From a75ae71ff0864f32f495419d79cd2d9dc9a9bdaf Mon Sep 17 00:00:00 2001 From: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> Date: Fri, 18 Jul 2025 20:08:01 +0530 Subject: [PATCH] [WEB-4442] fix: removed the deleted labels from webhook payload (#7337) * chore: removed the deleted label from payload * chore: optimised the query * chore: optimised the logic * chore: defined function for prefetch --- apps/api/plane/api/serializers/issue.py | 24 +++++++++++++++++-- apps/api/plane/bgtasks/webhook_task.py | 31 ++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/apps/api/plane/api/serializers/issue.py b/apps/api/plane/api/serializers/issue.py index 10738b97f..f906d4085 100644 --- a/apps/api/plane/api/serializers/issue.py +++ b/apps/api/plane/api/serializers/issue.py @@ -448,10 +448,30 @@ class LabelLiteSerializer(BaseSerializer): class IssueExpandSerializer(BaseSerializer): cycle = CycleLiteSerializer(source="issue_cycle.cycle", read_only=True) module = ModuleLiteSerializer(source="issue_module.module", read_only=True) - labels = LabelLiteSerializer(read_only=True, many=True) - assignees = UserLiteSerializer(read_only=True, many=True) + + labels = serializers.SerializerMethodField() + assignees = serializers.SerializerMethodField() state = StateLiteSerializer(read_only=True) + + def get_labels(self, obj): + expand = self.context.get("expand", []) + if "labels" in expand: + # Use prefetched data + return LabelLiteSerializer( + [il.label for il in obj.label_issue.all()], many=True + ).data + return [il.label_id for il in obj.label_issue.all()] + + def get_assignees(self, obj): + expand = self.context.get("expand", []) + if "assignees" in expand: + return UserLiteSerializer( + [ia.assignee for ia in obj.issue_assignee.all()], many=True + ).data + return [ia.assignee_id for ia in obj.issue_assignee.all()] + + class Meta: model = Issue fields = "__all__" diff --git a/apps/api/plane/bgtasks/webhook_task.py b/apps/api/plane/bgtasks/webhook_task.py index 0bcfd2693..ae7c30ac9 100644 --- a/apps/api/plane/bgtasks/webhook_task.py +++ b/apps/api/plane/bgtasks/webhook_task.py @@ -12,6 +12,7 @@ from celery import shared_task # Django imports from django.conf import settings +from django.db.models import Prefetch from django.core.mail import EmailMultiAlternatives, get_connection from django.core.serializers.json import DjangoJSONEncoder from django.template.loader import render_to_string @@ -42,6 +43,8 @@ from plane.db.models import ( Webhook, WebhookLog, IntakeIssue, + IssueLabel, + IssueAssignee, ) from plane.license.utils.instance_value import get_email_configuration from plane.utils.exception_logger import log_exception @@ -74,6 +77,15 @@ MODEL_MAPPER = { logger = logging.getLogger("plane.worker") +def get_issue_prefetches(): + return [ + Prefetch("label_issue", queryset=IssueLabel.objects.select_related("label")), + Prefetch( + "issue_assignee", queryset=IssueAssignee.objects.select_related("assignee") + ), + ] + + def get_model_data( event: str, event_id: Union[str, List[str]], many: bool = False ) -> Dict[str, Any]: @@ -103,10 +115,27 @@ def get_model_data( queryset = model.objects.get(pk=event_id) serializer = SERIALIZER_MAPPER.get(event) + if serializer is None: raise ValueError(f"Serializer not found for event: {event}") - return serializer(queryset, many=many).data + issue_prefetches = get_issue_prefetches() + if event == "issue": + if many: + queryset = queryset.prefetch_related(*issue_prefetches) + else: + issue_id = queryset.id + queryset = ( + model.objects.filter(pk=issue_id) + .prefetch_related(*issue_prefetches) + .first() + ) + + return serializer( + queryset, many=many, context={"expand": ["labels", "assignees"]} + ).data + else: + return serializer(queryset, many=many).data except ObjectDoesNotExist: raise ObjectDoesNotExist(f"No {event} found with id: {event_id}")