FEATURE: Silence Close Notifications User Setting (#26072)
This change creates a user setting that they can toggle if they don't want to receive unread notifications when someone closes a topic they have read and are watching/tracking it.
This commit is contained in:
parent
3f1566eeb1
commit
f71e9aad60
|
@ -167,6 +167,7 @@ export default class extends Controller {
|
|||
"tracked_category_ids",
|
||||
"watched_first_post_category_ids",
|
||||
"watched_precedence_over_muted",
|
||||
"topics_unread_when_closed",
|
||||
];
|
||||
|
||||
if (this.siteSettings.tagging_enabled) {
|
||||
|
|
|
@ -130,6 +130,7 @@ let userOptionFields = [
|
|||
"sidebar_link_to_filtered_list",
|
||||
"sidebar_show_count_of_new_items",
|
||||
"watched_precedence_over_muted",
|
||||
"topics_unread_when_closed",
|
||||
];
|
||||
|
||||
export function addSaveableUserOptionField(fieldName) {
|
||||
|
|
|
@ -49,6 +49,11 @@
|
|||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<PreferenceCheckbox
|
||||
@labelKey="user.topics_unread_when_closed"
|
||||
@checked={{this.model.user_option.topics_unread_when_closed}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -7,26 +7,33 @@ class PostTiming < ActiveRecord::Base
|
|||
validates_presence_of :post_number
|
||||
validates_presence_of :msecs
|
||||
|
||||
def self.pretend_read(topic_id, actual_read_post_number, pretend_read_post_number)
|
||||
def self.pretend_read(topic_id, actual_read_post_number, pretend_read_post_number, user_ids = nil)
|
||||
# This is done in SQL cause the logic is quite tricky and we want to do this in one db hit
|
||||
#
|
||||
DB.exec(
|
||||
"INSERT INTO post_timings(topic_id, user_id, post_number, msecs)
|
||||
user_ids_condition = user_ids.present? ? "AND user_id = ANY(ARRAY[:user_ids]::int[])" : ""
|
||||
sql_query = <<-SQL
|
||||
INSERT INTO post_timings(topic_id, user_id, post_number, msecs)
|
||||
SELECT :topic_id, user_id, :pretend_read_post_number, 1
|
||||
FROM post_timings pt
|
||||
WHERE topic_id = :topic_id AND
|
||||
post_number = :actual_read_post_number AND
|
||||
NOT EXISTS (
|
||||
post_number = :actual_read_post_number
|
||||
#{user_ids_condition}
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM post_timings pt1
|
||||
WHERE pt1.topic_id = pt.topic_id AND
|
||||
pt1.post_number = :pretend_read_post_number AND
|
||||
pt1.user_id = pt.user_id
|
||||
)
|
||||
",
|
||||
SQL
|
||||
|
||||
params = {
|
||||
pretend_read_post_number: pretend_read_post_number,
|
||||
topic_id: topic_id,
|
||||
actual_read_post_number: actual_read_post_number,
|
||||
)
|
||||
}
|
||||
params[:user_ids] = user_ids if user_ids.present?
|
||||
|
||||
DB.exec(sql_query, params)
|
||||
|
||||
TopicUser.ensure_consistency!(topic_id)
|
||||
end
|
||||
|
|
|
@ -292,6 +292,7 @@ end
|
|||
# sidebar_show_count_of_new_items :boolean default(FALSE), not null
|
||||
# watched_precedence_over_muted :boolean
|
||||
# chat_separate_sidebar_mode :integer default(0), not null
|
||||
# topics_unread_when_closed :boolean default(TRUE), not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
|
|
|
@ -39,7 +39,8 @@ class UserOptionSerializer < ApplicationSerializer
|
|||
:seen_popups,
|
||||
:sidebar_link_to_filtered_list,
|
||||
:sidebar_show_count_of_new_items,
|
||||
:watched_precedence_over_muted
|
||||
:watched_precedence_over_muted,
|
||||
:topics_unread_when_closed
|
||||
|
||||
def auto_track_topics_after_msecs
|
||||
object.auto_track_topics_after_msecs || SiteSetting.default_other_auto_track_topics_after_msecs
|
||||
|
|
|
@ -90,6 +90,21 @@ TopicStatusUpdater =
|
|||
# actually read the topic
|
||||
PostTiming.pretend_read(topic.id, old_highest_read, topic.highest_post_number)
|
||||
end
|
||||
|
||||
if status.closed? && status.enabled?
|
||||
sql_query = <<-SQL
|
||||
SELECT DISTINCT post_timings.user_id
|
||||
FROM post_timings
|
||||
JOIN user_options ON user_options.user_id = post_timings.user_id
|
||||
WHERE post_timings.topic_id = :topic_id
|
||||
AND user_options.topics_unread_when_closed = 'f'
|
||||
SQL
|
||||
user_ids = DB.query_single(sql_query, topic_id: topic.id)
|
||||
|
||||
if user_ids.present?
|
||||
PostTiming.pretend_read(topic.id, old_highest_read, topic.highest_post_number, user_ids)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def message_for(status)
|
||||
|
|
|
@ -52,6 +52,7 @@ class UserUpdater
|
|||
sidebar_link_to_filtered_list
|
||||
sidebar_show_count_of_new_items
|
||||
watched_precedence_over_muted
|
||||
topics_unread_when_closed
|
||||
]
|
||||
|
||||
NOTIFICATION_SCHEDULE_ATTRS = -> do
|
||||
|
|
|
@ -1774,6 +1774,7 @@ en:
|
|||
after_10_minutes: "after 10 minutes"
|
||||
|
||||
notification_level_when_replying: "When I post in a topic, set that topic to"
|
||||
topics_unread_when_closed: "Consider topics unread when they are closed"
|
||||
|
||||
invited:
|
||||
title: "Invites"
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddTopicsUnreadWhenClosedToUserOptions < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :user_options, :topics_unread_when_closed, :boolean, default: true, null: false
|
||||
end
|
||||
end
|
|
@ -794,6 +794,9 @@
|
|||
},
|
||||
"seen_popups": {
|
||||
"type": ["array", "null"]
|
||||
},
|
||||
"topics_unread_when_closed": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
@ -828,7 +831,8 @@
|
|||
"text_size_seq",
|
||||
"title_count_mode",
|
||||
"timezone",
|
||||
"skip_new_user_tips"
|
||||
"skip_new_user_tips",
|
||||
"topics_unread_when_closed"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
@ -214,11 +214,20 @@ module PageObjects
|
|||
find(".topic-notifications-button .select-kit-header").click
|
||||
end
|
||||
|
||||
def click_admin_menu_button
|
||||
find("#topic-footer-buttons .topic-admin-menu-button").click
|
||||
end
|
||||
|
||||
def watch_topic
|
||||
click_notifications_button
|
||||
find('li[data-name="watching"]').click
|
||||
end
|
||||
|
||||
def close_topic
|
||||
click_admin_menu_button
|
||||
find(".topic-admin-popup-menu ul.topic-admin-menu-topic li.topic-admin-close").click
|
||||
end
|
||||
|
||||
def has_read_post?(post)
|
||||
post_by_number(post).has_css?(".read-state.read", visible: :all, wait: 3)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
describe "Topics unread when closed", type: :system do
|
||||
fab!(:topics) { Fabricate.times(10, :post).map(&:topic) }
|
||||
let(:topic_list) { PageObjects::Components::TopicList.new }
|
||||
let(:topic_page) { PageObjects::Pages::Topic.new }
|
||||
|
||||
context "when closing a topic" do
|
||||
fab!(:admin)
|
||||
fab!(:user)
|
||||
|
||||
it "close notifications do not appear when disabled" do
|
||||
user.user_option.update!(topics_unread_when_closed: false)
|
||||
sign_in(user)
|
||||
topic = topics.third
|
||||
topic_page.visit_topic(topic)
|
||||
topic_page.watch_topic
|
||||
expect(topic_page).to have_read_post(1)
|
||||
|
||||
# Close the topic as an admin
|
||||
TopicStatusUpdater.new(topic, admin).update!("closed", true)
|
||||
|
||||
# Check that the user did not receive a new post notification badge
|
||||
visit("/latest")
|
||||
expect(topic_list).to have_no_unread_badge(topics.third)
|
||||
end
|
||||
|
||||
it "close notifications appear when enabled (the default)" do
|
||||
user.user_option.update!(topics_unread_when_closed: true)
|
||||
sign_in(user)
|
||||
topic = topics.third
|
||||
topic_page.visit_topic(topic)
|
||||
topic_page.watch_topic
|
||||
expect(topic_page).to have_read_post(1)
|
||||
|
||||
# Close the topic as an admin
|
||||
TopicStatusUpdater.new(topic, admin).update!("closed", true)
|
||||
|
||||
# Check that the user did receive a new post notification badge
|
||||
visit("/latest")
|
||||
expect(topic_list).to have_unread_badge(topics.third)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue