discourse/plugins/chat/app/jobs/regular/auto_join_channel_batch.rb
Jan Cernik cbbaeb55b5
FIX: Don't autojoin users when they have ready-only permissions (#20213)
After this change, in order to join a chat channel, a user needs to be in a group with at least “Reply” permission for the category. If the user only has “See” permission, they are able to preview the channel, but not join it or send messages. The auto-join function also follows this new restriction.

---------

Co-authored-by: Martin Brennan <martin@discourse.org>
2023-05-10 08:45:13 -03:00

80 lines
3.1 KiB
Ruby

# NOTE: When changing auto-join logic, make sure to update the `settings.auto_join_users_info` translation as well.
# frozen_string_literal: true
module Jobs
class AutoJoinChannelBatch < ::Jobs::Base
def execute(args)
return "starts_at or ends_at missing" if args[:starts_at].blank? || args[:ends_at].blank?
start_user_id = args[:starts_at].to_i
end_user_id = args[:ends_at].to_i
return "End is higher than start" if end_user_id < start_user_id
channel =
ChatChannel.find_by(
id: args[:chat_channel_id],
auto_join_users: true,
chatable_type: "Category",
)
return if !channel
category = channel.chatable
return if !category
query_args = {
chat_channel_id: channel.id,
start: start_user_id,
end: end_user_id,
suspended_until: Time.zone.now,
last_seen_at: 3.months.ago,
channel_category: channel.chatable_id,
permission_type: CategoryGroup.permission_types[:create_post],
everyone: Group::AUTO_GROUPS[:everyone],
mode: Chat::UserChatChannelMembership.join_modes[:automatic],
}
new_member_ids = DB.query_single(create_memberships_query(category), query_args)
# Only do this if we are running auto-join for a single user, if we
# are doing it for many then we should do it after all batches are
# complete for the channel in Jobs::AutoJoinChannelMemberships
if start_user_id == end_user_id
Chat::ChatChannelMembershipManager.new(channel).recalculate_user_count
end
Chat::Publisher.publish_new_channel(channel.reload, User.where(id: new_member_ids))
end
private
def create_memberships_query(category)
query = <<~SQL
INSERT INTO user_chat_channel_memberships (user_id, chat_channel_id, following, created_at, updated_at, join_mode)
SELECT DISTINCT(users.id), :chat_channel_id, TRUE, NOW(), NOW(), :mode
FROM users
INNER JOIN user_options uo ON uo.user_id = users.id
LEFT OUTER JOIN user_chat_channel_memberships uccm ON
uccm.chat_channel_id = :chat_channel_id AND uccm.user_id = users.id
LEFT OUTER JOIN group_users gu ON gu.user_id = users.id
LEFT OUTER JOIN category_groups cg ON cg.group_id = gu.group_id AND
cg.permission_type <= :permission_type
WHERE (users.id >= :start AND users.id <= :end) AND
users.staged IS FALSE AND
users.active AND
NOT EXISTS(SELECT 1 FROM anonymous_users a WHERE a.user_id = users.id) AND
(suspended_till IS NULL OR suspended_till <= :suspended_until) AND
(last_seen_at IS NULL OR last_seen_at > :last_seen_at) AND
uo.chat_enabled AND
uccm.id IS NULL AND
(NOT EXISTS(SELECT 1 FROM category_groups WHERE category_id = :channel_category)
OR EXISTS (SELECT 1 FROM category_groups WHERE category_id = :channel_category AND group_id = :everyone AND permission_type <= :permission_type)
OR cg.category_id = :channel_category)
RETURNING user_chat_channel_memberships.user_id
SQL
end
end
end