mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 06:14:12 +08:00
DEV: Update discourse-presence plugin to use new PresenceChannel system (#14519)
This removes all custom controllers and redis/messagebus logic from discourse-presence, and replaces it with core's new PresenceChannel system. All functionality should be retained. This implementation should scale much better to large numbers of users, reduce the number of HTTP requests made by clients, and reduce the volume of messages on the MessageBus. For more information on PresenceChannel, see 31db8352
This commit is contained in:
@ -1,178 +1,72 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# name: discourse-presence
|
||||
# about: Show which users are writing a reply to a topic
|
||||
# about: Show which users are replying to a topic, or editing a post
|
||||
# version: 2.0
|
||||
# authors: André Pereira, David Taylor, tgxworld
|
||||
# url: https://github.com/discourse/discourse/tree/main/plugins/discourse-presence
|
||||
# transpile_js: true
|
||||
|
||||
enabled_site_setting :presence_enabled
|
||||
hide_plugin if self.respond_to?(:hide_plugin)
|
||||
|
||||
register_asset 'stylesheets/presence.scss'
|
||||
|
||||
PLUGIN_NAME ||= -"discourse-presence"
|
||||
|
||||
after_initialize do
|
||||
|
||||
MessageBus.register_client_message_filter('/presence-plugin/') do |message|
|
||||
published_at = message.data["published_at"]
|
||||
register_presence_channel_prefix("discourse-presence") do |channel_name|
|
||||
if topic_id = channel_name[/\/discourse-presence\/reply\/(\d+)/, 1]
|
||||
topic = Topic.find(topic_id)
|
||||
config = PresenceChannel::Config.new
|
||||
|
||||
if published_at
|
||||
(Time.zone.now.to_i - published_at) <= ::Presence::MAX_BACKLOG_AGE_SECONDS
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
module ::Presence
|
||||
MAX_BACKLOG_AGE_SECONDS = 10
|
||||
|
||||
class Engine < ::Rails::Engine
|
||||
engine_name PLUGIN_NAME
|
||||
isolate_namespace Presence
|
||||
end
|
||||
end
|
||||
|
||||
require_dependency "application_controller"
|
||||
|
||||
class Presence::PresencesController < ::ApplicationController
|
||||
requires_plugin PLUGIN_NAME
|
||||
before_action :ensure_logged_in
|
||||
before_action :ensure_presence_enabled
|
||||
|
||||
EDITING_STATE = 'editing'
|
||||
REPLYING_STATE = 'replying'
|
||||
CLOSED_STATE = 'closed'
|
||||
|
||||
def handle_message
|
||||
[:state, :topic_id].each do |key|
|
||||
raise ActionController::ParameterMissing.new(key) unless params.key?(key)
|
||||
end
|
||||
|
||||
topic_id = permitted_params[:topic_id]
|
||||
topic = Topic.find_by(id: topic_id)
|
||||
|
||||
raise Discourse::InvalidParameters.new(:topic_id) unless topic
|
||||
guardian.ensure_can_see!(topic)
|
||||
|
||||
post = nil
|
||||
|
||||
if (permitted_params[:post_id])
|
||||
if (permitted_params[:state] != EDITING_STATE)
|
||||
raise Discourse::InvalidParameters.new(:state)
|
||||
end
|
||||
|
||||
post = Post.find_by(id: permitted_params[:post_id])
|
||||
raise Discourse::InvalidParameters.new(:topic_id) unless post
|
||||
|
||||
guardian.ensure_can_edit!(post)
|
||||
end
|
||||
|
||||
opts = {
|
||||
max_backlog_age: Presence::MAX_BACKLOG_AGE_SECONDS
|
||||
}
|
||||
|
||||
if permitted_params[:staff_only]
|
||||
opts[:group_ids] = [Group::AUTO_GROUPS[:staff]]
|
||||
if topic.private_message?
|
||||
config.allowed_user_ids = topic.allowed_users.pluck(:id)
|
||||
config.allowed_group_ids = topic.allowed_groups.pluck(:group_id) + [::Group::AUTO_GROUPS[:staff]]
|
||||
elsif secure_group_ids = topic.secure_group_ids
|
||||
config.allowed_group_ids = secure_group_ids
|
||||
else
|
||||
case permitted_params[:state]
|
||||
when EDITING_STATE
|
||||
opts[:group_ids] = [Group::AUTO_GROUPS[:staff]]
|
||||
|
||||
if !post.locked? && !permitted_params[:is_whisper]
|
||||
opts[:user_ids] = [post.user_id]
|
||||
|
||||
if topic.private_message?
|
||||
if post.wiki
|
||||
opts[:user_ids] = opts[:user_ids].concat(
|
||||
topic.allowed_users.where(
|
||||
"trust_level >= ? AND NOT admin OR moderator",
|
||||
SiteSetting.min_trust_to_edit_wiki_post
|
||||
).pluck(:id)
|
||||
)
|
||||
|
||||
opts[:user_ids].uniq!
|
||||
|
||||
# Ignore trust level and just publish to all allowed groups since
|
||||
# trying to figure out which users in the allowed groups have
|
||||
# the necessary trust levels can lead to a large array of user ids
|
||||
# if the groups are big.
|
||||
opts[:group_ids] = opts[:group_ids].concat(
|
||||
topic.allowed_groups.pluck(:id)
|
||||
)
|
||||
end
|
||||
else
|
||||
if post.wiki
|
||||
opts[:group_ids] << Group::AUTO_GROUPS[:"trust_level_#{SiteSetting.min_trust_to_edit_wiki_post}"]
|
||||
elsif SiteSetting.trusted_users_can_edit_others?
|
||||
opts[:group_ids] << Group::AUTO_GROUPS[:trust_level_4]
|
||||
end
|
||||
end
|
||||
end
|
||||
when REPLYING_STATE
|
||||
if permitted_params[:is_whisper]
|
||||
opts[:group_ids] = [Group::AUTO_GROUPS[:staff]]
|
||||
elsif topic.private_message?
|
||||
opts[:user_ids] = topic.allowed_users.pluck(:id)
|
||||
|
||||
opts[:group_ids] = [Group::AUTO_GROUPS[:staff]].concat(
|
||||
topic.allowed_groups.pluck(:id)
|
||||
)
|
||||
else
|
||||
opts[:group_ids] = topic.secure_group_ids
|
||||
end
|
||||
when CLOSED_STATE
|
||||
if topic.private_message?
|
||||
opts[:user_ids] = topic.allowed_users.pluck(:id)
|
||||
|
||||
opts[:group_ids] = [Group::AUTO_GROUPS[:staff]].concat(
|
||||
topic.allowed_groups.pluck(:id)
|
||||
)
|
||||
else
|
||||
opts[:group_ids] = topic.secure_group_ids
|
||||
end
|
||||
end
|
||||
# config.public=true would make data available to anon, so use the tl0 group instead
|
||||
config.allowed_group_ids = [ ::Group::AUTO_GROUPS[:trust_level_0] ]
|
||||
end
|
||||
|
||||
payload = {
|
||||
user: BasicUserSerializer.new(current_user, root: false).as_json,
|
||||
state: permitted_params[:state],
|
||||
is_whisper: permitted_params[:is_whisper].present?,
|
||||
published_at: Time.zone.now.to_i
|
||||
}
|
||||
config
|
||||
elsif topic_id = channel_name[/\/discourse-presence\/whisper\/(\d+)/, 1]
|
||||
Topic.find(topic_id) # Just ensure it exists
|
||||
PresenceChannel::Config.new(allowed_group_ids: [::Group::AUTO_GROUPS[:staff]])
|
||||
elsif post_id = channel_name[/\/discourse-presence\/edit\/(\d+)/, 1]
|
||||
post = Post.find(post_id)
|
||||
topic = Topic.find(post.topic_id)
|
||||
|
||||
if (post_id = permitted_params[:post_id]).present?
|
||||
payload[:post_id] = post_id
|
||||
config = PresenceChannel::Config.new
|
||||
config.allowed_group_ids = [ ::Group::AUTO_GROUPS[:staff] ]
|
||||
|
||||
# Locked and whisper posts are staff only
|
||||
next config if post.locked? || post.whisper?
|
||||
|
||||
config.allowed_user_ids = [ post.user_id ]
|
||||
|
||||
if topic.private_message? && post.wiki
|
||||
# Ignore trust level and just publish to all allowed groups since
|
||||
# trying to figure out which users in the allowed groups have
|
||||
# the necessary trust levels can lead to a large array of user ids
|
||||
# if the groups are big.
|
||||
config.allowed_user_ids += topic.allowed_users.pluck(:id)
|
||||
config.allowed_group_ids += topic.allowed_groups.pluck(:id)
|
||||
elsif post.wiki
|
||||
config.allowed_group_ids << Group::AUTO_GROUPS[:"trust_level_#{SiteSetting.min_trust_to_edit_wiki_post}"]
|
||||
end
|
||||
|
||||
MessageBus.publish("/presence-plugin/#{topic_id}", payload, opts)
|
||||
|
||||
render json: success_json
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_presence_enabled
|
||||
if !SiteSetting.presence_enabled ||
|
||||
(SiteSetting.allow_users_to_hide_profile &&
|
||||
current_user.user_option.hide_profile_and_presence?)
|
||||
|
||||
raise Discourse::NotFound
|
||||
if !topic.private_message? && SiteSetting.trusted_users_can_edit_others?
|
||||
config.allowed_group_ids << Group::AUTO_GROUPS[:trust_level_4]
|
||||
end
|
||||
|
||||
if SiteSetting.enable_category_group_moderation? && group_id = topic.category&.reviewable_by_group_id
|
||||
config.allowed_group_ids << group_id
|
||||
end
|
||||
|
||||
config
|
||||
end
|
||||
|
||||
def permitted_params
|
||||
params.permit(:state, :topic_id, :post_id, :is_whisper, :staff_only)
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
nil
|
||||
end
|
||||
|
||||
Presence::Engine.routes.draw do
|
||||
post '/publish' => 'presences#handle_message'
|
||||
end
|
||||
|
||||
Discourse::Application.routes.append do
|
||||
mount ::Presence::Engine, at: '/presence-plugin'
|
||||
end
|
||||
|
||||
end
|
||||
|
Reference in New Issue
Block a user