Skip to content

FEATURE: per-topic unsubscribe option in emails - #1768

Open
kaihao-zhao wants to merge 2 commits into
email-notifications-enhancementfrom
topic-email-management-stdsol61-r1
Open

kaihao-zhao wants to merge 2 commits into
email-notifications-enhancementfrom
topic-email-management-stdsol61-r1

Conversation

@kaihao-zhao

Copy link
Copy Markdown

See title.

@github-actions github-actions Bot added the i18n label Sep 30, 2026

@unblocked-local-kaihao unblocked-local-kaihao Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

4 issues found.

About Unblocked

Unblocked has been set up to automatically review your team's pull requests to identify genuine bugs and issues.

📖 Documentation — Learn more in our docs.

💬 Ask questions — Mention @unblocked-local-kaihao to request a review or summary, or ask follow-up questions.

👍 Give feedback — React to comments with 👍 or 👎 to help us improve.

⚙️ Customize — Adjust settings in your preferences.

Comment thread config/routes.rb
Comment on lines +440 to +441
get "t/:slug/:topic_id/unsubscribe" => "topics#unsubscribe", constraints: {topic_id: /\d+/}
get "t/:topic_id/unsubscribe" => "topics#unsubscribe", constraints: {topic_id: /\d+/}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

These GET routes immediately modify the logged-in user's notification level. Rails' CSRF protection does not validate GET requests, and unsubscribe also bypasses check_xhr, so an attacker can force an authenticated browser to unsubscribe from a topic through a crafted link or navigation. Keep GET read-only and apply the change through a CSRF-protected POST confirmation.

Comment on lines +107 to +108
if tu.notification_level > TopicUser.notification_levels[:regular]
tu.notification_level = TopicUser.notification_levels[:regular]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

For a mailing-list-mode user whose topic is tracking or watching, this sets the level to regular but does not stop the emails. Jobs::NotifyMailingListSubscribers excludes only muted topics, so every subsequent post is still emailed despite the unsubscribe confirmation. Select muted for mailing-list-mode users regardless of their previous notification level.

tu.notification_level = TopicUser.notification_levels[:muted]
end

tu.save!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Saving directly leaves notifications_reason_id unchanged. For an emailed topic with no notification reason, TopicUser.update_last_read will overwrite the new regular or muted level with tracking once the reading threshold is met. In mailing-list mode, this can re-enable emails for the muted topic. Use TopicUser.change, as set_notifications does, so the explicit choice is preserved.

Suggested change
tu.save!
TopicUser.change(current_user.id, params[:topic_id], notification_level: tu.notification_level)

export default Discourse.Route.extend({
model(params) {
const topic = this.store.createRecord("topic", { id: params.id });
return PostStream.loadTopicView(params.id).then(json => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This only loads the normal topic view: PostStream.loadTopicView requests /t/:id.json, not the unsubscribe endpoint. When an unsubscribe link is followed inside Discourse, the click interceptor performs an Ember transition without calling TopicsController#unsubscribe. The page therefore claims notifications have stopped while leaving the subscription unchanged. Ensure client-side entry applies the unsubscribe operation before showing confirmation, using a CSRF-protected mutation.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants