From 74a5ab952168d06134f9724f196e3c39ec7f1aba Mon Sep 17 00:00:00 2001 From: ouchan Date: Wed, 25 Mar 2026 02:11:40 +0900 Subject: [PATCH] fix: add model_activity.delay() to API issue update/create paths for webhook dispatch Fixes #6746 API-driven issue updates (PUT update, PUT create-via-upsert, PATCH) were missing `model_activity.delay()` calls, so webhooks were never dispatched for changes made through the API. The web UI paths already include these calls (e.g. in `post()` at L475), but the `put()` and `partial_update()` methods only called `issue_activity.delay()`. This adds `model_activity.delay()` immediately after each existing `issue_activity.delay()` in these three code paths, using the same signature as the existing call in `post()`. Tested on Plane CE v1.2.1 self-hosted: API PATCH triggers `webhook_send_task` in the Celery worker, confirming webhook delivery. Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/api/plane/api/views/issue.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/apps/api/plane/api/views/issue.py b/apps/api/plane/api/views/issue.py index b936cdcda00..20d4f604a66 100644 --- a/apps/api/plane/api/views/issue.py +++ b/apps/api/plane/api/views/issue.py @@ -629,6 +629,16 @@ def put(self, request, slug, project_id): current_instance=current_instance, epoch=int(timezone.now().timestamp()), ) + # Send the model activity for webhook dispatch + model_activity.delay( + model_name="issue", + model_id=str(issue.id), + requested_data=request.data, + current_instance=current_instance, + actor_id=request.user.id, + slug=slug, + origin=base_host(request=request, is_app=True), + ) return Response(serializer.data, status=status.HTTP_200_OK) return Response( # If the serializer is not valid, respond with 400 bad @@ -677,6 +687,16 @@ def put(self, request, slug, project_id): current_instance=None, epoch=int(timezone.now().timestamp()), ) + # Send the model activity for webhook dispatch + model_activity.delay( + model_name="issue", + model_id=str(serializer.data["id"]), + requested_data=request.data, + current_instance=None, + actor_id=request.user.id, + slug=slug, + origin=base_host(request=request, is_app=True), + ) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) else: @@ -752,6 +772,16 @@ def patch(self, request, slug, project_id, pk): current_instance=current_instance, epoch=int(timezone.now().timestamp()), ) + # Send the model activity for webhook dispatch + model_activity.delay( + model_name="issue", + model_id=str(pk), + requested_data=request.data, + current_instance=current_instance, + actor_id=request.user.id, + slug=slug, + origin=base_host(request=request, is_app=True), + ) return Response(serializer.data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)