mirror of
https://github.com/discourse/discourse.git
synced 2025-06-05 14:07:30 +08:00
FEATURE: support to mute all categories by default. (#8295)
Instead of enabling `suppress_from_latest` setting on many categories now we can enable `mute_all_categories_by_default` site setting. Then users should opt-in to categories for them to appear in the latest and categories pages.
This commit is contained in:
@ -27,14 +27,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="instructions">{{i18n 'user.watched_first_post_categories_instructions'}}</div>
|
<div class="instructions">{{i18n 'user.watched_first_post_categories_instructions'}}</div>
|
||||||
|
|
||||||
<div class="controls tracking-controls">
|
{{#unless siteSettings.mute_all_categories_by_default}}
|
||||||
<label>{{d-icon "d-muted"}} {{i18n 'user.muted_categories'}}</label>
|
<div class="controls tracking-controls">
|
||||||
{{#if canSee}}
|
<label>{{d-icon "d-muted"}} {{i18n 'user.muted_categories'}}</label>
|
||||||
<a class="show-tracking" href="{{unbound model.mutedTopicsPath}}">{{i18n 'user.tracked_topics_link'}}</a>
|
{{#if canSee}}
|
||||||
{{/if}}
|
<a class="show-tracking" href="{{unbound model.mutedTopicsPath}}">{{i18n 'user.tracked_topics_link'}}</a>
|
||||||
{{category-selector categories=model.mutedCategories blacklist=selectedCategories}}
|
{{/if}}
|
||||||
</div>
|
{{category-selector categories=model.mutedCategories blacklist=selectedCategories}}
|
||||||
<div class="instructions">{{i18n (if hideMutedTags 'user.muted_categories_instructions' 'user.muted_categories_instructions_dont_hide')}}</div>
|
</div>
|
||||||
|
<div class="instructions">{{i18n (if hideMutedTags 'user.muted_categories_instructions' 'user.muted_categories_instructions_dont_hide')}}</div>
|
||||||
|
{{/unless}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{plugin-outlet name="user-preferences-categories" args=(hash model=model save=(action "save"))}}
|
{{plugin-outlet name="user-preferences-categories" args=(hash model=model save=(action "save"))}}
|
||||||
|
@ -173,7 +173,7 @@ export default createWidget("hamburger-menu", {
|
|||||||
listCategories() {
|
listCategories() {
|
||||||
const maxCategoriesToDisplay = this.siteSettings
|
const maxCategoriesToDisplay = this.siteSettings
|
||||||
.header_dropdown_category_count;
|
.header_dropdown_category_count;
|
||||||
let categories = this.site.get("categoriesByCount");
|
let categories = [];
|
||||||
|
|
||||||
if (this.currentUser) {
|
if (this.currentUser) {
|
||||||
const allCategories = this.site
|
const allCategories = this.site
|
||||||
@ -203,6 +203,10 @@ export default createWidget("hamburger-menu", {
|
|||||||
.filter(c => !categories.includes(c))
|
.filter(c => !categories.includes(c))
|
||||||
.sort((a, b) => b.topic_count - a.topic_count)
|
.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) {
|
if (!this.siteSettings.allow_uncategorized_topics) {
|
||||||
|
@ -92,16 +92,12 @@ class CategoryList
|
|||||||
|
|
||||||
@categories = @categories.to_a
|
@categories = @categories.to_a
|
||||||
|
|
||||||
category_user = {}
|
notification_levels = CategoryUser.notification_levels_for(@guardian)
|
||||||
default_notification_level = nil
|
default_notification_level = CategoryUser.default_notification_level
|
||||||
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
|
|
||||||
|
|
||||||
allowed_topic_create = Set.new(Category.topic_create_allowed(@guardian).pluck(:id))
|
allowed_topic_create = Set.new(Category.topic_create_allowed(@guardian).pluck(:id))
|
||||||
@categories.each do |category|
|
@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.permission = CategoryGroup.permission_types[:full] if allowed_topic_create.include?(category.id)
|
||||||
category.has_children = category.subcategories.present?
|
category.has_children = category.subcategories.present?
|
||||||
end
|
end
|
||||||
|
@ -197,6 +197,26 @@ class CategoryUser < ActiveRecord::Base
|
|||||||
SQL
|
SQL
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
|
@ -55,15 +55,11 @@ class Site
|
|||||||
|
|
||||||
by_id = {}
|
by_id = {}
|
||||||
|
|
||||||
category_user = {}
|
notification_levels = CategoryUser.notification_levels_for(@guardian)
|
||||||
unless @guardian.anonymous?
|
default_notification_level = CategoryUser.default_notification_level
|
||||||
category_user = Hash[*CategoryUser.where(user: @guardian.user).pluck(:category_id, :notification_level).flatten]
|
|
||||||
end
|
|
||||||
|
|
||||||
regular = CategoryUser.notification_levels[:regular]
|
|
||||||
|
|
||||||
categories.each do |category|
|
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.permission = CategoryGroup.permission_types[:full] if allowed_topic_create&.include?(category.id) || @guardian.is_admin?
|
||||||
category.has_children = with_children.include?(category.id)
|
category.has_children = with_children.include?(category.id)
|
||||||
by_id[category.id] = category
|
by_id[category.id] = category
|
||||||
|
@ -2067,6 +2067,7 @@ en:
|
|||||||
default_categories_tracking: "List of categories that are tracked by default."
|
default_categories_tracking: "List of categories that are tracked by default."
|
||||||
default_categories_muted: "List of categories that are muted 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_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_watching: "List of tags that are watched by default."
|
||||||
default_tags_tracking: "List of tags that are tracked by default."
|
default_tags_tracking: "List of tags that are tracked by default."
|
||||||
|
@ -2022,6 +2022,9 @@ user_preferences:
|
|||||||
default_categories_watching_first_post:
|
default_categories_watching_first_post:
|
||||||
type: category_list
|
type: category_list
|
||||||
default: ""
|
default: ""
|
||||||
|
mute_all_categories_by_default:
|
||||||
|
default: false
|
||||||
|
client: true
|
||||||
|
|
||||||
default_tags_watching:
|
default_tags_watching:
|
||||||
type: tag_list
|
type: tag_list
|
||||||
|
@ -869,7 +869,34 @@ class TopicQuery
|
|||||||
def remove_muted_categories(list, user, opts = nil)
|
def remove_muted_categories(list, user, opts = nil)
|
||||||
category_id = get_category_id(opts[:exclude]) if opts
|
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")
|
list = list.references("cu")
|
||||||
.where("
|
.where("
|
||||||
NOT EXISTS (
|
NOT EXISTS (
|
||||||
|
@ -240,6 +240,39 @@ describe TopicQuery do
|
|||||||
end
|
end
|
||||||
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
|
context 'muted tags' do
|
||||||
it 'is removed from new and latest lists' do
|
it 'is removed from new and latest lists' do
|
||||||
SiteSetting.tagging_enabled = true
|
SiteSetting.tagging_enabled = true
|
||||||
|
@ -65,6 +65,35 @@ describe CategoryList do
|
|||||||
end
|
end
|
||||||
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
|
context "with a category" do
|
||||||
|
|
||||||
fab!(:topic_category) { Fabricate(:category_with_definition, num_featured_topics: 2) }
|
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])
|
expect(category.notification_level).to eq(NotificationLevels.all[:watching])
|
||||||
end
|
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_list = CategoryList.new(Guardian.new(nil))
|
||||||
category = category_list.categories.find { |c| c.id == topic_category.id }
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -41,6 +41,16 @@ describe Site do
|
|||||||
|
|
||||||
end
|
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
|
it "omits categories users can not write to from the category list" do
|
||||||
category = Fabricate(:category)
|
category = Fabricate(:category)
|
||||||
user = Fabricate(:user)
|
user = Fabricate(:user)
|
||||||
|
Reference in New Issue
Block a user