2018-02-07 01:37:23 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2021-04-28 09:29:54 +08:00
|
|
|
# this class is used to mirror unread and new status back to end users
|
|
|
|
# in JavaScript there is a mirror class that is kept in-sync using the mssage bus
|
2013-05-21 14:39:51 +08:00
|
|
|
# the allows end users to always know which topics have unread posts in them
|
2021-04-28 09:29:54 +08:00
|
|
|
# and which topics are new
|
|
|
|
|
2013-05-29 16:11:04 +08:00
|
|
|
class TopicTrackingState
|
2013-05-21 14:39:51 +08:00
|
|
|
|
2013-05-24 18:58:26 +08:00
|
|
|
include ActiveModel::SerializerSupport
|
|
|
|
|
2020-04-30 14:48:34 +08:00
|
|
|
UNREAD_MESSAGE_TYPE = "unread"
|
|
|
|
LATEST_MESSAGE_TYPE = "latest"
|
|
|
|
MUTED_MESSAGE_TYPE = "muted"
|
2020-12-10 13:49:05 +08:00
|
|
|
UNMUTED_MESSAGE_TYPE = "unmuted"
|
2013-05-21 14:39:51 +08:00
|
|
|
|
2014-02-27 04:37:42 +08:00
|
|
|
attr_accessor :user_id,
|
|
|
|
:topic_id,
|
|
|
|
:highest_post_number,
|
|
|
|
:last_read_post_number,
|
|
|
|
:created_at,
|
2014-07-17 03:39:39 +08:00
|
|
|
:category_id,
|
2021-04-28 09:29:54 +08:00
|
|
|
:notification_level
|
2013-05-23 13:21:07 +08:00
|
|
|
|
2013-05-29 16:11:04 +08:00
|
|
|
def self.publish_new(topic)
|
2018-03-05 16:18:23 +08:00
|
|
|
return unless topic.regular?
|
2013-05-29 16:11:04 +08:00
|
|
|
|
2021-04-28 09:29:54 +08:00
|
|
|
tags, tag_ids = nil
|
2020-06-12 14:20:07 +08:00
|
|
|
if SiteSetting.tagging_enabled
|
2021-04-28 09:29:54 +08:00
|
|
|
topic.tags.pluck(:id, :name).each do |id, name|
|
|
|
|
tags ||= []
|
|
|
|
tag_ids ||= []
|
|
|
|
|
|
|
|
tags << name
|
|
|
|
tag_ids << id
|
|
|
|
end
|
2020-06-12 14:20:07 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
payload = {
|
|
|
|
last_read_post_number: nil,
|
|
|
|
highest_post_number: 1,
|
|
|
|
created_at: topic.created_at,
|
|
|
|
topic_id: topic.id,
|
|
|
|
category_id: topic.category_id,
|
|
|
|
archetype: topic.archetype,
|
|
|
|
}
|
|
|
|
|
|
|
|
if tags
|
|
|
|
payload[:tags] = tags
|
|
|
|
payload[:topic_tag_ids] = tag_ids
|
|
|
|
end
|
|
|
|
|
2013-05-29 16:11:04 +08:00
|
|
|
message = {
|
|
|
|
topic_id: topic.id,
|
2021-04-28 09:29:54 +08:00
|
|
|
message_type: "new_topic",
|
2020-06-12 14:20:07 +08:00
|
|
|
payload: payload
|
2013-05-29 16:11:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
group_ids = topic.category && topic.category.secure_group_ids
|
|
|
|
|
2015-05-04 10:21:00 +08:00
|
|
|
MessageBus.publish("/new", message.as_json, group_ids: group_ids)
|
2013-05-29 16:11:04 +08:00
|
|
|
publish_read(topic.id, 1, topic.user_id)
|
|
|
|
end
|
|
|
|
|
2016-12-02 14:03:31 +08:00
|
|
|
def self.publish_latest(topic, staff_only = false)
|
2018-03-05 16:18:23 +08:00
|
|
|
return unless topic.regular?
|
2014-08-05 11:27:34 +08:00
|
|
|
|
|
|
|
message = {
|
|
|
|
topic_id: topic.id,
|
2018-03-05 16:18:23 +08:00
|
|
|
message_type: LATEST_MESSAGE_TYPE,
|
2014-08-05 11:27:34 +08:00
|
|
|
payload: {
|
|
|
|
bumped_at: topic.bumped_at,
|
2016-03-30 08:17:52 +08:00
|
|
|
category_id: topic.category_id,
|
2021-04-28 09:29:54 +08:00
|
|
|
archetype: topic.archetype,
|
|
|
|
topic_tag_ids: topic.tags.pluck(:id)
|
2014-08-05 11:27:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-02 14:03:31 +08:00
|
|
|
group_ids =
|
|
|
|
if staff_only
|
|
|
|
[Group::AUTO_GROUPS[:staff]]
|
|
|
|
else
|
|
|
|
topic.category && topic.category.secure_group_ids
|
|
|
|
end
|
2015-05-04 10:21:00 +08:00
|
|
|
MessageBus.publish("/latest", message.as_json, group_ids: group_ids)
|
2014-08-05 11:27:34 +08:00
|
|
|
end
|
|
|
|
|
2018-03-05 16:18:23 +08:00
|
|
|
def self.unread_channel_key(user_id)
|
|
|
|
"/unread/#{user_id}"
|
|
|
|
end
|
|
|
|
|
2020-05-01 06:33:57 +08:00
|
|
|
def self.publish_muted(topic)
|
|
|
|
user_ids = topic.topic_users
|
2020-04-23 12:57:35 +08:00
|
|
|
.where(notification_level: NotificationLevels.all[:muted])
|
|
|
|
.joins(:user)
|
|
|
|
.where("users.last_seen_at > ?", 7.days.ago)
|
|
|
|
.order("users.last_seen_at DESC")
|
|
|
|
.limit(100)
|
|
|
|
.pluck(:user_id)
|
|
|
|
return if user_ids.blank?
|
|
|
|
message = {
|
2020-05-01 06:33:57 +08:00
|
|
|
topic_id: topic.id,
|
2020-04-23 12:57:35 +08:00
|
|
|
message_type: MUTED_MESSAGE_TYPE,
|
|
|
|
}
|
|
|
|
MessageBus.publish("/latest", message.as_json, user_ids: user_ids)
|
|
|
|
end
|
|
|
|
|
2020-12-10 13:49:05 +08:00
|
|
|
def self.publish_unmuted(topic)
|
|
|
|
return if !SiteSetting.mute_all_categories_by_default
|
2020-12-16 06:30:21 +08:00
|
|
|
user_ids = User.watching_topic_when_mute_categories_by_default(topic)
|
2020-12-10 13:49:05 +08:00
|
|
|
.where("users.last_seen_at > ?", 7.days.ago)
|
|
|
|
.order("users.last_seen_at DESC")
|
|
|
|
.limit(100)
|
|
|
|
.pluck(:id)
|
|
|
|
return if user_ids.blank?
|
|
|
|
message = {
|
|
|
|
topic_id: topic.id,
|
|
|
|
message_type: UNMUTED_MESSAGE_TYPE,
|
|
|
|
}
|
|
|
|
MessageBus.publish("/latest", message.as_json, user_ids: user_ids)
|
|
|
|
end
|
|
|
|
|
2013-05-29 16:11:04 +08:00
|
|
|
def self.publish_unread(post)
|
2018-03-05 16:18:23 +08:00
|
|
|
return unless post.topic.regular?
|
2013-05-29 16:11:04 +08:00
|
|
|
# TODO at high scale we are going to have to defer this,
|
|
|
|
# perhaps cut down to users that are around in the last 7 days as well
|
2016-12-02 14:03:31 +08:00
|
|
|
|
|
|
|
group_ids =
|
|
|
|
if post.post_type == Post.types[:whisper]
|
|
|
|
[Group::AUTO_GROUPS[:staff]]
|
|
|
|
else
|
|
|
|
post.topic.category && post.topic.category.secure_group_ids
|
|
|
|
end
|
2013-05-29 16:11:04 +08:00
|
|
|
|
2020-06-12 14:20:07 +08:00
|
|
|
tags = nil
|
|
|
|
if include_tags_in_report?
|
2021-04-28 09:29:54 +08:00
|
|
|
tags = post.topic.tags.pluck(:name)
|
2020-06-12 14:20:07 +08:00
|
|
|
end
|
|
|
|
|
2013-05-29 16:11:04 +08:00
|
|
|
TopicUser
|
|
|
|
.tracking(post.topic_id)
|
2014-06-06 13:17:02 +08:00
|
|
|
.select([:user_id, :last_read_post_number, :notification_level])
|
2013-05-29 16:11:04 +08:00
|
|
|
.each do |tu|
|
|
|
|
|
2020-06-12 14:20:07 +08:00
|
|
|
payload = {
|
|
|
|
last_read_post_number: tu.last_read_post_number,
|
|
|
|
highest_post_number: post.post_number,
|
|
|
|
created_at: post.created_at,
|
|
|
|
category_id: post.topic.category_id,
|
|
|
|
notification_level: tu.notification_level,
|
2021-04-28 09:29:54 +08:00
|
|
|
archetype: post.topic.archetype
|
2020-06-12 14:20:07 +08:00
|
|
|
}
|
|
|
|
|
2021-04-28 09:29:54 +08:00
|
|
|
payload[:tags] = tags if tags
|
2020-06-12 14:20:07 +08:00
|
|
|
|
2013-05-29 16:11:04 +08:00
|
|
|
message = {
|
|
|
|
topic_id: post.topic_id,
|
2018-03-05 16:18:23 +08:00
|
|
|
message_type: UNREAD_MESSAGE_TYPE,
|
2020-06-12 14:20:07 +08:00
|
|
|
payload: payload
|
2013-05-29 16:11:04 +08:00
|
|
|
}
|
|
|
|
|
2018-03-05 16:18:23 +08:00
|
|
|
MessageBus.publish(self.unread_channel_key(tu.user_id), message.as_json, group_ids: group_ids)
|
2013-05-21 14:39:51 +08:00
|
|
|
end
|
2013-11-25 14:37:51 +08:00
|
|
|
|
2013-05-21 14:39:51 +08:00
|
|
|
end
|
|
|
|
|
2016-03-30 08:17:52 +08:00
|
|
|
def self.publish_recover(topic)
|
|
|
|
group_ids = topic.category && topic.category.secure_group_ids
|
|
|
|
|
|
|
|
message = {
|
|
|
|
topic_id: topic.id,
|
2021-04-28 09:29:54 +08:00
|
|
|
message_type: "recover"
|
2016-03-30 08:17:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
MessageBus.publish("/recover", message.as_json, group_ids: group_ids)
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.publish_delete(topic)
|
|
|
|
group_ids = topic.category && topic.category.secure_group_ids
|
|
|
|
|
|
|
|
message = {
|
|
|
|
topic_id: topic.id,
|
2021-04-28 09:29:54 +08:00
|
|
|
message_type: "delete"
|
2016-03-30 08:17:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
MessageBus.publish("/delete", message.as_json, group_ids: group_ids)
|
|
|
|
end
|
|
|
|
|
2020-11-10 12:40:48 +08:00
|
|
|
def self.publish_destroy(topic)
|
|
|
|
group_ids = topic.category && topic.category.secure_group_ids
|
|
|
|
|
|
|
|
message = {
|
|
|
|
topic_id: topic.id,
|
2021-04-28 09:29:54 +08:00
|
|
|
message_type: "destroy"
|
2020-11-10 12:40:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
MessageBus.publish("/destroy", message.as_json, group_ids: group_ids)
|
|
|
|
end
|
|
|
|
|
2014-02-27 04:37:42 +08:00
|
|
|
def self.publish_read(topic_id, last_read_post_number, user_id, notification_level = nil)
|
2019-08-29 00:07:56 +08:00
|
|
|
highest_post_number = DB.query_single("SELECT highest_post_number FROM topics WHERE id = ?", topic_id).first
|
2013-05-30 14:19:12 +08:00
|
|
|
|
2013-11-25 14:37:51 +08:00
|
|
|
message = {
|
|
|
|
topic_id: topic_id,
|
2021-04-28 09:29:54 +08:00
|
|
|
message_type: "read",
|
2013-11-25 14:37:51 +08:00
|
|
|
payload: {
|
|
|
|
last_read_post_number: last_read_post_number,
|
2019-08-29 00:07:56 +08:00
|
|
|
highest_post_number: highest_post_number,
|
2014-02-27 04:37:42 +08:00
|
|
|
topic_id: topic_id,
|
|
|
|
notification_level: notification_level
|
2013-05-30 14:19:12 +08:00
|
|
|
}
|
2013-11-25 14:37:51 +08:00
|
|
|
}
|
|
|
|
|
2018-03-05 16:18:23 +08:00
|
|
|
MessageBus.publish(self.unread_channel_key(user_id), message.as_json, user_ids: [user_id])
|
2013-05-21 14:39:51 +08:00
|
|
|
end
|
|
|
|
|
2021-02-15 05:50:33 +08:00
|
|
|
def self.publish_dismiss_new(user_id, topic_ids: [])
|
2019-11-25 03:17:31 +08:00
|
|
|
message = {
|
2021-04-28 09:29:54 +08:00
|
|
|
message_type: "dismiss_new",
|
2021-02-15 05:50:33 +08:00
|
|
|
payload: {
|
|
|
|
topic_ids: topic_ids
|
|
|
|
}
|
2019-11-25 03:17:31 +08:00
|
|
|
}
|
|
|
|
MessageBus.publish(self.unread_channel_key(user_id), message.as_json, user_ids: [user_id])
|
|
|
|
end
|
|
|
|
|
2013-05-23 13:21:07 +08:00
|
|
|
def self.treat_as_new_topic_clause
|
2014-03-04 05:11:59 +08:00
|
|
|
User.where("GREATEST(CASE
|
2016-02-18 13:57:22 +08:00
|
|
|
WHEN COALESCE(uo.new_topic_duration_minutes, :default_duration) = :always THEN u.created_at
|
|
|
|
WHEN COALESCE(uo.new_topic_duration_minutes, :default_duration) = :last_visit THEN COALESCE(u.previous_visit_at,u.created_at)
|
|
|
|
ELSE (:now::timestamp - INTERVAL '1 MINUTE' * COALESCE(uo.new_topic_duration_minutes, :default_duration))
|
2021-02-15 05:50:33 +08:00
|
|
|
END, u.created_at, :min_date)",
|
2013-05-23 13:21:07 +08:00
|
|
|
now: DateTime.now,
|
|
|
|
last_visit: User::NewTopicDuration::LAST_VISIT,
|
|
|
|
always: User::NewTopicDuration::ALWAYS,
|
2015-09-07 09:57:50 +08:00
|
|
|
default_duration: SiteSetting.default_other_new_topic_duration_minutes,
|
|
|
|
min_date: Time.at(SiteSetting.min_new_topics_time).to_datetime
|
2020-12-22 07:38:59 +08:00
|
|
|
).where_clause.ast.to_sql
|
2013-05-21 14:39:51 +08:00
|
|
|
end
|
|
|
|
|
2020-05-29 10:57:46 +08:00
|
|
|
def self.include_tags_in_report?
|
2021-03-11 10:13:15 +08:00
|
|
|
SiteSetting.tagging_enabled && @include_tags_in_report
|
2020-05-29 10:57:46 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def self.include_tags_in_report=(v)
|
|
|
|
@include_tags_in_report = v
|
|
|
|
end
|
|
|
|
|
2016-12-02 14:03:31 +08:00
|
|
|
def self.report(user, topic_id = nil)
|
2021-04-28 09:29:54 +08:00
|
|
|
# Sam: this is a hairy report, in particular I need custom joins and fancy conditions
|
|
|
|
# Dropping to sql_builder so I can make sense of it.
|
|
|
|
#
|
|
|
|
# Keep in mind, we need to be able to filter on a GROUP of users, and zero in on topic
|
|
|
|
# all our existing scope work does not do this
|
|
|
|
#
|
|
|
|
# This code needs to be VERY efficient as it is triggered via the message bus and may steal
|
|
|
|
# cycles from usual requests
|
2020-05-13 11:09:40 +08:00
|
|
|
tag_ids = muted_tag_ids(user)
|
|
|
|
|
2021-04-28 09:29:54 +08:00
|
|
|
sql = +report_raw_sql(
|
2019-04-05 12:25:19 +08:00
|
|
|
topic_id: topic_id,
|
|
|
|
skip_unread: true,
|
|
|
|
skip_order: true,
|
|
|
|
staff: user.staff?,
|
2019-11-14 13:11:34 +08:00
|
|
|
admin: user.admin?,
|
2019-12-10 06:50:05 +08:00
|
|
|
user: user,
|
2020-05-13 11:09:40 +08:00
|
|
|
muted_tag_ids: tag_ids
|
2019-04-05 12:25:19 +08:00
|
|
|
)
|
|
|
|
|
2015-09-29 09:55:09 +08:00
|
|
|
sql << "\nUNION ALL\n\n"
|
2019-04-05 12:25:19 +08:00
|
|
|
|
|
|
|
sql << report_raw_sql(
|
|
|
|
topic_id: topic_id,
|
|
|
|
skip_new: true,
|
|
|
|
skip_order: true,
|
|
|
|
staff: user.staff?,
|
|
|
|
filter_old_unread: true,
|
2019-11-14 13:11:34 +08:00
|
|
|
admin: user.admin?,
|
2019-12-10 06:50:05 +08:00
|
|
|
user: user,
|
2020-05-13 11:09:40 +08:00
|
|
|
muted_tag_ids: tag_ids
|
2019-04-05 12:25:19 +08:00
|
|
|
)
|
2015-09-07 09:57:50 +08:00
|
|
|
|
2020-05-29 10:57:46 +08:00
|
|
|
if SiteSetting.tagging_enabled && TopicTrackingState.include_tags_in_report?
|
2021-04-28 09:29:54 +08:00
|
|
|
sql = <<~SQL
|
|
|
|
WITH X AS (#{sql})
|
2020-05-29 10:57:46 +08:00
|
|
|
SELECT *, (
|
|
|
|
SELECT ARRAY_AGG(name) from topic_tags
|
|
|
|
JOIN tags on tags.id = topic_tags.tag_id
|
2021-04-28 09:29:54 +08:00
|
|
|
WHERE topic_id = X.topic_id
|
2020-05-29 10:57:46 +08:00
|
|
|
) tags
|
2021-04-28 09:29:54 +08:00
|
|
|
FROM X
|
2020-05-29 10:57:46 +08:00
|
|
|
SQL
|
|
|
|
end
|
|
|
|
|
2021-04-28 09:29:54 +08:00
|
|
|
DB.query(
|
|
|
|
sql,
|
|
|
|
user_id: user.id,
|
|
|
|
topic_id: topic_id,
|
|
|
|
min_new_topic_date: Time.at(SiteSetting.min_new_topics_time).to_datetime
|
|
|
|
)
|
2015-09-07 09:57:50 +08:00
|
|
|
end
|
|
|
|
|
2019-12-10 06:50:05 +08:00
|
|
|
def self.muted_tag_ids(user)
|
|
|
|
TagUser.lookup(user, :muted).pluck(:tag_id)
|
|
|
|
end
|
|
|
|
|
2021-04-28 09:29:54 +08:00
|
|
|
def self.report_raw_sql(opts = nil)
|
|
|
|
opts ||= {}
|
|
|
|
|
2015-09-07 09:57:50 +08:00
|
|
|
unread =
|
2021-04-28 09:29:54 +08:00
|
|
|
if opts[:skip_unread]
|
2015-09-07 09:57:50 +08:00
|
|
|
"1=0"
|
|
|
|
else
|
2021-04-28 09:29:54 +08:00
|
|
|
TopicQuery
|
|
|
|
.unread_filter(Topic, -999, staff: opts && opts[:staff])
|
|
|
|
.where_clause.ast.to_sql
|
|
|
|
.gsub("-999", ":user_id")
|
2015-09-07 09:57:50 +08:00
|
|
|
end
|
|
|
|
|
2021-04-28 09:29:54 +08:00
|
|
|
filter_old_unread =
|
|
|
|
if opts[:filter_old_unread]
|
2019-04-05 09:44:36 +08:00
|
|
|
" topics.updated_at >= us.first_unread_at AND "
|
|
|
|
else
|
|
|
|
""
|
|
|
|
end
|
|
|
|
|
2015-09-07 09:57:50 +08:00
|
|
|
new =
|
2021-04-28 09:29:54 +08:00
|
|
|
if opts[:skip_new]
|
2015-09-07 09:57:50 +08:00
|
|
|
"1=0"
|
|
|
|
else
|
2021-04-28 09:29:54 +08:00
|
|
|
TopicQuery.new_filter(Topic, "xxx").where_clause.ast.to_sql.gsub!("'xxx'", treat_as_new_topic_clause) +
|
|
|
|
" AND topics.created_at > :min_new_topic_date" +
|
|
|
|
" AND dismissed_topic_users.id IS NULL"
|
2015-09-07 09:57:50 +08:00
|
|
|
end
|
|
|
|
|
2021-04-28 09:29:54 +08:00
|
|
|
select = (opts[:select]) || "
|
|
|
|
u.id AS user_id,
|
|
|
|
topics.id AS topic_id,
|
2014-02-27 04:37:42 +08:00
|
|
|
topics.created_at,
|
2021-04-28 09:29:54 +08:00
|
|
|
#{opts[:staff] ? "highest_staff_post_number highest_post_number" : "highest_post_number"},
|
2014-02-27 04:37:42 +08:00
|
|
|
last_read_post_number,
|
2021-04-28 09:29:54 +08:00
|
|
|
c.id AS category_id,
|
|
|
|
tu.notification_level"
|
2015-09-07 09:57:50 +08:00
|
|
|
|
2019-04-05 12:25:19 +08:00
|
|
|
category_filter =
|
2021-04-28 09:29:54 +08:00
|
|
|
if opts[:admin]
|
2019-04-05 12:25:19 +08:00
|
|
|
""
|
|
|
|
else
|
2021-04-28 09:29:54 +08:00
|
|
|
append = "OR u.admin" if !opts.key?(:admin)
|
2019-04-05 12:25:19 +08:00
|
|
|
<<~SQL
|
|
|
|
(
|
2019-11-14 13:11:34 +08:00
|
|
|
NOT c.read_restricted #{append} OR c.id IN (
|
2019-04-05 12:25:19 +08:00
|
|
|
SELECT c2.id FROM categories c2
|
|
|
|
JOIN category_groups cg ON cg.category_id = c2.id
|
|
|
|
JOIN group_users gu ON gu.user_id = :user_id AND cg.group_id = gu.group_id
|
|
|
|
WHERE c2.read_restricted )
|
|
|
|
) AND
|
|
|
|
SQL
|
|
|
|
end
|
|
|
|
|
|
|
|
visibility_filter =
|
2021-04-28 09:29:54 +08:00
|
|
|
if opts[:staff]
|
2019-04-05 12:25:19 +08:00
|
|
|
""
|
|
|
|
else
|
2021-04-28 09:29:54 +08:00
|
|
|
append = "OR u.admin OR u.moderator" if !opts.key?(:staff)
|
2019-04-05 12:25:19 +08:00
|
|
|
"(topics.visible #{append}) AND"
|
|
|
|
end
|
|
|
|
|
2020-05-29 10:59:34 +08:00
|
|
|
tags_filter = ""
|
|
|
|
|
2021-04-28 09:29:54 +08:00
|
|
|
if (muted_tag_ids = opts[:muted_tag_ids]).present? && ['always', 'only_muted'].include?(SiteSetting.remove_muted_tags_from_latest)
|
2020-05-29 10:59:34 +08:00
|
|
|
existing_tags_sql = "(select array_agg(tag_id) from topic_tags where topic_tags.topic_id = topics.id)"
|
2021-04-28 09:29:54 +08:00
|
|
|
muted_tags_array_sql = "ARRAY[#{opts[:muted_tag_ids].join(',')}]"
|
2020-05-29 10:59:34 +08:00
|
|
|
|
|
|
|
if SiteSetting.remove_muted_tags_from_latest == 'always'
|
|
|
|
tags_filter = <<~SQL
|
|
|
|
NOT (
|
|
|
|
COALESCE(#{existing_tags_sql}, ARRAY[]::int[]) && #{muted_tags_array_sql}
|
|
|
|
) AND
|
2019-12-10 06:50:05 +08:00
|
|
|
SQL
|
2020-05-29 10:59:34 +08:00
|
|
|
else # only muted
|
|
|
|
tags_filter = <<~SQL
|
|
|
|
NOT (
|
|
|
|
COALESCE(#{existing_tags_sql}, ARRAY[-999]) <@ #{muted_tags_array_sql}
|
|
|
|
) AND
|
2019-12-10 06:50:05 +08:00
|
|
|
SQL
|
|
|
|
end
|
2020-05-29 10:59:34 +08:00
|
|
|
end
|
2019-12-10 06:50:05 +08:00
|
|
|
|
2019-04-05 12:25:19 +08:00
|
|
|
sql = +<<~SQL
|
2021-04-28 09:29:54 +08:00
|
|
|
SELECT #{select}
|
|
|
|
FROM topics
|
|
|
|
JOIN users u on u.id = :user_id
|
|
|
|
JOIN user_stats AS us ON us.user_id = u.id
|
|
|
|
JOIN user_options AS uo ON uo.user_id = u.id
|
|
|
|
JOIN categories c ON c.id = topics.category_id
|
|
|
|
LEFT JOIN topic_users tu ON tu.topic_id = topics.id AND tu.user_id = u.id
|
|
|
|
LEFT JOIN category_users ON category_users.category_id = topics.category_id AND category_users.user_id = #{opts[:user].id}
|
|
|
|
LEFT JOIN dismissed_topic_users ON dismissed_topic_users.topic_id = topics.id AND dismissed_topic_users.user_id = #{opts[:user].id}
|
|
|
|
WHERE u.id = :user_id AND
|
|
|
|
#{filter_old_unread}
|
|
|
|
topics.archetype <> 'private_message' AND
|
|
|
|
((#{unread}) OR (#{new})) AND
|
|
|
|
#{visibility_filter}
|
|
|
|
#{tags_filter}
|
|
|
|
topics.deleted_at IS NULL AND
|
|
|
|
#{category_filter}
|
|
|
|
NOT (
|
|
|
|
last_read_post_number IS NULL AND
|
|
|
|
COALESCE(category_users.notification_level, #{CategoryUser.default_notification_level}) = #{CategoryUser.notification_levels[:muted]}
|
|
|
|
)
|
|
|
|
SQL
|
|
|
|
|
|
|
|
if opts[:topic_id]
|
2015-07-21 19:53:54 +08:00
|
|
|
sql << " AND topics.id = :topic_id"
|
2013-05-23 13:21:07 +08:00
|
|
|
end
|
2014-09-10 20:19:24 +08:00
|
|
|
|
2021-04-28 09:29:54 +08:00
|
|
|
unless opts[:skip_order]
|
2015-09-29 09:55:09 +08:00
|
|
|
sql << " ORDER BY topics.bumped_at DESC"
|
|
|
|
end
|
|
|
|
|
|
|
|
sql
|
2013-05-21 14:39:51 +08:00
|
|
|
end
|
|
|
|
|
2018-03-15 22:48:40 +08:00
|
|
|
def self.publish_private_message(topic, archive_user_id: nil,
|
2018-03-13 08:35:15 +08:00
|
|
|
post: nil,
|
|
|
|
group_archive: false)
|
|
|
|
|
2018-03-06 14:38:43 +08:00
|
|
|
return unless topic.private_message?
|
|
|
|
channels = {}
|
|
|
|
|
|
|
|
allowed_user_ids = topic.allowed_users.pluck(:id)
|
|
|
|
|
2018-03-07 11:39:23 +08:00
|
|
|
if post && allowed_user_ids.include?(post.user_id)
|
2018-03-06 14:38:43 +08:00
|
|
|
channels["/private-messages/sent"] = [post.user_id]
|
2018-03-15 16:01:40 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
if archive_user_id
|
2018-03-13 08:35:15 +08:00
|
|
|
user_ids = [archive_user_id]
|
2018-03-07 11:39:23 +08:00
|
|
|
|
|
|
|
[
|
|
|
|
"/private-messages/archive",
|
|
|
|
"/private-messages/inbox",
|
|
|
|
"/private-messages/sent",
|
|
|
|
].each do |channel|
|
|
|
|
channels[channel] = user_ids
|
|
|
|
end
|
2018-03-06 14:38:43 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
if channels.except("/private-messages/sent").blank?
|
|
|
|
channels["/private-messages/inbox"] = allowed_user_ids
|
|
|
|
end
|
|
|
|
|
2018-03-15 16:01:40 +08:00
|
|
|
topic.allowed_groups.each do |group|
|
|
|
|
group_user_ids = group.users.pluck(:id)
|
|
|
|
next if group_user_ids.blank?
|
|
|
|
group_channels = []
|
|
|
|
group_channels << "/private-messages/group/#{group.name.downcase}"
|
|
|
|
group_channels << "#{group_channels.first}/archive" if group_archive
|
|
|
|
group_channels.each { |channel| channels[channel] = group_user_ids }
|
|
|
|
end
|
|
|
|
|
2018-03-06 14:38:43 +08:00
|
|
|
message = {
|
|
|
|
topic_id: topic.id
|
|
|
|
}
|
|
|
|
|
2018-09-04 10:16:21 +08:00
|
|
|
channels.each do |channel, ids|
|
2020-09-15 14:25:10 +08:00
|
|
|
if ids.present?
|
|
|
|
MessageBus.publish(
|
|
|
|
channel,
|
|
|
|
message.as_json,
|
|
|
|
user_ids: ids
|
|
|
|
)
|
|
|
|
end
|
2018-03-06 14:38:43 +08:00
|
|
|
end
|
|
|
|
end
|
2019-08-27 20:09:00 +08:00
|
|
|
|
|
|
|
def self.publish_read_indicator_on_write(topic_id, last_read_post_number, user_id)
|
|
|
|
topic = Topic.includes(:allowed_groups).select(:highest_post_number, :archetype, :id).find_by(id: topic_id)
|
|
|
|
|
2019-08-30 00:38:23 +08:00
|
|
|
if topic&.private_message?
|
2019-08-27 20:09:00 +08:00
|
|
|
groups = read_allowed_groups_of(topic)
|
2019-08-29 23:03:43 +08:00
|
|
|
update_topic_list_read_indicator(topic, groups, topic.highest_post_number, user_id, true)
|
2019-08-27 20:09:00 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.publish_read_indicator_on_read(topic_id, last_read_post_number, user_id)
|
|
|
|
topic = Topic.includes(:allowed_groups).select(:highest_post_number, :archetype, :id).find_by(id: topic_id)
|
|
|
|
|
2019-08-30 00:38:23 +08:00
|
|
|
if topic&.private_message?
|
2019-08-27 20:09:00 +08:00
|
|
|
groups = read_allowed_groups_of(topic)
|
|
|
|
post = Post.find_by(topic_id: topic.id, post_number: last_read_post_number)
|
2019-09-09 09:29:15 +08:00
|
|
|
trigger_post_read_count_update(post, groups, last_read_post_number, user_id)
|
2019-08-29 23:03:43 +08:00
|
|
|
update_topic_list_read_indicator(topic, groups, last_read_post_number, user_id, false)
|
2019-08-27 20:09:00 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.read_allowed_groups_of(topic)
|
|
|
|
topic.allowed_groups
|
|
|
|
.joins(:group_users)
|
|
|
|
.where(publish_read_state: true)
|
|
|
|
.select('ARRAY_AGG(group_users.user_id) AS members', :name, :id)
|
|
|
|
.group('groups.id')
|
|
|
|
end
|
|
|
|
|
2019-08-29 23:03:43 +08:00
|
|
|
def self.update_topic_list_read_indicator(topic, groups, last_read_post_number, user_id, write_event)
|
2019-08-27 20:09:00 +08:00
|
|
|
return unless last_read_post_number == topic.highest_post_number
|
2019-08-29 23:03:43 +08:00
|
|
|
message = { topic_id: topic.id, show_indicator: write_event }.as_json
|
2019-08-27 20:09:00 +08:00
|
|
|
groups_to_update = []
|
|
|
|
|
|
|
|
groups.each do |group|
|
|
|
|
member = group.members.include?(user_id)
|
|
|
|
|
2019-08-29 23:03:43 +08:00
|
|
|
member_writing = (write_event && member)
|
|
|
|
non_member_reading = (!write_event && !member)
|
2019-08-27 20:09:00 +08:00
|
|
|
next if non_member_reading || member_writing
|
|
|
|
|
|
|
|
groups_to_update << group
|
|
|
|
end
|
|
|
|
|
|
|
|
return if groups_to_update.empty?
|
2019-08-29 23:03:43 +08:00
|
|
|
MessageBus.publish("/private-messages/unread-indicator/#{topic.id}", message, user_ids: groups_to_update.flat_map(&:members))
|
2019-08-27 20:09:00 +08:00
|
|
|
end
|
|
|
|
|
2019-09-09 09:29:15 +08:00
|
|
|
def self.trigger_post_read_count_update(post, groups, last_read_post_number, user_id)
|
2019-10-02 08:57:34 +08:00
|
|
|
return if !post
|
2019-08-27 20:09:00 +08:00
|
|
|
return if groups.empty?
|
2019-09-09 09:29:15 +08:00
|
|
|
opts = { readers_count: post.readers_count, reader_id: user_id }
|
|
|
|
post.publish_change_to_clients!(:read, opts)
|
2019-08-27 20:09:00 +08:00
|
|
|
end
|
2013-05-21 14:39:51 +08:00
|
|
|
end
|