* dev: initiate external apis * dev: external api * dev: external public api implementation * dev: add prefix to all api tokens * dev: flag to enable disable api token api access * dev: webhook model create and apis * dev: webhook settings * fix: webhook logs * chore: removed drf spectacular * dev: remove retry_count and fix api logging for get requests * dev: refactor webhook logic * fix: celery retry mechanism * chore: event and action change * chore: migrations changes * dev: proxy setup for apis * chore: changed retry time and cleanup * chore: added issue comment and inbox issue api endpoints * fix: migration files * fix: added env variables * fix: removed issue attachment from proxy * fix: added new migration file * fix: restricted wehbook access * chore: changed urls * chore: fixed porject serializer * fix: set expire for api token * fix: retrive endpoint for api token * feat: Api Token screens & api integration * dev: webhook endpoint changes * dev: add fields for webhook updates * feat: Download Api secret key * chore: removed BASE API URL * feat: revoke token access * dev: migration fixes * feat: workspace webhooks (#2748) * feat: workspace webhook store, services integeration and rendered webhook list and create * chore: handled webhook update and rengenerate token in workspace webhooks * feat: regenerate key and delete functionality --------- Co-authored-by: Ramesh Kumar <rameshkumar@rameshs-MacBook-Pro.local> Co-authored-by: gurusainath <gurusainath007@gmail.com> Co-authored-by: Ramesh Kumar Chandra <rameshkumar2299@gmail.com> * fix: url validation added * fix: seperated env for webhook and api * Web hooks refactoring * add show option for generated hook key * Api token restructure * webhook minor fixes * fix build errors * chore: improvements in file structring * dev: rate limiting the open apis --------- Co-authored-by: pablohashescobar <nikhilschacko@gmail.com> Co-authored-by: LAKHAN BAHETI <lakhanbaheti9@gmail.com> Co-authored-by: rahulramesha <71900764+rahulramesha@users.noreply.github.com> Co-authored-by: Ramesh Kumar <rameshkumar@rameshs-MacBook-Pro.local> Co-authored-by: gurusainath <gurusainath007@gmail.com> Co-authored-by: Ramesh Kumar Chandra <rameshkumar2299@gmail.com> Co-authored-by: Nikhil <118773738+pablohashescobar@users.noreply.github.com> Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com> Co-authored-by: rahulramesha <rahulramesham@gmail.com>
139 lines
3.9 KiB
Python
139 lines
3.9 KiB
Python
import requests
|
|
import uuid
|
|
import hashlib
|
|
import json
|
|
|
|
# Django imports
|
|
from django.conf import settings
|
|
|
|
# Third party imports
|
|
from celery import shared_task
|
|
from sentry_sdk import capture_exception
|
|
|
|
from plane.db.models import Webhook, WebhookLog
|
|
|
|
|
|
@shared_task(
|
|
bind=True,
|
|
autoretry_for=(requests.RequestException,),
|
|
retry_backoff=600,
|
|
max_retries=5,
|
|
retry_jitter=True,
|
|
)
|
|
def webhook_task(self, webhook, slug, event, event_data, action):
|
|
try:
|
|
webhook = Webhook.objects.get(id=webhook, workspace__slug=slug)
|
|
|
|
headers = {
|
|
"Content-Type": "application/json",
|
|
"User-Agent": "Autopilot",
|
|
"X-Plane-Delivery": str(uuid.uuid4()),
|
|
"X-Plane-Event": event,
|
|
}
|
|
|
|
# Your secret key
|
|
if webhook.secret_key:
|
|
# Concatenate the data and the secret key
|
|
message = event_data + webhook.secret_key
|
|
|
|
# Create a SHA-256 hash of the message
|
|
sha256 = hashlib.sha256()
|
|
sha256.update(message.encode("utf-8"))
|
|
signature = sha256.hexdigest()
|
|
headers["X-Plane-Signature"] = signature
|
|
|
|
event_data = json.loads(event_data) if event_data is not None else None
|
|
|
|
action = {
|
|
"POST": "create",
|
|
"PATCH": "update",
|
|
"PUT": "update",
|
|
"DELETE": "delete",
|
|
}.get(action, action)
|
|
|
|
payload = {
|
|
"event": event,
|
|
"action": action,
|
|
"webhook_id": str(webhook.id),
|
|
"workspace_id": str(webhook.workspace_id),
|
|
"data": event_data,
|
|
}
|
|
|
|
# Send the webhook event
|
|
response = requests.post(
|
|
webhook.url,
|
|
headers=headers,
|
|
json=payload,
|
|
timeout=30,
|
|
)
|
|
|
|
# Log the webhook request
|
|
WebhookLog.objects.create(
|
|
workspace_id=str(webhook.workspace_id),
|
|
webhook_id=str(webhook.id),
|
|
event_type=str(event),
|
|
request_method=str(action),
|
|
request_headers=str(headers),
|
|
request_body=str(payload),
|
|
response_status=str(response.status_code),
|
|
response_headers=str(response.headers),
|
|
response_body=str(response.text),
|
|
retry_count=str(self.request.retries),
|
|
)
|
|
|
|
except requests.RequestException as e:
|
|
# Log the failed webhook request
|
|
WebhookLog.objects.create(
|
|
workspace_id=str(webhook.workspace_id),
|
|
webhook_id=str(webhook.id),
|
|
event_type=str(event),
|
|
request_method=str(action),
|
|
request_headers=str(headers),
|
|
request_body=str(payload),
|
|
response_status=500,
|
|
response_headers="",
|
|
response_body=str(e),
|
|
retry_count=str(self.request.retries),
|
|
)
|
|
|
|
# Retry logic
|
|
if self.request.retries >= self.max_retries:
|
|
Webhook.objects.filter(pk=webhook.id).update(is_active=False)
|
|
return
|
|
raise requests.RequestException()
|
|
|
|
except Exception as e:
|
|
if settings.DEBUG:
|
|
print(e)
|
|
capture_exception(e)
|
|
return
|
|
|
|
|
|
@shared_task()
|
|
def send_webhook(event, event_data, action, slug):
|
|
try:
|
|
webhooks = Webhook.objects.filter(workspace__slug=slug, is_active=True)
|
|
|
|
if event == "project":
|
|
webhooks = webhooks.filter(project=True)
|
|
|
|
if event == "issue":
|
|
webhooks = webhooks.filter(issue=True)
|
|
|
|
if event == "module":
|
|
webhooks = webhooks.filter(module=True)
|
|
|
|
if event == "cycle":
|
|
webhooks = webhooks.filter(cycle=True)
|
|
|
|
if event == "issue-comment":
|
|
webhooks = webhooks.filter(issue_comment=True)
|
|
|
|
for webhook in webhooks:
|
|
webhook_task.delay(webhook.id, slug, event, event_data, action)
|
|
|
|
except Exception as e:
|
|
if settings.DEBUG:
|
|
print(e)
|
|
capture_exception(e)
|
|
return
|