mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 08:43:25 +08:00
FEATURE: allow group membership to unmute categories and tags
For sites that are configured to mute some or all categories and tags for users by default, groups can now be configured to set members' notification level to normal from the group manage UI.
This commit is contained in:
parent
18fb34bf2e
commit
d65a839577
|
@ -6,9 +6,12 @@ export default Controller.extend({
|
|||
"model.watchingCategories.[]",
|
||||
"model.watchingFirstPostCategories.[]",
|
||||
"model.trackingCategories.[]",
|
||||
"model.regularCategories.[]",
|
||||
"model.mutedCategories.[]"
|
||||
)
|
||||
selectedCategories(watching, watchingFirst, tracking, muted) {
|
||||
return [].concat(watching, watchingFirst, tracking, muted).filter(t => t);
|
||||
selectedCategories(watching, watchingFirst, tracking, regular, muted) {
|
||||
return []
|
||||
.concat(watching, watchingFirst, tracking, regular, muted)
|
||||
.filter(t => t);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -6,9 +6,12 @@ export default Controller.extend({
|
|||
"model.watching_tags.[]",
|
||||
"model.watching_first_post_tags.[]",
|
||||
"model.tracking_tags.[]",
|
||||
"model.regular_tags.[]",
|
||||
"model.muted_tags.[]"
|
||||
)
|
||||
selectedTags(watching, watchingFirst, tracking, muted) {
|
||||
return [].concat(watching, watchingFirst, tracking, muted).filter(t => t);
|
||||
selectedTags(watching, watchingFirst, tracking, regular, muted) {
|
||||
return []
|
||||
.concat(watching, watchingFirst, tracking, regular, muted)
|
||||
.filter(t => t);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -200,6 +200,14 @@ const Group = RestModel.extend({
|
|||
);
|
||||
},
|
||||
|
||||
@observes("regular_category_ids")
|
||||
_updateRegularCategories() {
|
||||
this.set(
|
||||
"regularCategories",
|
||||
Category.findByIds(this.regular_category_ids)
|
||||
);
|
||||
},
|
||||
|
||||
@observes("muted_category_ids")
|
||||
_updateMutedCategories() {
|
||||
this.set("mutedCategories", Category.findByIds(this.muted_category_ids));
|
||||
|
@ -240,25 +248,27 @@ const Group = RestModel.extend({
|
|||
publish_read_state: this.publish_read_state
|
||||
};
|
||||
|
||||
["muted", "watching", "tracking", "watching_first_post"].forEach(s => {
|
||||
let prop =
|
||||
s === "watching_first_post"
|
||||
? "watchingFirstPostCategories"
|
||||
: s + "Categories";
|
||||
["muted", "regular", "watching", "tracking", "watching_first_post"].forEach(
|
||||
s => {
|
||||
let prop =
|
||||
s === "watching_first_post"
|
||||
? "watchingFirstPostCategories"
|
||||
: s + "Categories";
|
||||
|
||||
let categories = this.get(prop);
|
||||
let categories = this.get(prop);
|
||||
|
||||
if (categories) {
|
||||
attrs[s + "_category_ids"] =
|
||||
categories.length > 0 ? categories.map(c => c.get("id")) : [-1];
|
||||
if (categories) {
|
||||
attrs[s + "_category_ids"] =
|
||||
categories.length > 0 ? categories.map(c => c.get("id")) : [-1];
|
||||
}
|
||||
|
||||
let tags = this.get(s + "_tags");
|
||||
|
||||
if (tags) {
|
||||
attrs[s + "_tags"] = tags.length > 0 ? tags : [""];
|
||||
}
|
||||
}
|
||||
|
||||
let tags = this.get(s + "_tags");
|
||||
|
||||
if (tags) {
|
||||
attrs[s + "_tags"] = tags.length > 0 ? tags : [""];
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
if (this.flair_type === "icon") {
|
||||
attrs["flair_icon"] = this.flair_icon;
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-watching"}} {{i18n "user.watched_categories"}}</label>
|
||||
<label>{{d-icon "d-watching"}} {{i18n "groups.notifications.watching.title"}}</label>
|
||||
|
||||
{{category-selector
|
||||
categories=model.watchingCategories
|
||||
blacklist=selectedCategories
|
||||
blocklist=selectedCategories
|
||||
onChange=(action (mut model.watchingCategories))
|
||||
}}
|
||||
|
||||
|
@ -19,11 +19,11 @@
|
|||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-tracking"}} {{i18n "user.tracked_categories"}}</label>
|
||||
<label>{{d-icon "d-tracking"}} {{i18n "groups.notifications.tracking.title"}}</label>
|
||||
|
||||
{{category-selector
|
||||
categories=model.trackingCategories
|
||||
blacklist=selectedCategories
|
||||
blocklist=selectedCategories
|
||||
onChange=(action (mut model.trackingCategories))
|
||||
}}
|
||||
|
||||
|
@ -33,11 +33,11 @@
|
|||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-watching-first"}} {{i18n "user.watched_first_post_categories"}}</label>
|
||||
<label>{{d-icon "d-watching-first"}} {{i18n "groups.notifications.watching_first_post.title"}}</label>
|
||||
|
||||
{{category-selector
|
||||
categories=model.watchingFirstPostCategories
|
||||
blacklist=selectedCategories
|
||||
blocklist=selectedCategories
|
||||
onChange=(action (mut model.watchingFirstPostCategories))
|
||||
}}
|
||||
|
||||
|
@ -47,11 +47,25 @@
|
|||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-muted"}} {{i18n "user.muted_categories"}}</label>
|
||||
<label>{{d-icon "d-regular"}} {{i18n "groups.notifications.regular.title"}}</label>
|
||||
|
||||
{{category-selector
|
||||
categories=model.regularCategories
|
||||
blocklist=selectedCategories
|
||||
onChange=(action (mut model.regularCategories))
|
||||
}}
|
||||
|
||||
<div class="control-instructions">
|
||||
{{i18n "groups.manage.categories.regular_categories_instructions"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-muted"}} {{i18n "groups.notifications.muted.title"}}</label>
|
||||
|
||||
{{category-selector
|
||||
categories=model.mutedCategories
|
||||
blacklist=selectedCategories
|
||||
blocklist=selectedCategories
|
||||
onChange=(action (mut model.mutedCategories))
|
||||
}}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-watching"}} {{i18n "user.watched_tags"}}</label>
|
||||
<label>{{d-icon "d-watching"}} {{i18n "groups.notifications.watching.title"}}</label>
|
||||
|
||||
{{tag-chooser
|
||||
tags=model.watching_tags
|
||||
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-tracking"}} {{i18n "user.tracked_tags"}}</label>
|
||||
<label>{{d-icon "d-tracking"}} {{i18n "groups.notifications.tracking.title"}}</label>
|
||||
|
||||
{{tag-chooser
|
||||
tags=model.tracking_tags
|
||||
|
@ -37,7 +37,7 @@
|
|||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-watching-first"}} {{i18n "user.watched_first_post_tags"}}</label>
|
||||
<label>{{d-icon "d-watching-first"}} {{i18n "groups.notifications.watching_first_post.title"}}</label>
|
||||
|
||||
{{tag-chooser
|
||||
tags=model.watching_first_post_tags
|
||||
|
@ -53,7 +53,23 @@
|
|||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-muted"}} {{i18n "user.muted_tags"}}</label>
|
||||
<label>{{d-icon "d-regular"}} {{i18n "groups.notifications.regular.title"}}</label>
|
||||
|
||||
{{tag-chooser
|
||||
tags=model.regular_tags
|
||||
blacklist=selectedTags
|
||||
allowCreate=false
|
||||
everyTag=true
|
||||
unlimitedTagCount=true
|
||||
}}
|
||||
|
||||
<div class="control-instructions">
|
||||
{{i18n "groups.manage.tags.regular_tags_instructions"}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label>{{d-icon "d-muted"}} {{i18n "groups.notifications.muted.title"}}</label>
|
||||
|
||||
{{tag-chooser
|
||||
tags=model.muted_tags
|
||||
|
|
|
@ -611,7 +611,7 @@ class GroupsController < ApplicationController
|
|||
end
|
||||
|
||||
if !automatic || current_user.admin
|
||||
[:muted, :tracking, :watching, :watching_first_post].each do |level|
|
||||
[:muted, :regular, :tracking, :watching, :watching_first_post].each do |level|
|
||||
permitted_params << { "#{level}_category_ids" => [] }
|
||||
permitted_params << { "#{level}_tags" => [] }
|
||||
end
|
||||
|
|
|
@ -765,7 +765,7 @@ class Group < ActiveRecord::Base
|
|||
flair_icon.presence || flair_upload&.short_path
|
||||
end
|
||||
|
||||
[:muted, :tracking, :watching, :watching_first_post].each do |level|
|
||||
[:muted, :regular, :tracking, :watching, :watching_first_post].each do |level|
|
||||
define_method("#{level}_category_ids=") do |category_ids|
|
||||
@category_notifications ||= {}
|
||||
@category_notifications[level] = category_ids
|
||||
|
|
|
@ -86,7 +86,7 @@ class GroupUser < ActiveRecord::Base
|
|||
|
||||
higher_level_category_ids = user_levels.values.flatten
|
||||
|
||||
[:muted, :tracking, :watching_first_post, :watching].each do |level|
|
||||
[:muted, :regular, :tracking, :watching_first_post, :watching].each do |level|
|
||||
level_num = NotificationLevels.all[level]
|
||||
higher_level_category_ids -= (user_levels[level_num] || [])
|
||||
if group_category_ids = group_levels[level_num]
|
||||
|
@ -118,7 +118,7 @@ class GroupUser < ActiveRecord::Base
|
|||
|
||||
higher_level_tag_ids = user_levels.values.flatten
|
||||
|
||||
[:muted, :tracking, :watching_first_post, :watching].each do |level|
|
||||
[:muted, :regular, :tracking, :watching_first_post, :watching].each do |level|
|
||||
level_num = NotificationLevels.all[level]
|
||||
higher_level_tag_ids -= (user_levels[level_num] || [])
|
||||
if group_tag_ids = group_levels[level_num]
|
||||
|
|
|
@ -69,10 +69,12 @@ class BasicGroupSerializer < ApplicationSerializer
|
|||
admin_or_owner_attributes :watching_category_ids,
|
||||
:tracking_category_ids,
|
||||
:watching_first_post_category_ids,
|
||||
:regular_category_ids,
|
||||
:muted_category_ids,
|
||||
:watching_tags,
|
||||
:watching_first_post_tags,
|
||||
:tracking_tags,
|
||||
:regular_tags,
|
||||
:muted_tags
|
||||
|
||||
def include_display_name?
|
||||
|
@ -121,7 +123,7 @@ class BasicGroupSerializer < ApplicationSerializer
|
|||
scope.can_see_group_members?(object)
|
||||
end
|
||||
|
||||
[:watching, :tracking, :watching_first_post, :muted].each do |level|
|
||||
[:watching, :regular, :tracking, :watching_first_post, :muted].each do |level|
|
||||
define_method("#{level}_category_ids") do
|
||||
GroupCategoryNotificationDefault.lookup(object, level).pluck(:category_id)
|
||||
end
|
||||
|
|
|
@ -663,6 +663,7 @@ en:
|
|||
watched_categories_instructions: "Automatically watch all topics in these categories. Group members will be notified of all new posts and topics, and a count of new posts will also appear next to the topic."
|
||||
tracked_categories_instructions: "Automatically track all topics in these categories. A count of new posts will appear next to the topic."
|
||||
watching_first_post_categories_instructions: "Users will be notified of the first post in each new topic in these categories."
|
||||
regular_categories_instructions: "If these categories are muted, they will be unmuted for group members. Users will be notified if they are mentioned or someone replies to them."
|
||||
muted_categories_instructions: "Users will not be notified of anything about new topics in these categories, and they will not appear on the categories or latest topics pages."
|
||||
tags:
|
||||
title: Tags
|
||||
|
@ -671,6 +672,7 @@ en:
|
|||
watched_tags_instructions: "Automatically watch all topics with these tags. Group members will be notified of all new posts and topics, and a count of new posts will also appear next to the topic."
|
||||
tracked_tags_instructions: "Automatically track all topics with these tags. A count of new posts will appear next to the topic."
|
||||
watching_first_post_tags_instructions: "Users will be notified of the first post in each new topic with these tags."
|
||||
regular_tags_instructions: "If these tags are muted, they will be unmuted for group members. Users will be notified if they are mentioned or someone replies to them."
|
||||
muted_tags_instructions: "Users will not be notified of anything about new topics with these tags, and they will not appear in latest."
|
||||
logs:
|
||||
title: "Logs"
|
||||
|
|
|
@ -1059,18 +1059,22 @@ describe Group do
|
|||
let(:category1) { Fabricate(:category) }
|
||||
let(:category2) { Fabricate(:category) }
|
||||
let(:category3) { Fabricate(:category) }
|
||||
let(:category4) { Fabricate(:category) }
|
||||
let(:tag1) { Fabricate(:tag) }
|
||||
let(:tag2) { Fabricate(:tag) }
|
||||
let(:tag3) { Fabricate(:tag) }
|
||||
let(:tag4) { Fabricate(:tag) }
|
||||
let(:synonym1) { Fabricate(:tag, target_tag: tag1) }
|
||||
let(:synonym2) { Fabricate(:tag, target_tag: tag2) }
|
||||
|
||||
it "can set category notifications" do
|
||||
group.watching_category_ids = [category1.id, category2.id]
|
||||
group.tracking_category_ids = [category3.id]
|
||||
group.regular_category_ids = [category4.id]
|
||||
group.save!
|
||||
expect(GroupCategoryNotificationDefault.lookup(group, :watching).pluck(:category_id)).to contain_exactly(category1.id, category2.id)
|
||||
expect(GroupCategoryNotificationDefault.lookup(group, :tracking).pluck(:category_id)).to eq([category3.id])
|
||||
expect(GroupCategoryNotificationDefault.lookup(group, :regular).pluck(:category_id)).to eq([category4.id])
|
||||
|
||||
new_group = Fabricate.build(:group)
|
||||
new_group.watching_category_ids = [category1.id, category2.id]
|
||||
|
@ -1097,9 +1101,11 @@ describe Group do
|
|||
end
|
||||
|
||||
it "can set tag notifications" do
|
||||
group.regular_tags = [tag4.name]
|
||||
group.watching_tags = [tag1.name, tag2.name]
|
||||
group.tracking_tags = [tag3.name]
|
||||
group.save!
|
||||
expect(GroupTagNotificationDefault.lookup(group, :regular).pluck(:tag_id)).to eq([tag4.id])
|
||||
expect(GroupTagNotificationDefault.lookup(group, :watching).pluck(:tag_id)).to contain_exactly(tag1.id, tag2.id)
|
||||
expect(GroupTagNotificationDefault.lookup(group, :tracking).pluck(:tag_id)).to eq([tag3.id])
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ describe GroupUser do
|
|||
let(:category2) { Fabricate(:category) }
|
||||
let(:category3) { Fabricate(:category) }
|
||||
let(:category4) { Fabricate(:category) }
|
||||
let(:category5) { Fabricate(:category) }
|
||||
|
||||
def levels
|
||||
CategoryUser.notification_levels
|
||||
|
@ -50,16 +51,18 @@ describe GroupUser do
|
|||
|
||||
it "adds new category notifications" do
|
||||
group.muted_category_ids = [category1.id]
|
||||
group.tracking_category_ids = [category2.id]
|
||||
group.watching_category_ids = [category3.id]
|
||||
group.watching_first_post_category_ids = [category4.id]
|
||||
group.regular_category_ids = [category2.id]
|
||||
group.tracking_category_ids = [category3.id]
|
||||
group.watching_category_ids = [category4.id]
|
||||
group.watching_first_post_category_ids = [category5.id]
|
||||
group.save!
|
||||
expect { group.add(user) }.to change { CategoryUser.count }.by(4)
|
||||
expect { group.add(user) }.to change { CategoryUser.count }.by(5)
|
||||
h = CategoryUser.notification_levels_for(Guardian.new(user))
|
||||
expect(h[category1.id]).to eq(levels[:muted])
|
||||
expect(h[category2.id]).to eq(levels[:tracking])
|
||||
expect(h[category3.id]).to eq(levels[:watching])
|
||||
expect(h[category4.id]).to eq(levels[:watching_first_post])
|
||||
expect(h[category2.id]).to eq(levels[:regular])
|
||||
expect(h[category3.id]).to eq(levels[:tracking])
|
||||
expect(h[category4.id]).to eq(levels[:watching])
|
||||
expect(h[category5.id]).to eq(levels[:watching_first_post])
|
||||
end
|
||||
|
||||
it "only upgrades notifications" do
|
||||
|
@ -67,11 +70,12 @@ describe GroupUser do
|
|||
CategoryUser.create!(user: user, category_id: category2.id, notification_level: levels[:tracking])
|
||||
CategoryUser.create!(user: user, category_id: category3.id, notification_level: levels[:watching_first_post])
|
||||
CategoryUser.create!(user: user, category_id: category4.id, notification_level: levels[:watching])
|
||||
group.watching_first_post_category_ids = [category1.id, category2.id, category3.id, category4.id]
|
||||
group.regular_category_ids = [category1.id]
|
||||
group.watching_first_post_category_ids = [category2.id, category3.id, category4.id]
|
||||
group.save!
|
||||
group.add(user)
|
||||
h = CategoryUser.notification_levels_for(Guardian.new(user))
|
||||
expect(h[category1.id]).to eq(levels[:watching_first_post])
|
||||
expect(h[category1.id]).to eq(levels[:regular])
|
||||
expect(h[category2.id]).to eq(levels[:watching_first_post])
|
||||
expect(h[category3.id]).to eq(levels[:watching_first_post])
|
||||
expect(h[category4.id]).to eq(levels[:watching])
|
||||
|
@ -100,6 +104,7 @@ describe GroupUser do
|
|||
let(:tag2) { Fabricate(:tag) }
|
||||
let(:tag3) { Fabricate(:tag) }
|
||||
let(:tag4) { Fabricate(:tag) }
|
||||
let(:tag5) { Fabricate(:tag) }
|
||||
let(:synonym1) { Fabricate(:tag, target_tag: tag1) }
|
||||
|
||||
def levels
|
||||
|
@ -112,15 +117,17 @@ describe GroupUser do
|
|||
|
||||
it "adds new tag notifications" do
|
||||
group.muted_tags = [synonym1.name]
|
||||
group.tracking_tags = [tag2.name]
|
||||
group.watching_tags = [tag3.name]
|
||||
group.watching_first_post_tags = [tag4.name]
|
||||
group.regular_tags = [tag2.name]
|
||||
group.tracking_tags = [tag3.name]
|
||||
group.watching_tags = [tag4.name]
|
||||
group.watching_first_post_tags = [tag5.name]
|
||||
group.save!
|
||||
expect { group.add(user) }.to change { TagUser.count }.by(4)
|
||||
expect { group.add(user) }.to change { TagUser.count }.by(5)
|
||||
expect(TagUser.lookup(user, :muted).pluck(:tag_id)).to eq([tag1.id])
|
||||
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to eq([tag2.id])
|
||||
expect(TagUser.lookup(user, :watching).pluck(:tag_id)).to eq([tag3.id])
|
||||
expect(TagUser.lookup(user, :watching_first_post).pluck(:tag_id)).to eq([tag4.id])
|
||||
expect(TagUser.lookup(user, :regular).pluck(:tag_id)).to eq([tag2.id])
|
||||
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to eq([tag3.id])
|
||||
expect(TagUser.lookup(user, :watching).pluck(:tag_id)).to eq([tag4.id])
|
||||
expect(TagUser.lookup(user, :watching_first_post).pluck(:tag_id)).to eq([tag5.id])
|
||||
end
|
||||
|
||||
it "only upgrades notifications" do
|
||||
|
@ -128,13 +135,15 @@ describe GroupUser do
|
|||
TagUser.create!(user: user, tag_id: tag2.id, notification_level: levels[:tracking])
|
||||
TagUser.create!(user: user, tag_id: tag3.id, notification_level: levels[:watching_first_post])
|
||||
TagUser.create!(user: user, tag_id: tag4.id, notification_level: levels[:watching])
|
||||
group.watching_first_post_tags = [tag1.name, tag2.name, tag3.name, tag4.name]
|
||||
group.regular_tags = [tag1.name]
|
||||
group.watching_first_post_tags = [tag2.name, tag3.name, tag4.name]
|
||||
group.save!
|
||||
group.add(user)
|
||||
expect(TagUser.lookup(user, :muted).pluck(:tag_id)).to be_empty
|
||||
expect(TagUser.lookup(user, :regular).pluck(:tag_id)).to eq([tag1.id])
|
||||
expect(TagUser.lookup(user, :tracking).pluck(:tag_id)).to be_empty
|
||||
expect(TagUser.lookup(user, :watching).pluck(:tag_id)).to eq([tag4.id])
|
||||
expect(TagUser.lookup(user, :watching_first_post).pluck(:tag_id)).to contain_exactly(tag1.id, tag2.id, tag3.id)
|
||||
expect(TagUser.lookup(user, :watching_first_post).pluck(:tag_id)).to contain_exactly(tag2.id, tag3.id)
|
||||
end
|
||||
|
||||
it "merges notifications" do
|
||||
|
|
|
@ -16,7 +16,7 @@ QUnit.test("As an admin", async assert => {
|
|||
await visit("/g/discourse/manage/categories");
|
||||
|
||||
assert.ok(
|
||||
find(".groups-notifications-form .category-selector").length === 4,
|
||||
find(".groups-notifications-form .category-selector").length === 5,
|
||||
"it should display category inputs"
|
||||
);
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ QUnit.test("As a group owner", async assert => {
|
|||
await visit("/g/discourse/manage/categories");
|
||||
|
||||
assert.ok(
|
||||
find(".groups-notifications-form .category-selector").length === 4,
|
||||
find(".groups-notifications-form .category-selector").length === 5,
|
||||
"it should display category inputs"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@ QUnit.test("As an admin", async assert => {
|
|||
await visit("/g/discourse/manage/tags");
|
||||
|
||||
assert.ok(
|
||||
find(".groups-notifications-form .tag-chooser").length === 4,
|
||||
find(".groups-notifications-form .tag-chooser").length === 5,
|
||||
"it should display tag inputs"
|
||||
);
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ QUnit.test("As a group owner", async assert => {
|
|||
await visit("/g/discourse/manage/tags");
|
||||
|
||||
assert.ok(
|
||||
find(".groups-notifications-form .tag-chooser").length === 4,
|
||||
find(".groups-notifications-form .tag-chooser").length === 5,
|
||||
"it should display tag inputs"
|
||||
);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user