FEATURE: live reply indicators at the bottom of topic

This commit is contained in:
Régis Hanol
2017-12-06 21:58:59 +01:00
parent ea50f823cb
commit ae0acfb1df
9 changed files with 133 additions and 75 deletions

View File

@ -29,44 +29,31 @@ after_initialize do
end
def self.add(type, id, user_id)
redis_key = get_redis_key(type, id)
response = $redis.hset(redis_key, user_id, Time.zone.now)
response # Will be true if a new key
# return true if a key was added
$redis.hset(get_redis_key(type, id), user_id, Time.zone.now)
end
def self.remove(type, id, user_id)
redis_key = get_redis_key(type, id)
response = $redis.hdel(redis_key, user_id)
response > 0 # Return true if key was actually deleted
# return true if a key was deleted
$redis.hdel(get_redis_key(type, id), user_id) > 0
end
def self.get_users(type, id)
redis_key = get_redis_key(type, id)
user_ids = $redis.hkeys(redis_key).map(&:to_i)
user_ids = $redis.hkeys(get_redis_key(type, id)).map(&:to_i)
# TODO: limit the # of users returned
User.where(id: user_ids)
end
def self.publish(type, id)
topic =
if type == 'post'
Post.find_by(id: id).topic
else
Topic.find_by(id: id)
end
users = get_users(type, id)
serialized_users = users.map { |u| BasicUserSerializer.new(u, root: false) }
message = {
users: serialized_users
}
message = { users: serialized_users }
messagebus_channel = get_messagebus_channel(type, id)
topic = type == 'post' ? Post.find_by(id: id).topic : Topic.find_by(id: id)
if topic.archetype == Archetype.private_message
user_ids = User.where('admin or moderator').pluck(:id)
user_ids += topic.allowed_users.pluck(:id)
user_ids = User.where('admin OR moderator').pluck(:id) + topic.allowed_users.pluck(:id)
MessageBus.publish(messagebus_channel, message.as_json, user_ids: user_ids)
else
MessageBus.publish(messagebus_channel, message.as_json, group_ids: topic.secure_group_ids)
@ -76,19 +63,17 @@ after_initialize do
end
def self.cleanup(type, id)
hash = $redis.hgetall(get_redis_key(type, id))
original_hash_size = hash.length
any_changes = false
has_changed = false
# Delete entries older than 20 seconds
hash = $redis.hgetall(get_redis_key(type, id))
hash.each do |user_id, time|
if Time.zone.now - Time.parse(time) >= 20
any_changes ||= remove(type, id, user_id)
has_changed |= remove(type, id, user_id)
end
end
any_changes
has_changed
end
end
@ -99,6 +84,8 @@ after_initialize do
requires_plugin PLUGIN_NAME
before_action :ensure_logged_in
ACTIONS = %w{edit reply}.each(&:freeze)
def publish
data = params.permit(
:response_needed,
@ -108,60 +95,38 @@ after_initialize do
payload = {}
if data[:previous] && data[:previous][:action].in?(['edit', 'reply'])
if data[:previous] && data[:previous][:action].in?(ACTIONS)
type = data[:previous][:post_id] ? 'post' : 'topic'
id = data[:previous][:post_id] ? data[:previous][:post_id] : data[:previous][:topic_id]
topic =
if type == 'post'
Post.find_by(id: id)&.topic
else
Topic.find_by(id: id)
end
topic = type == 'post' ? Post.find_by(id: id)&.topic : Topic.find_by(id: id)
if topic
guardian.ensure_can_see!(topic)
removed = Presence::PresenceManager.remove(type, id, current_user.id)
any_removed = Presence::PresenceManager.cleanup(type, id)
any_changes = removed || any_removed
users = Presence::PresenceManager.publish(type, id) if any_changes
cleaned = Presence::PresenceManager.cleanup(type, id)
users = Presence::PresenceManager.publish(type, id) if removed || cleaned
end
end
if data[:current] && data[:current][:action].in?(['edit', 'reply'])
if data[:current] && data[:current][:action].in?(ACTIONS)
type = data[:current][:post_id] ? 'post' : 'topic'
id = data[:current][:post_id] ? data[:current][:post_id] : data[:current][:topic_id]
topic =
if type == 'post'
Post.find_by(id: id)&.topic
else
Topic.find_by(id: id)
end
topic = type == 'post' ? Post.find_by(id: id)&.topic : Topic.find_by(id: id)
if topic
guardian.ensure_can_see!(topic)
added = Presence::PresenceManager.add(type, id, current_user.id)
any_removed = Presence::PresenceManager.cleanup(type, id)
any_changes = added || any_removed
users = Presence::PresenceManager.publish(type, id) if any_changes
added = Presence::PresenceManager.add(type, id, current_user.id)
cleaned = Presence::PresenceManager.cleanup(type, id)
users = Presence::PresenceManager.publish(type, id) if added || cleaned
if data[:response_needed]
users ||= Presence::PresenceManager.get_users(type, id)
serialized_users = users.map { |u| BasicUserSerializer.new(u, root: false) }
messagebus_channel = Presence::PresenceManager.get_messagebus_channel(type, id)
payload = {
messagebus_channel: messagebus_channel,
messagebus_id: MessageBus.last_id(messagebus_channel),
users: serialized_users
}
users ||= Presence::PresenceManager.get_users(type, id)
payload = json_payload(messagebus_channel, users)
end
end
end
@ -169,10 +134,30 @@ after_initialize do
render json: payload
end
def ping
topic_id = params.require(:topic_id)
Presence::PresenceManager.cleanup("topic", topic_id)
messagebus_channel = Presence::PresenceManager.get_messagebus_channel("topic", topic_id)
users = Presence::PresenceManager.get_users("topic", topic_id)
render json: json_payload(messagebus_channel, users)
end
def json_payload(channel, users)
{
messagebus_channel: channel,
messagebus_id: MessageBus.last_id(channel),
users: users.map { |u| BasicUserSerializer.new(u, root: false) }
}
end
end
Presence::Engine.routes.draw do
post '/publish' => 'presences#publish'
get '/ping/:topic_id' => 'presences#ping'
end
Discourse::Application.routes.append do