mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
Initial release of Discourse
This commit is contained in:
197
app/models/topic_user.rb
Normal file
197
app/models/topic_user.rb
Normal file
@@ -0,0 +1,197 @@
|
||||
class TopicUser < ActiveRecord::Base
|
||||
|
||||
belongs_to :user
|
||||
belongs_to :topic
|
||||
|
||||
module NotificationLevel
|
||||
WATCHING = 3
|
||||
TRACKING = 2
|
||||
REGULAR = 1
|
||||
MUTED = 0
|
||||
end
|
||||
|
||||
module NotificationReasons
|
||||
CREATED_TOPIC = 1
|
||||
USER_CHANGED = 2
|
||||
USER_INTERACTED = 3
|
||||
CREATED_POST = 4
|
||||
end
|
||||
|
||||
def self.auto_track(user_id, topic_id, reason)
|
||||
if exec_sql("select 1 from topic_users where user_id = ? and topic_id = ? and notifications_reason_id is null", user_id, topic_id).count == 1
|
||||
self.change(user_id, topic_id,
|
||||
notification_level: NotificationLevel::TRACKING,
|
||||
notifications_reason_id: reason
|
||||
)
|
||||
|
||||
MessageBus.publish("/topic/#{topic_id}", {
|
||||
notification_level_change: NotificationLevel::TRACKING,
|
||||
notifications_reason_id: reason
|
||||
}, user_ids: [user_id])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Find the information specific to a user in a forum topic
|
||||
def self.lookup_for(user, topics)
|
||||
|
||||
# If the user isn't logged in, there's no last read posts
|
||||
return {} if user.blank?
|
||||
return {} if topics.blank?
|
||||
|
||||
topic_ids = topics.map {|ft| ft.id}
|
||||
create_lookup(TopicUser.where(topic_id: topic_ids, user_id: user.id))
|
||||
end
|
||||
|
||||
def self.create_lookup(topic_users)
|
||||
topic_users = topic_users.to_a
|
||||
|
||||
result = {}
|
||||
return result if topic_users.blank?
|
||||
|
||||
topic_users.each do |ftu|
|
||||
result[ftu.topic_id] = ftu
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def self.get(topic,user)
|
||||
if Topic === topic
|
||||
topic = topic.id
|
||||
end
|
||||
if User === user
|
||||
user = user.id
|
||||
end
|
||||
|
||||
TopicUser.where('topic_id = ? and user_id = ?', topic, user).first
|
||||
end
|
||||
|
||||
# Change attributes for a user (creates a record when none is present). First it tries an update
|
||||
# since there's more likely to be an existing record than not. If the update returns 0 rows affected
|
||||
# it then creates the row instead.
|
||||
def self.change(user_id, topic_id, attrs)
|
||||
|
||||
# Sometimes people pass objs instead of the ids. We can handle that.
|
||||
topic_id = topic_id.id if topic_id.is_a?(Topic)
|
||||
user_id = user_id.id if user_id.is_a?(User)
|
||||
|
||||
TopicUser.transaction do
|
||||
attrs = attrs.dup
|
||||
attrs[:starred_at] = DateTime.now if attrs[:starred_at].nil? && attrs[:starred]
|
||||
|
||||
if attrs[:notification_level]
|
||||
attrs[:notifications_changed_at] ||= DateTime.now
|
||||
attrs[:notifications_reason_id] ||= TopicUser::NotificationReasons::USER_CHANGED
|
||||
end
|
||||
attrs_array = attrs.to_a
|
||||
|
||||
attrs_sql = attrs_array.map {|t| "#{t[0]} = ?"}.join(", ")
|
||||
vals = attrs_array.map {|t| t[1]}
|
||||
rows = TopicUser.update_all([attrs_sql, *vals], ["topic_id = ? and user_id = ?", topic_id.to_i, user_id])
|
||||
|
||||
if rows == 0
|
||||
now = DateTime.now
|
||||
auto_track_after = self.exec_sql("select auto_track_topics_after_msecs from users where id = ?", user_id).values[0][0]
|
||||
auto_track_after ||= SiteSetting.auto_track_topics_after
|
||||
auto_track_after = auto_track_after.to_i
|
||||
|
||||
if auto_track_after >= 0 && auto_track_after <= (attrs[:total_msecs_viewed] || 0)
|
||||
attrs[:notification_level] ||= TopicUser::NotificationLevel::TRACKING
|
||||
end
|
||||
|
||||
TopicUser.create(attrs.merge!(user_id: user_id, topic_id: topic_id.to_i, first_visited_at: now ,last_visited_at: now))
|
||||
end
|
||||
|
||||
end
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
# In case of a race condition to insert, do nothing
|
||||
end
|
||||
|
||||
def self.track_visit!(topic,user)
|
||||
now = DateTime.now
|
||||
rows = exec_sql_row_count(
|
||||
"update topic_users set last_visited_at=? where topic_id=? and user_id=?",
|
||||
now, topic.id, user.id
|
||||
)
|
||||
|
||||
if rows == 0
|
||||
exec_sql('insert into topic_users(topic_id, user_id, last_visited_at, first_visited_at)
|
||||
values(?,?,?,?)',
|
||||
topic.id, user.id, now, now)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Update the last read and the last seen post count, but only if it doesn't exist.
|
||||
# This would be a lot easier if psql supported some kind of upsert
|
||||
def self.update_last_read(user, topic_id, post_number, msecs)
|
||||
return if post_number.blank?
|
||||
msecs = 0 if msecs.to_i < 0
|
||||
|
||||
args = {
|
||||
user_id: user.id,
|
||||
topic_id: topic_id,
|
||||
post_number: post_number,
|
||||
now: DateTime.now,
|
||||
msecs: msecs,
|
||||
tracking: TopicUser::NotificationLevel::TRACKING,
|
||||
threshold: SiteSetting.auto_track_topics_after
|
||||
}
|
||||
|
||||
rows = exec_sql("UPDATE topic_users
|
||||
SET
|
||||
last_read_post_number = greatest(:post_number, tu.last_read_post_number),
|
||||
seen_post_count = t.highest_post_number,
|
||||
total_msecs_viewed = tu.total_msecs_viewed + :msecs,
|
||||
notification_level =
|
||||
case when tu.notifications_reason_id is null and (tu.total_msecs_viewed + :msecs) >
|
||||
coalesce(u.auto_track_topics_after_msecs,:threshold) and
|
||||
coalesce(u.auto_track_topics_after_msecs, :threshold) >= 0 then
|
||||
:tracking
|
||||
else
|
||||
tu.notification_level
|
||||
end
|
||||
FROM topic_users tu
|
||||
join topics t on t.id = tu.topic_id
|
||||
join users u on u.id = :user_id
|
||||
WHERE
|
||||
tu.topic_id = topic_users.topic_id AND
|
||||
tu.user_id = topic_users.user_id AND
|
||||
tu.topic_id = :topic_id AND
|
||||
tu.user_id = :user_id
|
||||
RETURNING
|
||||
topic_users.notification_level, tu.notification_level old_level
|
||||
",
|
||||
args).values
|
||||
|
||||
if rows.length == 1
|
||||
before = rows[0][1].to_i
|
||||
after = rows[0][0].to_i
|
||||
|
||||
if before != after
|
||||
MessageBus.publish("/topic/#{topic_id}", {notification_level_change: after}, user_ids: [user.id])
|
||||
end
|
||||
end
|
||||
|
||||
if rows.length == 0
|
||||
|
||||
self
|
||||
|
||||
args[:tracking] = TopicUser::NotificationLevel::TRACKING
|
||||
args[:regular] = TopicUser::NotificationLevel::REGULAR
|
||||
args[:site_setting] = SiteSetting.auto_track_topics_after
|
||||
exec_sql("INSERT INTO topic_users (user_id, topic_id, last_read_post_number, seen_post_count, last_visited_at, first_visited_at, notification_level)
|
||||
SELECT :user_id, :topic_id, :post_number, ft.highest_post_number, :now, :now,
|
||||
case when coalesce(u.auto_track_topics_after_msecs, :site_setting) = 0 then :tracking else :regular end
|
||||
FROM topics AS ft
|
||||
JOIN users u on u.id = :user_id
|
||||
WHERE ft.id = :topic_id
|
||||
AND NOT EXISTS(SELECT 1
|
||||
FROM topic_users AS ftu
|
||||
WHERE ftu.user_id = :user_id and ftu.topic_id = :topic_id)",
|
||||
args)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user