Skip to content

Fix Jira bot DM notifications persisting after user disconnect#1286

Merged
nevyangelova merged 2 commits intomasterfrom
MM-67804
Mar 19, 2026
Merged

Fix Jira bot DM notifications persisting after user disconnect#1286
nevyangelova merged 2 commits intomasterfrom
MM-67804

Conversation

@nevyangelova
Copy link
Copy Markdown
Contributor

Summary

  • Block channel subscription create/edit in DM and GM channels
  • On disconnect automatically remove any subscriptions in the user's DM channel with the Jira bot

QA Steps

  1. Set "Roles Allowed to Edit Jira Subscriptions" to users
  2. /jira connect, open bot DM, try to create a subscription and it should get rejected.
  3. Create in a public channel should work.

DM subscriptions cleaned up on disconnect

  1. On the current release (before this fix) create a subscription in the bot DM, coz we will need it.
  2. Deploy this fix
  3. /jira disconnect
  4. Reconnect, /jira subscribe list in bot DM should remove the subscription.
  5. Trigger a matching Jira event and should not receive a DM notification.
  6. Subscriptions in public/private channels should work.

Ticket Link

https://mattermost.atlassian.net/browse/MM-67804

@nevyangelova nevyangelova requested a review from a team as a code owner March 16, 2026 03:16
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 16, 2026

📝 Walkthrough

Walkthrough

This PR introduces channel type validation to prevent subscriptions to direct message and group channels, and implements automatic cleanup of DM subscriptions when users disconnect from the system.

Changes

Cohort / File(s) Summary
Subscription Channel Type Validation
server/subscribe.go, server/http_test.go
Added channel type checks in subscription creation and editing handlers that reject Direct or Group channel types with HTTP 400 Bad Request before permission checks. Tests verify rejection behavior for both DM and GM channels.
DM Subscription Cleanup Logic
server/subscribe.go
Introduced removeSubscriptionsForDMChannel() to delete all subscriptions for a specific DM channel and cleanupDMSubscriptionsOnDisconnect() to resolve and remove DM channel subscriptions during user disconnect, with error logging.
Cleanup Method Tests
server/subscribe_test.go
Added test coverage for DM subscription removal with multiple scenarios (no subscriptions, single/multiple DM subscriptions mixed with other channels) and disconnect cleanup including success and no-op cases.
Disconnect Integration
server/user.go
Integrated DM subscription cleanup into the disconnect flow by invoking cleanupDMSubscriptionsOnDisconnect() after removing the connection and updating user state.
Test Expectation Updates
server/utils_test.go
Updated test mock expectations to reflect additional KVGet call for subscription cleanup and removed Once() assertion on GetDirectChannel to allow multiple invocations.

Sequence Diagram

sequenceDiagram
    participant User as User Disconnect
    participant Plugin as Plugin (user.go)
    participant Subscribe as Subscribe Module
    participant KV as KV Store
    
    User->>Plugin: disconnectUser()
    Plugin->>Subscribe: cleanupDMSubscriptionsOnDisconnect(instanceID, mattermostUserID)
    Subscribe->>Plugin: GetDirectChannel(mattermostUserID)
    Plugin-->>Subscribe: channelID or error
    
    alt DM Channel Found
        Subscribe->>KV: GetSubscriptions(instanceID)
        KV-->>Subscribe: subscriptions
        Subscribe->>Subscribe: filter subscriptions by DM channelID
        Subscribe->>Subscribe: removeSubscriptionsForDMChannel()
        Subscribe->>KV: SetWithOptions(updated subscriptions)
        KV-->>Subscribe: success
    else DM Channel Not Found
        Subscribe-->>Plugin: no-op (log warning if error)
    end
    
    Plugin-->>User: disconnect completed
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested Labels

3: QA Review

Suggested Reviewers

  • avasconcelos114
  • ogi-m
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix Jira bot DM notifications persisting after user disconnect' directly aligns with the main objective: preventing DM subscriptions from persisting after user disconnect by removing them on disconnect.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch MM-67804
📝 Coding Plan
  • Generate coding plan for human review comments

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/subscribe.go (1)

1374-1374: ⚠️ Potential issue | 🟡 Minor

Remove debug print statement.

Line 1374 contains fmt.Print("/n httpGetSubscriptionTemplates") which appears to be leftover debug code.

