diff --git a/app/assets/javascripts/discourse/templates/preferences/categories.hbs b/app/assets/javascripts/discourse/templates/preferences/categories.hbs index e264ef11375..671242a16a9 100644 --- a/app/assets/javascripts/discourse/templates/preferences/categories.hbs +++ b/app/assets/javascripts/discourse/templates/preferences/categories.hbs @@ -27,14 +27,16 @@
{{i18n 'user.watched_first_post_categories_instructions'}}
-
- - {{#if canSee}} - {{i18n 'user.tracked_topics_link'}} - {{/if}} - {{category-selector categories=model.mutedCategories blacklist=selectedCategories}} -
-
{{i18n (if hideMutedTags 'user.muted_categories_instructions' 'user.muted_categories_instructions_dont_hide')}}
+ {{#unless siteSettings.mute_all_categories_by_default}} +
+ + {{#if canSee}} + {{i18n 'user.tracked_topics_link'}} + {{/if}} + {{category-selector categories=model.mutedCategories blacklist=selectedCategories}} +
+
{{i18n (if hideMutedTags 'user.muted_categories_instructions' 'user.muted_categories_instructions_dont_hide')}}
+ {{/unless}} {{plugin-outlet name="user-preferences-categories" args=(hash model=model save=(action "save"))}} diff --git a/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6 b/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6 index b11689796a6..be146f42857 100644 --- a/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6 +++ b/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6 @@ -173,7 +173,7 @@ export default createWidget("hamburger-menu", { listCategories() { const maxCategoriesToDisplay = this.siteSettings .header_dropdown_category_count; - let categories = this.site.get("categoriesByCount"); + let categories = []; if (this.currentUser) { const allCategories = this.site @@ -203,6 +203,10 @@ export default createWidget("hamburger-menu", { .filter(c => !categories.includes(c)) .sort((a, b) => b.topic_count - a.topic_count) ); + } else { + categories = this.site + .get("categoriesByCount") + .filter(c => c.notification_level !== NotificationLevels.MUTED); } if (!this.siteSettings.allow_uncategorized_topics) { diff --git a/app/models/category_list.rb b/app/models/category_list.rb index f1f7b6a0d94..bc1d6a4980a 100644 --- a/app/models/category_list.rb +++ b/app/models/category_list.rb @@ -92,16 +92,12 @@ class CategoryList @categories = @categories.to_a - category_user = {} - default_notification_level = nil - unless @guardian.anonymous? - category_user = Hash[*CategoryUser.where(user: @guardian.user).pluck(:category_id, :notification_level).flatten] - default_notification_level = CategoryUser.notification_levels[:regular] - end + notification_levels = CategoryUser.notification_levels_for(@guardian) + default_notification_level = CategoryUser.default_notification_level allowed_topic_create = Set.new(Category.topic_create_allowed(@guardian).pluck(:id)) @categories.each do |category| - category.notification_level = category_user[category.id] || default_notification_level + category.notification_level = notification_levels[category.id] || default_notification_level category.permission = CategoryGroup.permission_types[:full] if allowed_topic_create.include?(category.id) category.has_children = category.subcategories.present? end diff --git a/app/models/category_user.rb b/app/models/category_user.rb index e25f917d322..d2dd1a4d363 100644 --- a/app/models/category_user.rb +++ b/app/models/category_user.rb @@ -197,6 +197,26 @@ class CategoryUser < ActiveRecord::Base SQL end + def self.default_notification_level + SiteSetting.mute_all_categories_by_default ? notification_levels[:muted] : notification_levels[:regular] + end + + def self.notification_levels_for(guardian) + if guardian.anonymous? + notification_levels = [ + SiteSetting.default_categories_watching.split("|"), + SiteSetting.default_categories_tracking.split("|"), + SiteSetting.default_categories_watching_first_post.split("|"), + ].flatten.map { |id| [id.to_i, 1] } + + notification_levels += SiteSetting.default_categories_muted.split("|").map { |id| [id.to_i, 0] } + else + notification_levels = CategoryUser.where(user: guardian.user).pluck(:category_id, :notification_level) + end + + Hash[*notification_levels.flatten] + end + end # == Schema Information diff --git a/app/models/site.rb b/app/models/site.rb index c7330e1e254..d8bddf0a995 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -55,15 +55,11 @@ class Site by_id = {} - category_user = {} - unless @guardian.anonymous? - category_user = Hash[*CategoryUser.where(user: @guardian.user).pluck(:category_id, :notification_level).flatten] - end - - regular = CategoryUser.notification_levels[:regular] + notification_levels = CategoryUser.notification_levels_for(@guardian) + default_notification_level = CategoryUser.default_notification_level categories.each do |category| - category.notification_level = category_user[category.id] || regular + category.notification_level = notification_levels[category.id] || default_notification_level category.permission = CategoryGroup.permission_types[:full] if allowed_topic_create&.include?(category.id) || @guardian.is_admin? category.has_children = with_children.include?(category.id) by_id[category.id] = category diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index ffd59c83806..dac88f2d938 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2067,6 +2067,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." + 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." default_tags_tracking: "List of tags that are tracked by default." diff --git a/config/site_settings.yml b/config/site_settings.yml index 63f1aecf1c1..02a4ae33860 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -2022,6 +2022,9 @@ user_preferences: default_categories_watching_first_post: type: category_list default: "" + mute_all_categories_by_default: + default: false + client: true default_tags_watching: type: tag_list diff --git a/lib/topic_query.rb b/lib/topic_query.rb index 8a2c4637f33..dec1268030d 100644 --- a/lib/topic_query.rb +++ b/lib/topic_query.rb @@ -869,7 +869,34 @@ class TopicQuery def remove_muted_categories(list, user, opts = nil) category_id = get_category_id(opts[:exclude]) if opts - if user + if SiteSetting.mute_all_categories_by_default + if user + list = list.references("cu") + .where(" + NOT EXISTS ( + SELECT 1 + FROM categories c + LEFT OUTER JOIN category_users cu + ON c.id = cu.category_id AND cu.user_id = :user_id + WHERE c.id = topics.category_id + AND c.id <> :category_id + AND (COALESCE(cu.notification_level, :muted) = :muted) + AND (COALESCE(tu.notification_level, :regular) <= :regular) + )", user_id: user.id, + muted: CategoryUser.notification_levels[:muted], + regular: TopicUser.notification_levels[:regular], + category_id: category_id || -1) + else + category_ids = [ + SiteSetting.default_categories_watching.split("|"), + SiteSetting.default_categories_tracking.split("|"), + SiteSetting.default_categories_watching_first_post.split("|") + ].flatten.map(&:to_i) + category_ids << category_id if category_id.present? && category_ids.exclude?(category_id) + + list = list.where("topics.category_id IN (?)", category_ids) if category_ids.present? + end + elsif user list = list.references("cu") .where(" NOT EXISTS ( diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb index e3e2ab2724e..aac94f9b67a 100644 --- a/spec/components/topic_query_spec.rb +++ b/spec/components/topic_query_spec.rb @@ -240,6 +240,39 @@ describe TopicQuery do end end + context 'mute_all_categories_by_default' do + fab!(:category) { Fabricate(:category_with_definition) } + fab!(:topic) { Fabricate(:topic, category: category) } + + before do + SiteSetting.mute_all_categories_by_default = true + end + + it 'should remove all topics from new and latest lists by default' do + expect(topic_query.list_new.topics.map(&:id)).not_to include(topic.id) + expect(topic_query.list_latest.topics.map(&:id)).not_to include(topic.id) + end + + it 'should include tracked category topics in new and latest lists' do + topic = Fabricate(:topic, category: category) + CategoryUser.create!(user_id: user.id, + category_id: category.id, + notification_level: CategoryUser.notification_levels[:tracking]) + expect(topic_query.list_new.topics.map(&:id)).to include(topic.id) + expect(topic_query.list_latest.topics.map(&:id)).to include(topic.id) + end + + it 'should include default watched category topics in latest list for anonymous users' do + SiteSetting.default_categories_watching = 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) + end + end + context 'muted tags' do it 'is removed from new and latest lists' do SiteSetting.tagging_enabled = true diff --git a/spec/models/category_list_spec.rb b/spec/models/category_list_spec.rb index 85f4507894c..bc6e03963d4 100644 --- a/spec/models/category_list_spec.rb +++ b/spec/models/category_list_spec.rb @@ -65,6 +65,35 @@ describe CategoryList do end end + context "when mute_all_categories_by_default enabled" do + fab!(:category) { Fabricate(:category) } + + before do + SiteSetting.mute_all_categories_by_default = true + end + + it "removes the category by default" do + expect(category_list.categories).not_to include(category) + end + + it "returns correct notification level for user tracking category" do + CategoryUser.set_notification_level_for_category(user, NotificationLevels.all[:tracking], category.id) + notification_level = category_list.categories.find { |c| c.id == category.id }.notification_level + expect(notification_level).to eq(CategoryUser.notification_levels[:tracking]) + end + + it "returns correct notification level in default categories for anonymous" do + SiteSetting.default_categories_watching = category.id.to_s + notification_level = CategoryList.new(Guardian.new).categories.find { |c| c.id == category.id }.notification_level + expect(notification_level).to eq(CategoryUser.notification_levels[:regular]) + end + + it "removes the default muted categories for anonymous" do + SiteSetting.default_categories_muted = category.id.to_s + expect(CategoryList.new(Guardian.new).categories).not_to include(category) + end + end + context "with a category" do fab!(:topic_category) { Fabricate(:category_with_definition, num_featured_topics: 2) } @@ -114,11 +143,11 @@ describe CategoryList do expect(category.notification_level).to eq(NotificationLevels.all[:watching]) end - it "returns no notication level for anonymous users" do + it "returns default notication level for anonymous users" do category_list = CategoryList.new(Guardian.new(nil)) category = category_list.categories.find { |c| c.id == topic_category.id } - expect(category.notification_level).to be_nil + expect(category.notification_level).to eq(NotificationLevels.all[:regular]) end end diff --git a/spec/models/site_spec.rb b/spec/models/site_spec.rb index 53b5f7493e3..c97aafe10b6 100644 --- a/spec/models/site_spec.rb +++ b/spec/models/site_spec.rb @@ -41,6 +41,16 @@ describe Site do end + it "returns correct notification level for categories" do + category = Fabricate(:category) + guardian = Guardian.new + expect(Site.new(guardian).categories.last.notification_level).to eq(1) + SiteSetting.mute_all_categories_by_default = true + expect(Site.new(guardian).categories.last.notification_level).to eq(0) + SiteSetting.default_categories_tracking = category.id.to_s + expect(Site.new(guardian).categories.last.notification_level).to eq(1) + end + it "omits categories users can not write to from the category list" do category = Fabricate(:category) user = Fabricate(:user)