Skip to content

feat(api): support mentioning users in work-item comments#9403

Open
clwluvw wants to merge 1 commit into
makeplane:previewfrom
clwluvw:user-api
Open

feat(api): support mentioning users in work-item comments#9403
clwluvw wants to merge 1 commit into
makeplane:previewfrom
clwluvw:user-api

Conversation

@clwluvw

@clwluvw clwluvw commented Jul 12, 2026

Copy link
Copy Markdown

Description

Add a first-class mentions field to the public REST API comment create/update serializer. The server renders the internal markup into comment_html so mentioned members are notified without callers hand-crafting the markup, and the ids remain parseable back out of comment_html.

Also fix the public comment endpoints so notifications actually fire:

  • pass notification=True (and origin) on comment create/update/delete, matching the internal app API (issue_activity defaults notification=False)
  • dispatch the persisted comment (IssueCommentSerializer) as requested_data so the activity carries the comment id and rendered markup, without which the notification pipeline's comment-mention branch was skipped

Only active, non-bot project members can be mentioned; unknown ids are rejected and non-members are ignored. Adds contract tests (including an end-to-end assertion that a Notification row is created) and updates the OpenAPI example.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

Summary by CodeRabbit

  • New Features

    • Added a mentions field for issue comment create/update to render mention markup into comment_html.
    • Mentioned project members are notified when mentions are included (including on updates).
    • Mentions are de-duplicated; non-project members and bot accounts are ignored; max 100 mentions enforced.
  • Bug Fixes

    • Improved comment activity payloads to reflect the server-rendered comment content used for notifications.
  • Documentation

    • Updated issue comment API examples to include mentions.
  • Tests

    • Expanded contract tests for mention rendering, sanitization, validation, notification behavior, idempotent updates, and rate-limit cache isolation.

Copilot AI review requested due to automatic review settings July 12, 2026 17:04
@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97f4b30b-a938-44d9-9d0e-43291038d8b5

📥 Commits

Reviewing files that changed from the base of the PR and between 1d1fd90 and a3212f4.

📒 Files selected for processing (5)
  • apps/api/plane/api/serializers/issue.py
  • apps/api/plane/api/views/issue.py
  • apps/api/plane/tests/contract/api/conftest.py
  • apps/api/plane/tests/contract/api/test_issue_comment_mentions.py
  • apps/api/plane/utils/openapi/examples.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/api/plane/tests/contract/api/conftest.py
  • apps/api/plane/api/serializers/issue.py
  • apps/api/plane/utils/openapi/examples.py
  • apps/api/plane/tests/contract/api/test_issue_comment_mentions.py

📝 Walkthrough

Walkthrough

Issue comments now accept user IDs through a mentions field, render eligible mentions into comment_html, and use persisted comment data in activity payloads. Contract tests cover creation, updates, filtering, idempotency, sanitization, and notifications.

Changes

Issue comment mentions

Layer / File(s) Summary
Mention rendering and validation
apps/api/plane/api/serializers/issue.py
Adds mention markup helpers and a write-only mentions field; active, non-bot project members are rendered in order without duplicates and the resulting HTML is sanitized.
Persisted comment activity flow
apps/api/plane/api/views/issue.py
Passes project context to comment serializers and serializes persisted comments for create/update activities; deletion activities include notification metadata.
API contract coverage and documentation
apps/api/plane/tests/contract/api/conftest.py, apps/api/plane/tests/contract/api/test_issue_comment_mentions.py, apps/api/plane/utils/openapi/examples.py
Adds cache isolation, coverage for rendering, filtering, updates, idempotency, sanitization, activity notifications, and OpenAPI documentation for the mentions field.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant IssueCommentCreateSerializer
  participant ProjectMember
  participant IssueComment
  participant ActivityDispatcher
  participant NotificationPipeline
  Client->>IssueCommentCreateSerializer: Submit comment and mentions
  IssueCommentCreateSerializer->>ProjectMember: Filter mention targets
  ProjectMember-->>IssueCommentCreateSerializer: Return eligible member IDs
  IssueCommentCreateSerializer->>IssueComment: Save rendered comment_html
  IssueComment->>ActivityDispatcher: Emit persisted comment activity
  ActivityDispatcher->>NotificationPipeline: Dispatch notifying activity
  NotificationPipeline-->>Client: Create in-app notification
Loading

Suggested reviewers: dheeru0198, pablohashescobar

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding user mentions to work-item comments.
Description check ✅ Passed The description covers the change well, but it omits the Screenshots, Test Scenarios, and References sections from the template.
Docstring Coverage ✅ Passed Docstring coverage is 96.67% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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.

Copilot AI 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.

Pull request overview

Adds first-class user-mention support to the public REST API for work-item comments, aligning external comment create/update/delete behavior with the internal app so mention notifications reliably fire and mention markup is server-rendered/round-trippable.

Changes:

  • Extend the public comment create/update serializer to accept a mentions list and append <mention-component> markup into comment_html.
  • Fix public comment activity dispatch to include persisted comment data (with id + rendered markup) and to enable notifications on create/update/delete.
  • Add contract tests (including an end-to-end Notification row assertion) and update the OpenAPI request example.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
apps/api/plane/utils/openapi/examples.py Updates request example for comment creation to document the new mentions field.
apps/api/plane/tests/contract/api/test_issue_comment_mentions.py Adds contract coverage for mention rendering, validation, de-duplication/idempotence, and notification creation.
apps/api/plane/api/views/issue.py Ensures comment activities carry persisted comment payload and enables notifications/origin for create/update/delete.
apps/api/plane/api/serializers/issue.py Implements server-side mention markup rendering and project-member filtering for the new mentions field.

Comment thread apps/api/plane/api/serializers/issue.py
Comment thread apps/api/plane/utils/openapi/examples.py

@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.

🧹 Nitpick comments (1)
apps/api/plane/api/serializers/issue.py (1)

737-747: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Document the reliance on values_list("id", flat=True); it silently drives the id-based logic downstream.

Because the child field's queryset is a flat values_list, PrimaryKeyRelatedField.to_internal_value returns the raw id (UUID) rather than a User instance. The rest of validate depends on that: member_id__in=mention_user_ids and especially user_id in valid_member_ids (UUID-vs-UUID). A well-meaning change to User.objects.all() would return User instances and break the in comparisons silently (mentions would just stop rendering). A short comment guarding this intent would prevent a future regression.

🤖 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/api/serializers/issue.py` around lines 737 - 747, Add a
concise comment above the `mentions` field documenting that `values_list("id",
flat=True)` intentionally makes `PrimaryKeyRelatedField` return UUID ids, which
downstream `validate` logic relies on for `member_id__in` and `user_id in
valid_member_ids`; warn against changing it to a queryset of `User` instances.
🤖 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.

Nitpick comments:
In `@apps/api/plane/api/serializers/issue.py`:
- Around line 737-747: Add a concise comment above the `mentions` field
documenting that `values_list("id", flat=True)` intentionally makes
`PrimaryKeyRelatedField` return UUID ids, which downstream `validate` logic
relies on for `member_id__in` and `user_id in valid_member_ids`; warn against
changing it to a queryset of `User` instances.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 214cbf45-6a6c-4d65-8c08-05bc71176f41

📥 Commits

Reviewing files that changed from the base of the PR and between dc9d80b and 19004b0.

📒 Files selected for processing (4)
  • apps/api/plane/api/serializers/issue.py
  • apps/api/plane/api/views/issue.py
  • apps/api/plane/tests/contract/api/test_issue_comment_mentions.py
  • apps/api/plane/utils/openapi/examples.py

@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.

🧹 Nitpick comments (1)
apps/api/plane/api/serializers/issue.py (1)

743-753: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Add a length cap to mentions

mentions accepts an unbounded list, so a single request can trigger a large number of validation queries and generate oversized comment_html. Set max_length on the ListField to bound the payload.

🤖 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/api/serializers/issue.py` around lines 743 - 753, Update the
mentions ListField declaration to include an appropriate max_length limit,
bounding the number of user IDs accepted while preserving its existing
validation and optional behavior.
🤖 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.

Nitpick comments:
In `@apps/api/plane/api/serializers/issue.py`:
- Around line 743-753: Update the mentions ListField declaration to include an
appropriate max_length limit, bounding the number of user IDs accepted while
preserving its existing validation and optional behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 83be16a1-f9a7-4ef3-9f5f-6c4dea2bad83

📥 Commits

Reviewing files that changed from the base of the PR and between 19004b0 and 1d1fd90.

📒 Files selected for processing (5)
  • apps/api/plane/api/serializers/issue.py
  • apps/api/plane/api/views/issue.py
  • apps/api/plane/tests/contract/api/conftest.py
  • apps/api/plane/tests/contract/api/test_issue_comment_mentions.py
  • apps/api/plane/utils/openapi/examples.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/api/plane/tests/contract/api/test_issue_comment_mentions.py

Add a first-class `mentions` field to the public REST API comment
create/update serializer. The server renders the internal
<mention-component> markup into comment_html so mentioned members are
notified without callers hand-crafting the markup, and the ids remain
parseable back out of comment_html. The list is capped (max_length=100)
so a single comment cannot render unbounded mention markup.

Also fix the public comment endpoints so notifications actually fire:
- pass notification=True (and origin) on comment create/update/delete,
  matching the internal app API (issue_activity defaults notification=False)
- dispatch the persisted comment (IssueCommentSerializer) as requested_data
  so the activity carries the comment id and rendered markup, without which
  the notification pipeline's comment-mention branch was skipped

Sanitize comment_html on the public write path with validate_html_content
(after mention rendering), matching the internal app serializer so external
clients cannot store unsafe/invalid HTML; the whitelisted mention markup
survives sanitization.

Only active, non-bot project members can be mentioned; unknown ids are
rejected and non-members are ignored. Adds contract tests (including an
end-to-end assertion that a Notification row is created and that unsafe
HTML is stripped) and updates the OpenAPI create/update examples.

Also reset the public API rate limiter between contract tests
(tests/contract/api/conftest.py): ApiKeyRateThrottle counts requests per
API key in the shared cache, and the suite reuses one fixed token, so the
per-run count accumulated across tests and tripped the 60/minute limit
(HTTP 429) once enough request-making tests were added.

Signed-off-by: Seena Fallah <seenafallah@gmail.com>
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.

2 participants