🧹 Remove debug statement
 func (p *Plugin) httpGetSubscriptionTemplates(w http.ResponseWriter, r *http.Request) (int, error) {
-	fmt.Print("/n httpGetSubscriptionTemplates")
 	mattermostUserID := r.Header.Get("Mattermost-User-Id")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/subscribe.go` at line 1374, Remove the leftover debug print statement
fmt.Print("/n httpGetSubscriptionTemplates") from the
httpGetSubscriptionTemplates handler; locate the call inside the
httpGetSubscriptionTemplates function and delete that fmt.Print line so no
debugging output is printed in production.
🧹 Nitpick comments (1)
server/subscribe_test.go (1)

1682-1806: LGTM with a suggestion.

The test cases comprehensively cover the key scenarios for removeSubscriptionsForDMChannel. The verification logic correctly checks that only the expected subscriptions remain after removal.

Consider adding an explicit assertion in the "no subscriptions to remove" case to verify that KVSetWithOptions is NOT called, making the test intent clearer:

💡 Optional: Add explicit no-write assertion
 		"no subscriptions to remove": {
 			existingSubs:          []ChannelSubscription{},
 			expectedRemainingByID: nil,
 		},

After running the test, add:

if tc.expectedRemainingByID == nil {
    api.AssertNotCalled(t, "KVSetWithOptions", mock.Anything, mock.Anything, mock.Anything)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/subscribe_test.go` around lines 1682 - 1806, Add an explicit assertion
that KVSetWithOptions is NOT called when there are no subscriptions to remove:
inside TestRemoveSubscriptionsForDMChannel's loop after calling
p.removeSubscriptionsForDMChannel (for the case where tc.expectedRemainingByID
== nil) call api.AssertNotCalled(t, "KVSetWithOptions", mock.Anything,
mock.Anything, mock.Anything) so the test verifies no write happens; locate this
change in the TestRemoveSubscriptionsForDMChannel test that sets up api
(plugintest.API) and invokes p.removeSubscriptionsForDMChannel.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@server/subscribe.go`:
- Line 1374: Remove the leftover debug print statement fmt.Print("/n
httpGetSubscriptionTemplates") from the httpGetSubscriptionTemplates handler;
locate the call inside the httpGetSubscriptionTemplates function and delete that
fmt.Print line so no debugging output is printed in production.

---

Nitpick comments:
In `@server/subscribe_test.go`:
- Around line 1682-1806: Add an explicit assertion that KVSetWithOptions is NOT
called when there are no subscriptions to remove: inside
TestRemoveSubscriptionsForDMChannel's loop after calling
p.removeSubscriptionsForDMChannel (for the case where tc.expectedRemainingByID
== nil) call api.AssertNotCalled(t, "KVSetWithOptions", mock.Anything,
mock.Anything, mock.Anything) so the test verifies no write happens; locate this
change in the TestRemoveSubscriptionsForDMChannel test that sets up api
(plugintest.API) and invokes p.removeSubscriptionsForDMChannel.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 81000ad5-9a63-4cd7-acb5-01bcd011cc75

📥 Commits

Reviewing files that changed from the base of the PR and between 980aded and 7eabfbd.

📒 Files selected for processing (5)
  • server/http_test.go
  • server/subscribe.go
  • server/subscribe_test.go
  • server/user.go
  • server/utils_test.go

@nevyangelova nevyangelova added 2: Dev Review Requires review by a core committer 3: QA Review Requires review by a QA tester labels Mar 17, 2026
Copy link
Copy Markdown
Contributor

@avasconcelos114 avasconcelos114 left a comment

Choose a reason for hiding this comment

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

Nice work! Just got a couple of comments

Comment thread server/subscribe.go
Comment on lines +482 to +485
dmChannel, err := p.client.Channel.GetDirect(mattermostUserID, conf.botUserID)
if err != nil {
return
}
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.

Feels like we may want to log errors here as we are doing for any error that happens in removeSubscriptionsForDMChannel

Comment thread server/subscribe.go Outdated
})
}

func (p *Plugin) removeSubscriptionsForDMChannel(instanceID types.ID, channelID string) error {
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.

Considering the function accepts any channelID and removes subscriptions regardless of whether they are DM or not, we might want to rename this for accuracy

@nevyangelova
Copy link
Copy Markdown
Contributor Author

Thanks @avasconcelos114 I addressed the comments 🙏

Copy link
Copy Markdown
Contributor

@avasconcelos114 avasconcelos114 left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks!

@nevyangelova nevyangelova removed the 2: Dev Review Requires review by a core committer label Mar 18, 2026
@nevyangelova
Copy link
Copy Markdown
Contributor Author

@ogi-m dev reviews complete

Copy link
Copy Markdown

@ogi-m ogi-m left a comment

Choose a reason for hiding this comment

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

Working as expected!

@ogi-m ogi-m added 4: Reviews Complete All reviewers have approved the pull request and removed 3: QA Review Requires review by a QA tester labels Mar 18, 2026
@nevyangelova nevyangelova merged commit d3cec53 into master Mar 19, 2026
20 checks passed
@nevyangelova nevyangelova deleted the MM-67804 branch March 19, 2026 04:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4: Reviews Complete All reviewers have approved the pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants