Merge branch 'chore/api_endpoints' of github.com:makeplane/plane into chore/api_endpoints

This commit is contained in:
NarayanBavisetti 2023-11-21 20:17:06 +05:30
commit 21b6804ebc
3 changed files with 83 additions and 25 deletions

View File

@ -66,7 +66,6 @@ class IssueSerializer(BaseSerializer):
project_id=self.context.get("project_id"),
is_active=True,
member_id__in=data["assignees"],
is_active=True,
).values_list("member_id", flat=True)
# Validate labels are from project

View File

@ -36,28 +36,31 @@ class TimezoneMixin:
else:
timezone.deactivate()
class WebhookMixin:
webhook_event = None
def finalize_response(self, request, response, *args, **kwargs):
response = super().finalize_response(request, response, *args, **kwargs)
if (
self.webhook_event
and self.request.method in ["POST", "PATCH", "DELETE"]
and self.request.method in ["POST", "PATCH"]
and response.status_code in [200, 201, 204]
):
# Get the id
object_id = (
response.data.get("id") if isinstance(response.data, dict) else None
)
send_webhook.delay(
event=self.webhook_event,
event_data=json.dumps(response.data, cls=DjangoJSONEncoder),
event_id=object_id,
action=self.request.method,
slug=self.workspace_slug,
)
return response
class BaseAPIView(TimezoneMixin, APIView, BasePaginator):
authentication_classes = [
APIKeyAuthentication,
@ -139,13 +142,13 @@ class BaseAPIView(TimezoneMixin, APIView, BasePaginator):
response = super().finalize_response(request, response, *args, **kwargs)
# Add custom headers if they exist in the request META
ratelimit_remaining = request.META.get('X-RateLimit-Remaining')
ratelimit_remaining = request.META.get("X-RateLimit-Remaining")
if ratelimit_remaining is not None:
response['X-RateLimit-Remaining'] = ratelimit_remaining
response["X-RateLimit-Remaining"] = ratelimit_remaining
ratelimit_reset = request.META.get('X-RateLimit-Reset')
ratelimit_reset = request.META.get("X-RateLimit-Reset")
if ratelimit_reset is not None:
response['X-RateLimit-Reset'] = ratelimit_reset
response["X-RateLimit-Reset"] = ratelimit_reset
return response

View File

@ -2,15 +2,63 @@ import requests
import uuid
import hashlib
import json
import hmac
# Django imports
from django.conf import settings
from django.core.serializers.json import DjangoJSONEncoder
# Third party imports
from celery import shared_task
from sentry_sdk import capture_exception
from plane.db.models import Webhook, WebhookLog
from plane.db.models import (
Webhook,
WebhookLog,
Project,
Issue,
Cycle,
Module,
ModuleIssue,
CycleIssue,
IssueComment,
)
from plane.api.serializers import (
ProjectSerializer,
IssueSerializer,
CycleSerializer,
ModuleSerializer,
CycleIssueSerializer,
ModuleIssueSerializer,
IssueCommentSerializer,
)
SERIALIZER_MAPPER = {
"project": ProjectSerializer,
"issue": IssueSerializer,
"cycle": CycleSerializer,
"module": ModuleSerializer,
"cycle_issue": CycleIssueSerializer,
"module_issue": ModuleIssueSerializer,
"issue_comment": IssueCommentSerializer,
}
MODEL_MAPPER = {
"project": Project,
"issue": Issue,
"cycle": Cycle,
"module": Module,
"cycle_issue": CycleIssue,
"module_issue": ModuleIssue,
"issue_comment": IssueComment,
}
def get_model_data(event, event_id):
model = MODEL_MAPPER.get(event)
queryset = model.objects.get(pk=event_id)
serializer = SERIALIZER_MAPPER.get(event)
return serializer(queryset).data
@shared_task(
@ -20,7 +68,7 @@ from plane.db.models import Webhook, WebhookLog
max_retries=5,
retry_jitter=True,
)
def webhook_task(self, webhook, slug, event, event_data, action):
def webhook_task(self, webhook, slug, event, event_id, action):
try:
webhook = Webhook.objects.get(id=webhook, workspace__slug=slug)
@ -31,19 +79,26 @@ def webhook_task(self, webhook, slug, event, event_data, action):
"X-Plane-Event": event,
}
# Your secret key
event_data = get_model_data(event=event, event_id=event_id)
# # Your secret key
event_data = (
json.loads(json.dumps(event_data, cls=DjangoJSONEncoder))
if event_data is not None
else None
)
# Use HMAC for generating signature
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()
event_data_json = json.dumps(event_data) if event_data is not None else '{}'
hmac_signature = hmac.new(
webhook.secret_key.encode("utf-8"),
event_data_json.encode("utf-8"),
hashlib.sha256
)
signature = hmac_signature.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",
@ -103,6 +158,7 @@ def webhook_task(self, webhook, slug, event, event_data, action):
raise requests.RequestException()
except Exception as e:
print(e)
if settings.DEBUG:
print(e)
capture_exception(e)
@ -110,7 +166,7 @@ def webhook_task(self, webhook, slug, event, event_data, action):
@shared_task()
def send_webhook(event, event_data, action, slug):
def send_webhook(event, event_id, action, slug):
try:
webhooks = Webhook.objects.filter(workspace__slug=slug, is_active=True)
@ -130,7 +186,7 @@ def send_webhook(event, event_data, action, slug):
webhooks = webhooks.filter(issue_comment=True)
for webhook in webhooks:
webhook_task.delay(webhook.id, slug, event, event_data, action)
webhook_task.delay(webhook.id, slug, event, event_id, action)
except Exception as e:
if settings.DEBUG: