FEATURE: new watched_precedence_over_muted setting (#22252)
New setting which allow admin to define behavior when topic is in watched category and muted topic and vice versa. If watched_precedence_over_muted setting is true, that topic is still visible in list of topics and notification is created. If watched_precedence_over_muted setting is false, that topic is not still visible in list of topics and notification is skipped as well.
This commit is contained in:
parent
4f7f9ef87c
commit
9cf981f1f1
|
@ -200,6 +200,10 @@ class PostAlerter
|
|||
|
||||
DiscourseEvent.trigger(:post_alerter_before_post, post, new_record, notified)
|
||||
|
||||
if !SiteSetting.watched_precedence_over_muted
|
||||
notified = notified + category_or_tag_muters(post.topic)
|
||||
end
|
||||
|
||||
if new_record
|
||||
if post.topic.private_message?
|
||||
# private messages
|
||||
|
@ -265,6 +269,18 @@ class PostAlerter
|
|||
.pluck(:user_id)
|
||||
end
|
||||
|
||||
def category_or_tag_muters(topic)
|
||||
User
|
||||
.joins(
|
||||
"LEFT JOIN category_users ON users.id = category_users.user_id AND category_users.category_id = #{topic.category_id.to_i} AND category_users.notification_level = #{CategoryUser.notification_levels[:muted].to_i}",
|
||||
)
|
||||
.joins("LEFT JOIN topic_tags ON topic_tags.topic_id = #{topic.id.to_i}")
|
||||
.joins(
|
||||
"LEFT JOIN tag_users ON users.id = tag_users.user_id AND tag_users.tag_id = topic_tags.tag_id AND tag_users.notification_level = #{TagUser.notification_levels[:muted].to_i}",
|
||||
)
|
||||
.where("category_users.id IS NOT NULL OR tag_users.id IS NOT NULL")
|
||||
end
|
||||
|
||||
def notify_first_post_watchers(post, user_ids, notified = nil)
|
||||
return [] if user_ids.blank?
|
||||
user_ids.uniq!
|
||||
|
|
|
@ -2380,6 +2380,7 @@ en:
|
|||
remove_muted_tags_from_latest: "Don't show topics tagged only with muted tags in the latest topic list."
|
||||
force_lowercase_tags: "Force all new tags to be entirely lowercase."
|
||||
create_post_for_category_and_tag_changes: "Create a small action post when a topic's category or tags change"
|
||||
watched_precedence_over_muted: "Notify me about topics in categories or tags I’m watching that also belong to one I have muted"
|
||||
|
||||
company_name: "Company Name"
|
||||
governing_law: "Governing Law"
|
||||
|
|
|
@ -2820,6 +2820,10 @@ tags:
|
|||
type: enum
|
||||
default: always
|
||||
enum: RemoveMutedTagsFromLatestSiteSetting
|
||||
watched_precedence_over_muted:
|
||||
client: true
|
||||
default: false
|
||||
|
||||
force_lowercase_tags:
|
||||
default: true
|
||||
client: true
|
||||
|
|
|
@ -897,24 +897,42 @@ class TopicQuery
|
|||
category_id = get_category_id(opts[:exclude]) if opts
|
||||
|
||||
if user
|
||||
watched_tag_ids =
|
||||
if SiteSetting.watched_precedence_over_muted
|
||||
TagUser
|
||||
.where(user: user)
|
||||
.where("notification_level >= ?", TopicUser.notification_levels[:watching])
|
||||
.pluck(:tag_id)
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
# OR watched_topic_tags.id IS NOT NULL",
|
||||
list =
|
||||
list
|
||||
.references("cu")
|
||||
.joins(
|
||||
"LEFT JOIN category_users ON category_users.category_id = topics.category_id AND category_users.user_id = #{user.id}",
|
||||
list.references("cu").joins(
|
||||
"LEFT JOIN category_users ON category_users.category_id = topics.category_id AND category_users.user_id = #{user.id}",
|
||||
)
|
||||
if watched_tag_ids.present?
|
||||
list =
|
||||
list.joins(
|
||||
"LEFT JOIN topic_tags watched_topic_tags ON watched_topic_tags.topic_id = topics.id AND #{DB.sql_fragment("watched_topic_tags.tag_id IN (?)", watched_tag_ids)}",
|
||||
)
|
||||
.where(
|
||||
"topics.category_id = :category_id
|
||||
end
|
||||
|
||||
list =
|
||||
list.where(
|
||||
"topics.category_id = :category_id
|
||||
OR
|
||||
(COALESCE(category_users.notification_level, :default) <> :muted AND (topics.category_id IS NULL OR topics.category_id NOT IN(:indirectly_muted_category_ids)))
|
||||
#{watched_tag_ids.present? ? "OR watched_topic_tags.id IS NOT NULL" : ""}
|
||||
OR tu.notification_level > :regular",
|
||||
category_id: category_id || -1,
|
||||
default: CategoryUser.default_notification_level,
|
||||
indirectly_muted_category_ids:
|
||||
CategoryUser.indirectly_muted_category_ids(user).presence || [-1],
|
||||
muted: CategoryUser.notification_levels[:muted],
|
||||
regular: TopicUser.notification_levels[:regular],
|
||||
)
|
||||
category_id: category_id || -1,
|
||||
default: CategoryUser.default_notification_level,
|
||||
indirectly_muted_category_ids:
|
||||
CategoryUser.indirectly_muted_category_ids(user).presence || [-1],
|
||||
muted: CategoryUser.notification_levels[:muted],
|
||||
regular: TopicUser.notification_levels[:regular],
|
||||
)
|
||||
elsif SiteSetting.mute_all_categories_by_default
|
||||
category_ids = [
|
||||
SiteSetting.default_categories_watching.split("|"),
|
||||
|
@ -971,8 +989,18 @@ class TopicQuery
|
|||
SELECT 1
|
||||
FROM topic_tags tt
|
||||
WHERE tt.tag_id IN (:tag_ids)
|
||||
AND tt.topic_id = topics.id)",
|
||||
AND tt.topic_id = topics.id
|
||||
#{user && !opts[:skip_categories] ? "AND COALESCE(category_users.notification_level, :regular) < :watching_or_infinite" : ""})",
|
||||
tag_ids: muted_tag_ids,
|
||||
regular: CategoryUser.notification_levels[:regular],
|
||||
watching_or_infinite:
|
||||
(
|
||||
if SiteSetting.watched_precedence_over_muted
|
||||
CategoryUser.notification_levels[:watching]
|
||||
else
|
||||
99
|
||||
end
|
||||
),
|
||||
)
|
||||
else
|
||||
list =
|
||||
|
@ -981,10 +1009,20 @@ class TopicQuery
|
|||
EXISTS (
|
||||
SELECT 1
|
||||
FROM topic_tags tt
|
||||
WHERE tt.tag_id NOT IN (:tag_ids)
|
||||
AND tt.topic_id = topics.id
|
||||
WHERE (tt.tag_id NOT IN (:tag_ids)
|
||||
AND tt.topic_id = topics.id)
|
||||
#{user && !opts[:skip_categories] ? "OR COALESCE(category_users.notification_level, :regular) >= :watching_or_infinite" : ""}
|
||||
) OR NOT EXISTS (SELECT 1 FROM topic_tags tt WHERE tt.topic_id = topics.id)",
|
||||
tag_ids: muted_tag_ids,
|
||||
regular: CategoryUser.notification_levels[:regular],
|
||||
watching_or_infinite:
|
||||
(
|
||||
if SiteSetting.watched_precedence_over_muted
|
||||
CategoryUser.notification_levels[:watching]
|
||||
else
|
||||
99
|
||||
end
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -49,7 +49,7 @@ class TopicQuery
|
|||
|
||||
def list_private_messages_new(user, type = :user)
|
||||
list = filter_private_message_new(user, type)
|
||||
list = TopicQuery.remove_muted_tags(list, user)
|
||||
list = TopicQuery.remove_muted_tags(list, user, skip_categories: true)
|
||||
list = remove_dismissed(list, user)
|
||||
|
||||
create_list(:private_messages, {}, list)
|
||||
|
|
|
@ -2092,4 +2092,73 @@ RSpec.describe TopicQuery do
|
|||
expect(original_topic_query.list_latest.topics.map(&:id)).to eq([topic2, topic1].map(&:id))
|
||||
end
|
||||
end
|
||||
|
||||
describe "precedence of categories and tag setting" do
|
||||
fab!(:watched_category) do
|
||||
Fabricate(:category).tap do |category|
|
||||
CategoryUser.create!(
|
||||
user: user,
|
||||
category: category,
|
||||
notification_level: CategoryUser.notification_levels[:watching],
|
||||
)
|
||||
end
|
||||
end
|
||||
fab!(:muted_category) do
|
||||
Fabricate(:category).tap do |category|
|
||||
CategoryUser.create!(
|
||||
user: user,
|
||||
category: category,
|
||||
notification_level: CategoryUser.notification_levels[:muted],
|
||||
)
|
||||
end
|
||||
end
|
||||
fab!(:watched_tag) do
|
||||
Fabricate(:tag).tap do |tag|
|
||||
TagUser.create!(
|
||||
user: user,
|
||||
tag: tag,
|
||||
notification_level: TagUser.notification_levels[:watching],
|
||||
)
|
||||
end
|
||||
end
|
||||
fab!(:muted_tag) do
|
||||
Fabricate(:tag).tap do |tag|
|
||||
TagUser.create!(
|
||||
user: user,
|
||||
tag: tag,
|
||||
notification_level: TagUser.notification_levels[:muted],
|
||||
)
|
||||
end
|
||||
end
|
||||
fab!(:topic) { Fabricate(:topic) }
|
||||
fab!(:topic_in_watched_category_and_muted_tag) do
|
||||
Fabricate(:topic, category: watched_category, tags: [muted_tag])
|
||||
end
|
||||
fab!(:topic_in_muted_category_and_watched_tag) do
|
||||
Fabricate(:topic, category: muted_category, tags: [watched_tag])
|
||||
end
|
||||
fab!(:topic_in_watched_and_muted_tag) { Fabricate(:topic, tags: [watched_tag, muted_tag]) }
|
||||
fab!(:topic_in_muted_category) { Fabricate(:topic, category: muted_category) }
|
||||
fab!(:topic_in_muted_tag) { Fabricate(:topic, tags: [muted_tag]) }
|
||||
|
||||
context "when enabled" do
|
||||
it "returns topics even if category or tag is muted but another tag or category is watched" do
|
||||
SiteSetting.watched_precedence_over_muted = true
|
||||
query = TopicQuery.new(user).list_latest
|
||||
expect(query.topics.map(&:id)).to contain_exactly(
|
||||
topic.id,
|
||||
topic_in_watched_category_and_muted_tag.id,
|
||||
topic_in_muted_category_and_watched_tag.id,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when disabled" do
|
||||
it "returns topics without muted category or tag" do
|
||||
SiteSetting.watched_precedence_over_muted = false
|
||||
query = TopicQuery.new(user).list_latest
|
||||
expect(query.topics.map(&:id)).to contain_exactly(topic.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -230,6 +230,8 @@ RSpec.describe TagUser do
|
|||
end
|
||||
|
||||
it "sets notification level to the highest one if there are multiple tags" do
|
||||
SiteSetting.watched_precedence_over_muted = true
|
||||
|
||||
TagUser.create!(
|
||||
user: user,
|
||||
tag: tracked_tag,
|
||||
|
|
|
@ -1871,6 +1871,77 @@ RSpec.describe PostAlerter do
|
|||
end
|
||||
end
|
||||
|
||||
context "with category and tags" do
|
||||
fab!(:muted_category) do
|
||||
Fabricate(:category).tap do |category|
|
||||
CategoryUser.set_notification_level_for_category(
|
||||
user,
|
||||
CategoryUser.notification_levels[:muted],
|
||||
category.id,
|
||||
)
|
||||
end
|
||||
end
|
||||
fab!(:muted_tag) do
|
||||
Fabricate(:tag).tap do |tag|
|
||||
TagUser.create!(
|
||||
user: user,
|
||||
tag: tag,
|
||||
notification_level: TagUser.notification_levels[:muted],
|
||||
)
|
||||
end
|
||||
end
|
||||
fab!(:watched_tag) do
|
||||
Fabricate(:tag).tap do |tag|
|
||||
TagUser.create!(
|
||||
user: user,
|
||||
tag: tag,
|
||||
notification_level: TagUser.notification_levels[:watching],
|
||||
)
|
||||
end
|
||||
end
|
||||
fab!(:topic_with_muted_tag_and_watched_category) do
|
||||
Fabricate(:topic, category: category, tags: [muted_tag])
|
||||
end
|
||||
fab!(:topic_with_muted_category_and_watched_tag) do
|
||||
Fabricate(:topic, category: muted_category, tags: [watched_tag])
|
||||
end
|
||||
fab!(:topic_with_watched_category) { Fabricate(:topic, category: category) }
|
||||
fab!(:post) { Fabricate(:post, topic: topic_with_muted_tag_and_watched_category) }
|
||||
fab!(:post_2) { Fabricate(:post, topic: topic_with_muted_category_and_watched_tag) }
|
||||
fab!(:post_3) { Fabricate(:post, topic: topic_with_watched_category) }
|
||||
|
||||
before do
|
||||
CategoryUser.set_notification_level_for_category(
|
||||
user,
|
||||
CategoryUser.notification_levels[:watching],
|
||||
category.id,
|
||||
)
|
||||
end
|
||||
|
||||
it "adds notification when watched_precedence_over_mute setting is true" do
|
||||
SiteSetting.watched_precedence_over_muted = true
|
||||
expect {
|
||||
PostAlerter.post_created(topic_with_muted_tag_and_watched_category.posts.first)
|
||||
}.to change { Notification.count }.by(1)
|
||||
expect {
|
||||
PostAlerter.post_created(topic_with_muted_category_and_watched_tag.posts.first)
|
||||
}.to change { Notification.count }.by(1)
|
||||
end
|
||||
|
||||
it "does not add notification when watched_precedence_over_mute setting is false" do
|
||||
SiteSetting.watched_precedence_over_muted = false
|
||||
expect {
|
||||
PostAlerter.post_created(topic_with_muted_tag_and_watched_category.posts.first)
|
||||
}.not_to change { Notification.count }
|
||||
expect {
|
||||
PostAlerter.post_created(topic_with_muted_category_and_watched_tag.posts.first)
|
||||
}.not_to change { Notification.count }
|
||||
expect { PostAlerter.post_created(topic_with_watched_category.posts.first) }.to change {
|
||||
Notification.count
|
||||
}.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
context "with on change" do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
fab!(:other_tag) { Fabricate(:tag) }
|
||||
|
|
Loading…
Reference in New Issue