mirror of
https://github.com/discourse/discourse.git
synced 2024-12-05 11:33:43 +08:00
c00205730e
Presence endpoints are often called asynchronously at the same time as other request, and never need to modify the session. Skipping ensures that an unneeded cookie rotation doesn't race against another request and cause issues. This change brings presence in line with message-bus's behaviour.
88 lines
2.9 KiB
Ruby
88 lines
2.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class PresenceController < ApplicationController
|
|
skip_before_action :check_xhr
|
|
before_action :ensure_logged_in, only: [:update]
|
|
before_action :skip_persist_session
|
|
|
|
MAX_CHANNELS_PER_REQUEST ||= 50
|
|
|
|
def get
|
|
names = params.require(:channels)
|
|
raise Discourse::InvalidParameters.new(:channels) if !(names.is_a?(Array) && names.all? { |n| n.is_a? String })
|
|
|
|
names.uniq!
|
|
|
|
raise Discourse::InvalidParameters.new("Too many channels") if names.length > MAX_CHANNELS_PER_REQUEST
|
|
|
|
user_group_ids = if current_user
|
|
GroupUser.where(user_id: current_user.id).pluck("group_id")
|
|
else
|
|
[]
|
|
end
|
|
|
|
result = {}
|
|
names.each do |name|
|
|
channel = PresenceChannel.new(name)
|
|
if channel.can_view?(user_id: current_user&.id, group_ids: user_group_ids)
|
|
result[name] = PresenceChannelStateSerializer.new(channel.state, root: nil)
|
|
else
|
|
result[name] = nil
|
|
end
|
|
rescue PresenceChannel::NotFound
|
|
result[name] = nil
|
|
end
|
|
|
|
render json: result
|
|
end
|
|
|
|
def update
|
|
client_id = params[:client_id]
|
|
raise Discourse::InvalidParameters.new(:client_id) if !client_id.is_a?(String) || client_id.blank?
|
|
|
|
# JS client is designed to throttle to one request per second
|
|
# When no changes are being made, it makes one request every 30 seconds
|
|
RateLimiter.new(nil, "update-presence-#{current_user.id}", 20, 10.seconds).performed!
|
|
|
|
present_channels = params[:present_channels]
|
|
if present_channels && !(present_channels.is_a?(Array) && present_channels.all? { |c| c.is_a? String })
|
|
raise Discourse::InvalidParameters.new(:present_channels)
|
|
end
|
|
|
|
leave_channels = params[:leave_channels]
|
|
if leave_channels && !(leave_channels.is_a?(Array) && leave_channels.all? { |c| c.is_a? String })
|
|
raise Discourse::InvalidParameters.new(:leave_channels)
|
|
end
|
|
|
|
if present_channels && present_channels.length > MAX_CHANNELS_PER_REQUEST
|
|
raise Discourse::InvalidParameters.new("Too many present_channels")
|
|
end
|
|
|
|
response = {}
|
|
|
|
present_channels&.each do |name|
|
|
PresenceChannel.new(name).present(user_id: current_user&.id, client_id: params[:client_id])
|
|
response[name] = true
|
|
rescue PresenceChannel::NotFound, PresenceChannel::InvalidAccess
|
|
response[name] = false
|
|
end
|
|
|
|
leave_channels&.each do |name|
|
|
PresenceChannel.new(name).leave(user_id: current_user&.id, client_id: params[:client_id])
|
|
rescue PresenceChannel::NotFound
|
|
# Do nothing. Don't reveal that this channel doesn't exist
|
|
end
|
|
|
|
render json: response
|
|
end
|
|
|
|
private
|
|
|
|
def skip_persist_session
|
|
# Presence endpoints are often called asynchronously at the same time as other request,
|
|
# and never need to modify the session. Skipping ensures that an unneeded cookie rotation
|
|
# doesn't race against another request and cause issues.
|
|
session.options[:skip] = true
|
|
end
|
|
end
|