discourse/plugins/discourse-presence/plugin.rb

179 lines
5.2 KiB
Ruby

# frozen_string_literal: true
# name: discourse-presence
# about: Show which users are writing a reply to a topic
# version: 2.0
# authors: André Pereira, David Taylor, tgxworld
# url: https://github.com/discourse/discourse/tree/main/plugins/discourse-presence
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/') do |message|
published_at = message.data["published_at"]
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]]
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
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
}
if (post_id = permitted_params[:post_id]).present?
payload[:post_id] = post_id
end
MessageBus.publish("/presence/#{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
end
end
def permitted_params
params.permit(:state, :topic_id, :post_id, :is_whisper, :staff_only)
end
end
Presence::Engine.routes.draw do
post '/publish' => 'presences#handle_message'
end
Discourse::Application.routes.append do
mount ::Presence::Engine, at: '/presence'
end
end