Skip to content

fix: track and subscribe inline assignees when work items are created via the external API#9450

Open
stella-nova wants to merge 1 commit into
makeplane:previewfrom
stella-nova:fix/create-issue-activity-assignees-key
Open

fix: track and subscribe inline assignees when work items are created via the external API#9450
stella-nova wants to merge 1 commit into
makeplane:previewfrom
stella-nova:fix/create-issue-activity-assignees-key

Conversation

@stella-nova

@stella-nova stella-nova commented Jul 20, 2026

Copy link
Copy Markdown

Description

create_issue_activity only runs track_assignees when the create payload contains assignee_ids (the web app field name). Work items created through the external REST API (/api/v1/...) carry assignees instead, so inline assignees on create produce no assignee activity and are never auto-subscribed to the work item — meaning they get no notification for the assignment or for any later change. Assigning in a separate PATCH afterwards works, because the update path maps both field names to track_assignees, and track_assignees itself already reads both keys via extract_ids(requested_data, "assignee_ids", "assignees"). Only the create gate misses the external API key.

This PR accepts both assignee_ids and assignees in the create gate in apps/api/plane/bgtasks/issue_activities_task.py.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Test Scenarios

Unit tests added in plane/tests/unit/bg_tasks/test_issue_activities_task.py: creating with assignee_ids, creating with assignees (both must track the assignee activity and create the IssueSubscriber), and creating without assignees (no activities collected, no subscription, the "created" activity still recorded). Ran against PostgreSQL: 3 passed. Verified red/green: on the unpatched task exactly the assignees test fails. ruff check clean.

References

Fixes #9449.

Summary by CodeRabbit

  • Bug Fixes
    • Issue creation now correctly tracks assignees and creates subscriptions when assignees are provided through either supported API format.
    • Issues created without assignees no longer generate unnecessary assignee activity or subscriptions.

…ssue creation

create_issue_activity only ran track_assignees when the payload contained
assignee_ids (the web app field name). Work items created through the external
REST API (/api/v1/...) carry assignees instead, so inline assignees on create
produced no assignee activity and were never auto-subscribed to the work item -
meaning they got no notification for the assignment or any later change.
track_assignees itself already reads both keys via extract_ids, as does the
update path (both field names are mapped); only the create gate was missing
the external API key.

Accept both assignee_ids and assignees in the create gate.

Unit tests added for both payload shapes and the no-assignees case.
@CLAassistant

CLAassistant commented Jul 20, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Assignee activity tracking

Layer / File(s) Summary
Accept both assignee payload keys
apps/api/plane/bgtasks/issue_activities_task.py
The create activity task invokes assignee tracking for both assignee_ids and assignees.
Validate activity and subscription outcomes
apps/api/plane/tests/unit/bg_tasks/test_issue_activities_task.py
Tests cover both payload keys and verify that missing assignees produce only the created activity without subscriptions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: dheeru0198

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: handling inline assignees on external API work-item creation.
Description check ✅ Passed The description includes the change summary, type of change, test scenarios, and linked reference, with no required section missing.
Linked Issues check ✅ Passed The code and tests address #9449 by recognizing assignees on create and ensuring assignee activity and subscriptions occur.
Out of Scope Changes check ✅ Passed The PR stays focused on the assignee-create bug fix and its tests, with no unrelated changes evident.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/api/plane/tests/unit/bg_tasks/test_issue_activities_task.py (1)

110-117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test the None payload scenario.

To prevent regressions and ensure the background task handles null payloads gracefully without crashing, consider adding a test case where requested_data is explicitly None.

💡 Proposed test case
    `@pytest.mark.django_db`
    def test_create_with_none_payload_creates_only_created_activity(self, workspace, project, issue, author):
        """Null payload: no crash, only 'created' activity is logged."""
        activities = self._run(issue, project, workspace, author, None)

        assert activities == []
        assert not IssueSubscriber.objects.filter(issue_id=issue.id).exists()
        assert IssueActivity.objects.filter(issue_id=issue.id, verb="created").exists()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/plane/tests/unit/bg_tasks/test_issue_activities_task.py` around
lines 110 - 117, Add a test alongside
test_create_without_assignees_only_creates_created_activity that calls _run with
requested_data=None, then assert it completes without error, returns no
additional activities, creates no IssueSubscriber record, and records only the
created IssueActivity.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/plane/bgtasks/issue_activities_task.py`:
- Line 581: Update the assignee-tracking condition around requested_data to
first verify that requested_data is a dictionary before calling .get(). When it
is None or parses as a JSON array or other non-dictionary type, skip assignee
tracking without raising an AttributeError.

---

Nitpick comments:
In `@apps/api/plane/tests/unit/bg_tasks/test_issue_activities_task.py`:
- Around line 110-117: Add a test alongside
test_create_without_assignees_only_creates_created_activity that calls _run with
requested_data=None, then assert it completes without error, returns no
additional activities, creates no IssueSubscriber record, and records only the
created IssueActivity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d7c696ee-8a38-4d59-b4c1-0cae7c81f18b

📥 Commits

Reviewing files that changed from the base of the PR and between 7cef741 and aba2118.

📒 Files selected for processing (2)
  • apps/api/plane/bgtasks/issue_activities_task.py
  • apps/api/plane/tests/unit/bg_tasks/test_issue_activities_task.py

issue_activity.save(update_fields=["created_at", "actor_id"])
requested_data = json.loads(requested_data) if requested_data is not None else None
if requested_data.get("assignee_ids") is not None:
if requested_data.get("assignee_ids") is not None or requested_data.get("assignees") is not None:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard against non-dictionary types to prevent crashes.

If requested_data evaluates to None (which is explicitly allowed by the preceding line) or if it parses as a JSON array instead of a JSON object, calling .get() will raise an AttributeError and crash the background task.

Guard the dictionary access by verifying the payload type to ensure the task gracefully skips assignee tracking when the payload is missing or invalid.

🛡️ Proposed fix
-    if requested_data.get("assignee_ids") is not None or requested_data.get("assignees") is not None:
+    if isinstance(requested_data, dict) and (requested_data.get("assignee_ids") is not None or requested_data.get("assignees") is not None):
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if requested_data.get("assignee_ids") is not None or requested_data.get("assignees") is not None:
if isinstance(requested_data, dict) and (requested_data.get("assignee_ids") is not None or requested_data.get("assignees") is not None):
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/plane/bgtasks/issue_activities_task.py` at line 581, Update the
assignee-tracking condition around requested_data to first verify that
requested_data is a dictionary before calling .get(). When it is None or parses
as a JSON array or other non-dictionary type, skip assignee tracking without
raising an AttributeError.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🐛 Bug: Work items created via the external API with inline assignees never subscribe or notify the assignees

2 participants