FEATURE: add `regular_categories` field in site setting & user option. (#10477)
Like "default watching" and "default tracking" categories option now the "regular" categories support is added. It will be useful for sites that are muted by default. The user option will be displayed only if `mute_all_categories_by_default` site setting is enabled.
This commit is contained in:
parent
a3c0d4a8b5
commit
8348a41124
|
@ -173,6 +173,7 @@ export default Mixin.create({
|
|||
"default_categories_tracking",
|
||||
"default_categories_muted",
|
||||
"default_categories_watching_first_post",
|
||||
"default_categories_regular",
|
||||
"default_tags_watching",
|
||||
"default_tags_tracking",
|
||||
"default_tags_muted",
|
||||
|
|
|
@ -9,6 +9,7 @@ export default Controller.extend({
|
|||
|
||||
this.saveAttrNames = [
|
||||
"muted_category_ids",
|
||||
"regular_category_ids",
|
||||
"watched_category_ids",
|
||||
"tracked_category_ids",
|
||||
"watched_first_post_category_ids"
|
||||
|
@ -19,10 +20,13 @@ export default Controller.extend({
|
|||
"model.watchedCategories",
|
||||
"model.watchedFirstPostCategories",
|
||||
"model.trackedCategories",
|
||||
"model.regularCategories",
|
||||
"model.mutedCategories"
|
||||
)
|
||||
selectedCategories(watched, watchedFirst, tracked, muted) {
|
||||
return [].concat(watched, watchedFirst, tracked, muted).filter(t => t);
|
||||
selectedCategories(watched, watchedFirst, tracked, regular, muted) {
|
||||
return []
|
||||
.concat(watched, watchedFirst, tracked, regular, muted)
|
||||
.filter(t => t);
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
|
|
|
@ -332,25 +332,27 @@ const User = RestModel.extend({
|
|||
|
||||
var updatedState = {};
|
||||
|
||||
["muted", "watched", "tracked", "watched_first_post"].forEach(s => {
|
||||
if (fields === undefined || fields.includes(s + "_category_ids")) {
|
||||
let prop =
|
||||
s === "watched_first_post"
|
||||
? "watchedFirstPostCategories"
|
||||
: s + "Categories";
|
||||
let cats = this.get(prop);
|
||||
if (cats) {
|
||||
let cat_ids = cats.map(c => c.get("id"));
|
||||
updatedState[s + "_category_ids"] = cat_ids;
|
||||
["muted", "regular", "watched", "tracked", "watched_first_post"].forEach(
|
||||
s => {
|
||||
if (fields === undefined || fields.includes(s + "_category_ids")) {
|
||||
let prop =
|
||||
s === "watched_first_post"
|
||||
? "watchedFirstPostCategories"
|
||||
: s + "Categories";
|
||||
let cats = this.get(prop);
|
||||
if (cats) {
|
||||
let cat_ids = cats.map(c => c.get("id"));
|
||||
updatedState[s + "_category_ids"] = cat_ids;
|
||||
|
||||
// HACK: denote lack of categories
|
||||
if (cats.length === 0) {
|
||||
cat_ids = [-1];
|
||||
// HACK: denote lack of categories
|
||||
if (cats.length === 0) {
|
||||
cat_ids = [-1];
|
||||
}
|
||||
data[s + "_category_ids"] = cat_ids;
|
||||
}
|
||||
data[s + "_category_ids"] = cat_ids;
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
[
|
||||
"muted_tags",
|
||||
|
@ -704,6 +706,14 @@ const User = RestModel.extend({
|
|||
this.set("mutedCategories", Category.findByIds(this.muted_category_ids));
|
||||
},
|
||||
|
||||
@observes("regular_category_ids")
|
||||
updateRegularCategories() {
|
||||
this.set(
|
||||
"regularCategories",
|
||||
Category.findByIds(this.regular_category_ids)
|
||||
);
|
||||
},
|
||||
|
||||
@observes("tracked_category_ids")
|
||||
updateTrackedCategories() {
|
||||
this.set(
|
||||
|
|
|
@ -37,7 +37,17 @@
|
|||
</div>
|
||||
<div class="instructions">{{i18n "user.watched_first_post_categories_instructions"}}</div>
|
||||
|
||||
{{#unless siteSettings.mute_all_categories_by_default}}
|
||||
{{#if siteSettings.mute_all_categories_by_default}}
|
||||
<div class="controls tracking-controls">
|
||||
<label>{{d-icon "d-regular"}} {{i18n "user.regular_categories"}}</label>
|
||||
{{category-selector
|
||||
categories=model.regularCategories
|
||||
blocklist=selectedCategories
|
||||
onChange=(action (mut model.regularCategories))
|
||||
}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n "user.regular_categories_instructions"}}</div>
|
||||
{{else}}
|
||||
<div class="controls tracking-controls">
|
||||
<label>{{d-icon "d-muted"}} {{i18n "user.muted_categories"}}</label>
|
||||
{{#if canSee}}
|
||||
|
@ -50,7 +60,7 @@
|
|||
}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n (if hideMutedTags "user.muted_categories_instructions" "user.muted_categories_instructions_dont_hide")}}</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{plugin-outlet name="user-preferences-categories" args=(hash model=model save=(action "save"))}}
|
||||
|
|
|
@ -54,6 +54,8 @@ class Admin::SiteSettingsController < Admin::AdminController
|
|||
notification_level = NotificationLevels.all[:muted]
|
||||
when "default_categories_watching_first_post"
|
||||
notification_level = NotificationLevels.all[:watching_first_post]
|
||||
when "default_categories_regular"
|
||||
notification_level = NotificationLevels.all[:regular]
|
||||
end
|
||||
|
||||
CategoryUser.where(category_id: (previous_category_ids - new_category_ids), notification_level: notification_level).delete_all
|
||||
|
@ -131,6 +133,8 @@ class Admin::SiteSettingsController < Admin::AdminController
|
|||
notification_level = NotificationLevels.all[:muted]
|
||||
when "default_categories_watching_first_post"
|
||||
notification_level = NotificationLevels.all[:watching_first_post]
|
||||
when "default_categories_regular"
|
||||
notification_level = NotificationLevels.all[:regular]
|
||||
end
|
||||
|
||||
user_ids = CategoryUser.where(category_id: previous_category_ids - new_category_ids, notification_level: notification_level).distinct.pluck(:user_id)
|
||||
|
|
|
@ -207,6 +207,7 @@ class CategoryUser < ActiveRecord::Base
|
|||
SiteSetting.default_categories_watching.split("|"),
|
||||
SiteSetting.default_categories_tracking.split("|"),
|
||||
SiteSetting.default_categories_watching_first_post.split("|"),
|
||||
SiteSetting.default_categories_regular.split("|")
|
||||
].flatten.map { |id| [id.to_i, self.notification_levels[:regular]] }
|
||||
|
||||
notification_levels += SiteSetting.default_categories_muted.split("|").map { |id| [id.to_i, self.notification_levels[:muted]] }
|
||||
|
|
|
@ -1448,7 +1448,7 @@ class User < ActiveRecord::Base
|
|||
|
||||
values = []
|
||||
|
||||
%w{watching watching_first_post tracking muted}.each do |s|
|
||||
%w{watching watching_first_post tracking regular muted}.each do |s|
|
||||
category_ids = SiteSetting.get("default_categories_#{s}").split("|").map(&:to_i)
|
||||
category_ids.each do |category_id|
|
||||
next if category_id == 0
|
||||
|
|
|
@ -35,6 +35,7 @@ class UserSerializer < UserCardSerializer
|
|||
|
||||
private_attributes :locale,
|
||||
:muted_category_ids,
|
||||
:regular_category_ids,
|
||||
:watched_tags,
|
||||
:watching_first_post_tags,
|
||||
:tracked_tags,
|
||||
|
@ -219,6 +220,10 @@ class UserSerializer < UserCardSerializer
|
|||
CategoryUser.lookup(object, :muted).pluck(:category_id)
|
||||
end
|
||||
|
||||
def regular_category_ids
|
||||
CategoryUser.lookup(object, :regular).pluck(:category_id)
|
||||
end
|
||||
|
||||
def tracked_category_ids
|
||||
CategoryUser.lookup(object, :tracking).pluck(:category_id)
|
||||
end
|
||||
|
|
|
@ -6,6 +6,7 @@ class UserUpdater
|
|||
watched_first_post_category_ids: :watching_first_post,
|
||||
watched_category_ids: :watching,
|
||||
tracked_category_ids: :tracking,
|
||||
regular_category_ids: :regular,
|
||||
muted_category_ids: :muted
|
||||
}
|
||||
|
||||
|
|
|
@ -984,6 +984,8 @@ en:
|
|||
muted_categories: "Muted"
|
||||
muted_categories_instructions: "You will not be notified of anything about new topics in these categories, and they will not appear on the categories or latest pages."
|
||||
muted_categories_instructions_dont_hide: "You will not be notified of anything about new topics in these categories."
|
||||
regular_categories: "Regular"
|
||||
regular_categories_instructions: "These category topics will be displayed in the `latest` and `top` topics list."
|
||||
no_category_access: "As a moderator you have limited category access, save is disabled."
|
||||
delete_account: "Delete My Account"
|
||||
delete_account_confirm: "Are you sure you want to permanently delete your account? This action cannot be undone!"
|
||||
|
|
|
@ -2172,6 +2172,7 @@ en:
|
|||
default_categories_tracking: "List of categories that are tracked by default."
|
||||
default_categories_muted: "List of categories that are muted by default."
|
||||
default_categories_watching_first_post: "List of categories in which first post in each new topic will be watched by default."
|
||||
default_categories_regular: "List of categories that are normal by default. Useful when `mute_all_categories_by_default` site setting is enabled."
|
||||
mute_all_categories_by_default: "Set the default notification level of all the categories to muted. Require users opt-in to categories for them to appear in 'latest' and 'categories' pages. If you wish to amend the defaults for anonymous users set 'default_categories_' settings."
|
||||
|
||||
default_tags_watching: "List of tags that are watched by default."
|
||||
|
|
|
@ -2174,6 +2174,9 @@ user_preferences:
|
|||
default_categories_watching_first_post:
|
||||
type: category_list
|
||||
default: ""
|
||||
default_categories_regular:
|
||||
type: category_list
|
||||
default: ""
|
||||
mute_all_categories_by_default:
|
||||
default: false
|
||||
client: true
|
||||
|
|
|
@ -23,7 +23,8 @@ module SiteSettings::Validations
|
|||
default_categories_selected = [
|
||||
SiteSetting.default_categories_tracking.split("|"),
|
||||
SiteSetting.default_categories_muted.split("|"),
|
||||
SiteSetting.default_categories_watching_first_post.split("|")
|
||||
SiteSetting.default_categories_watching_first_post.split("|"),
|
||||
SiteSetting.default_categories_regular.split("|")
|
||||
].flatten.map(&:to_i).to_set
|
||||
|
||||
validate_default_categories(category_ids, default_categories_selected)
|
||||
|
@ -35,7 +36,8 @@ module SiteSettings::Validations
|
|||
default_categories_selected = [
|
||||
SiteSetting.default_categories_watching.split("|"),
|
||||
SiteSetting.default_categories_muted.split("|"),
|
||||
SiteSetting.default_categories_watching_first_post.split("|")
|
||||
SiteSetting.default_categories_watching_first_post.split("|"),
|
||||
SiteSetting.default_categories_regular.split("|")
|
||||
].flatten.map(&:to_i).to_set
|
||||
|
||||
validate_default_categories(category_ids, default_categories_selected)
|
||||
|
@ -47,7 +49,8 @@ module SiteSettings::Validations
|
|||
default_categories_selected = [
|
||||
SiteSetting.default_categories_watching.split("|"),
|
||||
SiteSetting.default_categories_tracking.split("|"),
|
||||
SiteSetting.default_categories_watching_first_post.split("|")
|
||||
SiteSetting.default_categories_watching_first_post.split("|"),
|
||||
SiteSetting.default_categories_regular.split("|")
|
||||
].flatten.map(&:to_i).to_set
|
||||
|
||||
validate_default_categories(category_ids, default_categories_selected)
|
||||
|
@ -59,7 +62,21 @@ module SiteSettings::Validations
|
|||
default_categories_selected = [
|
||||
SiteSetting.default_categories_watching.split("|"),
|
||||
SiteSetting.default_categories_tracking.split("|"),
|
||||
SiteSetting.default_categories_muted.split("|")
|
||||
SiteSetting.default_categories_muted.split("|"),
|
||||
SiteSetting.default_categories_regular.split("|")
|
||||
].flatten.map(&:to_i).to_set
|
||||
|
||||
validate_default_categories(category_ids, default_categories_selected)
|
||||
end
|
||||
|
||||
def validate_default_categories_regular(new_val)
|
||||
category_ids = validate_category_ids(new_val)
|
||||
|
||||
default_categories_selected = [
|
||||
SiteSetting.default_categories_watching.split("|"),
|
||||
SiteSetting.default_categories_tracking.split("|"),
|
||||
SiteSetting.default_categories_muted.split("|"),
|
||||
SiteSetting.default_categories_watching_first_post.split("|")
|
||||
].flatten.map(&:to_i).to_set
|
||||
|
||||
validate_default_categories(category_ids, default_categories_selected)
|
||||
|
|
|
@ -891,7 +891,8 @@ class TopicQuery
|
|||
category_ids = [
|
||||
SiteSetting.default_categories_watching.split("|"),
|
||||
SiteSetting.default_categories_tracking.split("|"),
|
||||
SiteSetting.default_categories_watching_first_post.split("|")
|
||||
SiteSetting.default_categories_watching_first_post.split("|"),
|
||||
SiteSetting.default_categories_regular.split("|")
|
||||
].flatten.map(&:to_i)
|
||||
category_ids << category_id if category_id.present? && category_ids.exclude?(category_id)
|
||||
|
||||
|
|
|
@ -338,6 +338,11 @@ describe TopicQuery do
|
|||
expect(TopicQuery.new.list_latest.topics.map(&:id)).to include(topic.id)
|
||||
end
|
||||
|
||||
it 'should include default regular category topics in latest list for anonymous users' do
|
||||
SiteSetting.default_categories_regular = category.id.to_s
|
||||
expect(TopicQuery.new.list_latest.topics.map(&:id)).to include(topic.id)
|
||||
end
|
||||
|
||||
it 'should include topics when filtered by category' do
|
||||
topic_query = TopicQuery.new(user, category: topic.category_id)
|
||||
expect(topic_query.list_latest.topics.map(&:id)).to include(topic.id)
|
||||
|
|
|
@ -1645,6 +1645,7 @@ describe User do
|
|||
fab!(:category1) { Fabricate(:category) }
|
||||
fab!(:category2) { Fabricate(:category) }
|
||||
fab!(:category3) { Fabricate(:category) }
|
||||
fab!(:category4) { Fabricate(:category) }
|
||||
|
||||
before do
|
||||
SiteSetting.default_email_digest_frequency = 1440 # daily
|
||||
|
@ -1666,6 +1667,7 @@ describe User do
|
|||
SiteSetting.default_categories_tracking = category1.id.to_s
|
||||
SiteSetting.default_categories_muted = category2.id.to_s
|
||||
SiteSetting.default_categories_watching_first_post = category3.id.to_s
|
||||
SiteSetting.default_categories_regular = category4.id.to_s
|
||||
end
|
||||
|
||||
it "has overriden preferences" do
|
||||
|
@ -1688,6 +1690,7 @@ describe User do
|
|||
expect(CategoryUser.lookup(user, :tracking).pluck(:category_id)).to eq([category1.id])
|
||||
expect(CategoryUser.lookup(user, :muted).pluck(:category_id)).to eq([category2.id])
|
||||
expect(CategoryUser.lookup(user, :watching_first_post).pluck(:category_id)).to eq([category3.id])
|
||||
expect(CategoryUser.lookup(user, :regular).pluck(:category_id)).to eq([category4.id])
|
||||
end
|
||||
|
||||
it "does not set category preferences for staged users" do
|
||||
|
@ -1696,6 +1699,7 @@ describe User do
|
|||
expect(CategoryUser.lookup(user, :tracking).pluck(:category_id)).to eq([])
|
||||
expect(CategoryUser.lookup(user, :muted).pluck(:category_id)).to eq([])
|
||||
expect(CategoryUser.lookup(user, :watching_first_post).pluck(:category_id)).to eq([])
|
||||
expect(CategoryUser.lookup(user, :regular).pluck(:category_id)).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ require 'rails_helper'
|
|||
|
||||
describe SiteSerializer do
|
||||
let(:guardian) { Guardian.new }
|
||||
let(:category) { Fabricate(:category) }
|
||||
|
||||
it "includes category custom fields only if its preloaded" do
|
||||
category = Fabricate(:category)
|
||||
category.custom_fields["enable_marketplace"] = true
|
||||
category.save_custom_fields
|
||||
|
||||
|
@ -18,4 +18,14 @@ describe SiteSerializer do
|
|||
data = MultiJson.dump(described_class.new(Site.new(guardian), scope: guardian, root: false))
|
||||
expect(data).to include("enable_marketplace")
|
||||
end
|
||||
|
||||
it "returns correct notification level for categories" do
|
||||
SiteSetting.mute_all_categories_by_default = true
|
||||
SiteSetting.default_categories_regular = category.id.to_s
|
||||
|
||||
serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json
|
||||
categories = serialized[:categories]
|
||||
expect(categories[0][:notification_level]).to eq(0)
|
||||
expect(categories[-1][:notification_level]).to eq(1)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,7 +23,7 @@ RSpec.describe WebHookUserSerializer do
|
|||
|
||||
it 'should only include the required keys' do
|
||||
count = serializer.as_json.keys.count
|
||||
difference = count - 49
|
||||
difference = count - 50
|
||||
|
||||
expect(difference).to eq(0), lambda {
|
||||
message = (difference < 0 ?
|
||||
|
|
|
@ -179,6 +179,7 @@ export default {
|
|||
skip_new_user_tips: false,
|
||||
enable_quoting: true,
|
||||
muted_category_ids: [],
|
||||
regular_category_ids: [],
|
||||
tracked_category_ids: [],
|
||||
watched_category_ids: [3],
|
||||
watched_first_post_category_ids: [],
|
||||
|
@ -2499,6 +2500,7 @@ export default {
|
|||
can_delete_all_posts: true,
|
||||
locale: null,
|
||||
muted_category_ids: [],
|
||||
regular_category_ids: [],
|
||||
watched_tags: [],
|
||||
watching_first_post_tags: [],
|
||||
tracked_tags: [],
|
||||
|
@ -2857,6 +2859,7 @@ export default {
|
|||
associated_accounts: [],
|
||||
locale: "en_US",
|
||||
muted_category_ids: [],
|
||||
regular_category_ids: [],
|
||||
watched_tags: [],
|
||||
watching_first_post_tags: [],
|
||||
tracked_tags: [],
|
||||
|
|
Loading…
Reference in New Issue