Skip to content
This repository was archived by the owner on Jul 14, 2025. It is now read-only.

Commit 8c52b9a

Browse files
authored
FEATURE: new "notification level when assigned" user preference (#626)
This adds a new user preference allowed users to control how the notification level of the topic they're assigned to changes. Internal ref - t/141162
1 parent 654f197 commit 8c52b9a

File tree

10 files changed

+187
-11
lines changed

10 files changed

+187
-11
lines changed

.discourse-compatibility

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
< 3.4.0.beta4-dev: 654f197003f9cdf1926b07137fc2214b21c91a79
12
< 3.4.0.beta3-dev: 6472f4593e1a4abbb457288db012ddb10f0b16f5
23
< 3.4.0.beta1-dev: fe725251c1b248c349c38c96432e892c668822c6
34
< 3.3.0.beta2-dev: b796ae3fcc89b48cf777de5ee3a4c21aada9271e
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import Component from "@glimmer/component";
2+
import { service } from "@ember/service";
3+
import { i18n } from "discourse-i18n";
4+
import ComboBox from "select-kit/components/combo-box";
5+
6+
export default class NotificationLevelWhenAssigned extends Component {
7+
@service siteSettings;
8+
9+
constructor(owner, args) {
10+
super(...arguments);
11+
if (this.siteSettings.assign_enabled) {
12+
args.outletArgs.customAttrNames.push("notification_level_when_assigned");
13+
}
14+
}
15+
16+
get notificationLevelsWhenAssigned() {
17+
// The order matches the "notification level when replying" user preference
18+
return [
19+
{
20+
name: i18n("user.notification_level_when_assigned.watch_topic"),
21+
value: "watch_topic",
22+
},
23+
{
24+
name: i18n("user.notification_level_when_assigned.track_topic"),
25+
value: "track_topic",
26+
},
27+
{
28+
name: i18n("user.notification_level_when_assigned.do_nothing"),
29+
value: "do_nothing",
30+
},
31+
];
32+
}
33+
34+
<template>
35+
{{#if this.siteSettings.assign_enabled}}
36+
<div
37+
class="controls controls-dropdown"
38+
data-setting-name="user-notification-level-when-assigned"
39+
>
40+
<label>{{i18n "user.notification_level_when_assigned.label"}}</label>
41+
<ComboBox
42+
@content={{this.notificationLevelsWhenAssigned}}
43+
@value={{@outletArgs.model.user_option.notification_level_when_assigned}}
44+
@valueProperty="value"
45+
@onChange={{action
46+
(mut @outletArgs.model.user_option.notification_level_when_assigned)
47+
}}
48+
/>
49+
</div>
50+
{{/if}}
51+
</template>
52+
}

assets/javascripts/discourse/initializers/extend-for-assigns.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,8 @@ export default {
860860

861861
api.addUserSearchOption("assignableGroups");
862862

863+
api.addSaveableUserOptionField("notification_level_when_assigned");
864+
863865
api.addBulkActionButton({
864866
id: "assign-topics",
865867
label: "topics.bulk.assign",

config/locales/client.en.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ en:
100100
assignable_levels:
101101
title: "Who can assign this group"
102102
user:
103+
notification_level_when_assigned:
104+
label: "When assigned"
105+
watch_topic: "Watch topic"
106+
track_topic: "Track topic"
107+
do_nothing: "Do nothing"
103108
messages:
104109
assigned_title: "Assigned (%{count})"
105110
assigned: "Assigned"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# frozen_string_literal: true
2+
class AddNotificationLevelWhenAssignedUserOption < ActiveRecord::Migration[7.2]
3+
def change
4+
add_column :user_options, :notification_level_when_assigned, :integer, null: false, default: 3 # watch topic
5+
end
6+
end

lib/assigner.rb

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -329,17 +329,19 @@ def assign(
329329
publish_assignment(assignment, assign_to, note, status)
330330

331331
if assignment.assigned_to_user?
332-
if !TopicUser.exists?(
333-
user_id: assign_to.id,
334-
topic_id: topic.id,
335-
notification_level: TopicUser.notification_levels[:watching],
336-
)
337-
TopicUser.change(
338-
assign_to.id,
339-
topic.id,
340-
notification_level: TopicUser.notification_levels[:watching],
341-
notifications_reason_id: TopicUser.notification_reasons[:plugin_changed],
342-
)
332+
if !assign_to.user_option.do_nothing_when_assigned?
333+
notification_level =
334+
if assign_to.user_option.track_topic_when_assigned?
335+
TopicUser.notification_levels[:tracking]
336+
else
337+
TopicUser.notification_levels[:watching]
338+
end
339+
340+
topic_user = TopicUser.find_by(user_id: assign_to.id, topic:)
341+
if !topic_user || topic_user.notification_level < notification_level
342+
notifications_reason_id = TopicUser.notification_reasons[:plugin_changed]
343+
TopicUser.change(assign_to.id, topic.id, notification_level:, notifications_reason_id:)
344+
end
343345
end
344346

345347
if SiteSetting.assign_mailer == AssignMailer.levels[:always] ||
@@ -506,6 +508,7 @@ def add_small_action_post(action_code, assign_to, text)
506508
@assigned_by,
507509
text,
508510
bump: false,
511+
auto_track: false,
509512
post_type: SiteSetting.assigns_public ? Post.types[:small_action] : Post.types[:whisper],
510513
action_code: action_code,
511514
custom_fields: custom_fields,
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# frozen_string_literal: true
2+
3+
module DiscourseAssign
4+
module UserOptionExtension
5+
extend ActiveSupport::Concern
6+
7+
prepended do
8+
enum :notification_level_when_assigned,
9+
{ do_nothing: 1, track_topic: 2, watch_topic: 3 },
10+
suffix: "when_assigned"
11+
end
12+
end
13+
end

plugin.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,24 @@ module ::DiscourseAssign
2222
require_relative "lib/validators/assign_statuses_validator"
2323

2424
after_initialize do
25+
UserUpdater::OPTION_ATTR.push(:notification_level_when_assigned)
26+
2527
reloadable_patch do |plugin|
2628
Group.prepend(DiscourseAssign::GroupExtension)
2729
ListController.prepend(DiscourseAssign::ListControllerExtension)
2830
Post.prepend(DiscourseAssign::PostExtension)
2931
Topic.prepend(DiscourseAssign::TopicExtension)
3032
WebHook.prepend(DiscourseAssign::WebHookExtension)
3133
Notification.prepend(DiscourseAssign::NotificationExtension)
34+
UserOption.prepend(DiscourseAssign::UserOptionExtension)
35+
end
36+
37+
add_to_serializer(:user_option, :notification_level_when_assigned) do
38+
object.notification_level_when_assigned
39+
end
40+
41+
add_to_serializer(:current_user_option, :notification_level_when_assigned) do
42+
object.notification_level_when_assigned
3243
end
3344

3445
register_group_param(:assignable_level)

spec/lib/assigner_spec.rb

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,46 @@
4343
)
4444
end
4545

46+
describe "when user watchs topic when assigned" do
47+
before { moderator.user_option.watch_topic_when_assigned! }
48+
49+
it "respects 'when assigned' user preference" do
50+
expect(TopicUser.find_by(user: moderator)).to be(nil)
51+
52+
assigner.assign(moderator)
53+
54+
expect(TopicUser.find_by(user: moderator).notification_level).to eq(
55+
TopicUser.notification_levels[:watching],
56+
)
57+
end
58+
end
59+
60+
describe "when user tracks topic when assigned" do
61+
before { moderator.user_option.track_topic_when_assigned! }
62+
63+
it "respects 'when assigned' user preference" do
64+
expect(TopicUser.find_by(user: moderator)).to be(nil)
65+
66+
assigner.assign(moderator)
67+
68+
expect(TopicUser.find_by(user: moderator).notification_level).to eq(
69+
TopicUser.notification_levels[:tracking],
70+
)
71+
end
72+
end
73+
74+
describe "when user wants to do nothing when assigned" do
75+
before { moderator.user_option.do_nothing_when_assigned! }
76+
77+
it "respects 'when assigned' user preference" do
78+
expect(TopicUser.find_by(user: moderator)).to be(nil)
79+
80+
assigner.assign(moderator)
81+
82+
expect(TopicUser.find_by(user: moderator)).to be(nil)
83+
end
84+
end
85+
4686
it "deletes notification for original assignee when reassigning" do
4787
Jobs.run_immediately!
4888

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
describe "Assign | User Preferences", type: :system, js: true do
4+
fab!(:user)
5+
6+
let(:selector) { "[data-setting-name='user-notification-level-when-assigned'] .combobox" }
7+
8+
before { sign_in(user) }
9+
10+
describe "when discourse-assign is disabled" do
11+
before { SiteSetting.assign_enabled = false }
12+
13+
it "does not show the 'when assigned' tracking user preference" do
14+
visit "/my/preferences/tracking"
15+
16+
expect(page).not_to have_css(selector)
17+
end
18+
end
19+
20+
describe "when discourse-assign is enabled" do
21+
before { SiteSetting.assign_enabled = true }
22+
23+
let(:when_assigned) { PageObjects::Components::SelectKit.new(selector) }
24+
25+
it "shows the 'when assigned' tracking user preference" do
26+
visit "/my/preferences/tracking"
27+
28+
expect(when_assigned).to have_selected_value("watch_topic")
29+
end
30+
31+
it "supports changing the 'when assigned' tracking user preference" do
32+
visit "/my/preferences/tracking"
33+
34+
when_assigned.expand
35+
when_assigned.select_row_by_value("track_topic")
36+
37+
page.find("button.save-changes").click
38+
page.refresh
39+
40+
expect(when_assigned).to have_selected_value("track_topic")
41+
end
42+
end
43+
end

0 commit comments

Comments
 (0)