You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(notifications): restrict task assignment notifications to assignee - #3894
Currently, task creation and task reassignment events enter the general project notification pipeline (Projects::notifyProjectUsers()). As a result, assignment notifications are sent to all project members who have notifications enabled, and broadcasted to project chat channels (Slack, Discord, Mattermost, Telegram).
This pull request introduces an optional $recipientIds allow-list to the Notification model:
Notification Model: Added public ?array $recipientIds = null. When null, the existing project-wide notification flow remains 100% backward-compatible.
Projects Service (notifyProjectUsers):
Sanitizes and enforces $recipientIds when present.
Suppresses mention/collaborator bypass so third-party users are not inadvertently added to private assignments.
Skips project-wide messenger notifications for targeted assignments.
Scopes in-app notifications to the allow-list.
Tickets Service:
In quickAddTicket() & addTicket(): Restricts assignment notifications to the assigned user (editorId).
In updateTicket(): Detects if editorId changed, sets action = 'assigned', and targets only the incoming assignee.
Unit Tests: Added test coverage in ProjectsServiceTest verifying allow-list filtering, bypass suppression, and messenger skipping.
Link to ticket
N/A (or link your issue if one was created on GitHub, e.g. Fixes #xxxx)
Type
Fix
Feature
Cleanup
Screenshot of the result
N/A (Backend notification routing change; no UI modifications)
- Add optional recipientIds allow-list to Notification model
- Filter candidate users by recipientIds in Projects::notifyProjectUsers()
- Disable mention and collaborator filter bypass when in targeted recipient mode
- Suppress project-wide chat messenger broadcasts for targeted assignment notifications
- Target assignee on task creation in quickAddTicket() and addTicket()
- Detect assignee changes in updateTicket() and target only the new assignee
- Add unit test coverage in ProjectsServiceTest
…d update PHPDoc
- Build candidate recipients from getUsersWithAccessToProject() when recipientIds is set
- Update in-app notification candidate selection to support indirect access
- Update notifyProjectUsers PHPDoc regarding mention/collaborator bypass contract
- Add unit test coverage for indirect project access notifications
Test reassignment notification targeting and unchanged assignments
app/Domain/Tickets/Services/Tickets.php:2633
There is no service-level test for this new reassignment decision: the added tests inject recipientIds directly and do not verify that updateTicket() targets only a genuinely changed, non-empty assignee while ordinary updates remain project-wide. Add tests that capture the Notification passed to notifyProjectUsers() for reassignment, unchanged/omitted editorId, and unassignment.
… predicate and assert in-app recipients
- Build targeted candidates by validating allow-listed IDs against isUserAssignedToProject() and fetching user rows via UserRepository
- Support direct team members, indirect project settings ('all'/'clients'), and global admins/owners for targeted notifications
- Reuse validated candidate rows for in-app notification routing
- Add assertion for in-app notification recipients in targeted notification test
- Add tests for unassigned admin/owner notifications, unauthorized recipient dropping, and author self-assignment exclusion
Reject malformed allow-list entries before casting user IDs
app/Domain/Projects/Services/Projects.php:360
intval broadens malformed allow-list entries instead of rejecting them: for example, true and [7] both become user ID 1, while 2.9 becomes ID 2. Since notificationFilter and plugins can mutate this public model, malformed input can send private assignment details to an unintended user. Accept only positive integers (and, if needed, digit-only strings) before casting.
Add service test coverage for ticket reassignment notifications
app/Domain/Tickets/Services/Tickets.php:2655
No ticket-service test exercises this reassignment branch. The added ProjectsServiceTest injects recipientIds directly, so it would still pass if updateTicket() failed to set the allow-list, targeted an unchanged assignee, or retained the project-wide path. Add a service test that captures notifyProjectUsers() and verifies changed versus unchanged editorId values.
… add reassignment test coverage
- Validate allow-list entries strictly (positive integers or digit strings) before casting
- Add unit test verifying malformed entries are rejected without unintended coercion
- Add TicketsService test coverage for ticket reassignment notifications
- Add test coverage verifying non-reassignment and unassignment notifications do not target recipientIds
The reason will be displayed to describe this comment to others. Learn more.
🔵 Needs a closer look
Inline reassignment through patchTicket() still does not notify the incoming assignee.
0 open findings
Previously missed (1)
In code that hasn't changed since last review
Notify assignees on inline ticket reassignment
app/Domain/Tickets/Services/Tickets.php:2633
Reassignment targeting is only implemented in updateTicket(), but the current assignee chip and kanban assignee swimlane persist editorId through Tickets.Tickets.patchTicket (the chip contract is documented at app/Views/Templates/components/forms/chip.blade.php:21-23, and the swimlane call is at app/Domain/Tickets/Js/ticketsController.js:1391-1395). That path reaches patch(), which does not build an assignment notification, so common inline reassignments still deliver no notification to the incoming assignee. Move the assignment-notification construction into a shared helper and invoke it after successful editorId changes from both updateTicket() and patch() (while avoiding duplicate sends), with coverage for the patch path.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Currently, task creation and task reassignment events enter the general project notification pipeline (
Projects::notifyProjectUsers()). As a result, assignment notifications are sent to all project members who have notifications enabled, and broadcasted to project chat channels (Slack, Discord, Mattermost, Telegram).This pull request introduces an optional
$recipientIdsallow-list to theNotificationmodel:public ?array $recipientIds = null. Whennull, the existing project-wide notification flow remains 100% backward-compatible.notifyProjectUsers):$recipientIdswhen present.quickAddTicket()&addTicket(): Restricts assignment notifications to the assigned user (editorId).updateTicket(): Detects ifeditorIdchanged, setsaction = 'assigned', and targets only the incoming assignee.ProjectsServiceTestverifying allow-list filtering, bypass suppression, and messenger skipping.Link to ticket
N/A (or link your issue if one was created on GitHub, e.g. Fixes #xxxx)
Type
Screenshot of the result
N/A (Backend notification routing change; no UI modifications)