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:
Vinoth Kannan 2020-08-20 00:35:04 +05:30 committed by GitHub
parent a3c0d4a8b5
commit 8348a41124
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 109 additions and 27 deletions

View File

@ -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",

View File

@ -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

View File

@ -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(

View File

@ -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"))}}

View File

@ -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)

View File

@ -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]] }

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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!"

View File

@ -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."

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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 ?

View File

@ -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: [],