mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 06:41:25 +08:00
DEV: Refactor DM channel creation into new service pattern (#22144)
This will be used when we move the channel creation for DMs to happen when we first send a message in a DM channel to avoid a double-request. For now we can just have a new API endpoint for creating this that the existing frontend code can use, that uses the new service pattern. This also uses the new policy pattern for services where the policy can be defined in a class so a more dynamic reason for the policy failing can be sent to the controller. Co-authored-by: Loïc Guitaut <loic@discourse.org>
This commit is contained in:
@ -1,133 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Chat
|
||||
class DirectMessageChannelCreator
|
||||
class NotAllowed < StandardError
|
||||
end
|
||||
|
||||
def self.create!(acting_user:, target_users:)
|
||||
Guardian.new(acting_user).ensure_can_create_direct_message!
|
||||
target_users.uniq!
|
||||
direct_message = Chat::DirectMessage.for_user_ids(target_users.map(&:id))
|
||||
|
||||
if direct_message
|
||||
chat_channel = Chat::Channel.find_by!(chatable: direct_message)
|
||||
else
|
||||
enforce_max_direct_message_users!(acting_user, target_users)
|
||||
ensure_actor_can_communicate!(acting_user, target_users)
|
||||
direct_message = Chat::DirectMessage.create!(user_ids: target_users.map(&:id))
|
||||
chat_channel = direct_message.create_chat_channel!
|
||||
end
|
||||
|
||||
update_memberships(acting_user, target_users, chat_channel.id)
|
||||
Chat::Publisher.publish_new_channel(chat_channel, target_users)
|
||||
|
||||
chat_channel
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.enforce_max_direct_message_users!(acting_user, target_users)
|
||||
# We never want to prevent the actor from communicating with themselves
|
||||
target_users = target_users.reject { |user| user.id == acting_user.id }
|
||||
|
||||
if !acting_user.staff? && target_users.size > SiteSetting.chat_max_direct_message_users
|
||||
if SiteSetting.chat_max_direct_message_users == 0
|
||||
raise NotAllowed.new(I18n.t("chat.errors.over_chat_max_direct_message_users_allow_self"))
|
||||
else
|
||||
raise NotAllowed.new(
|
||||
I18n.t(
|
||||
"chat.errors.over_chat_max_direct_message_users",
|
||||
count: SiteSetting.chat_max_direct_message_users + 1, # +1 for the acting_user
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.update_memberships(acting_user, target_users, chat_channel_id)
|
||||
sql_params = {
|
||||
acting_user_id: acting_user.id,
|
||||
user_ids: target_users.map(&:id),
|
||||
chat_channel_id: chat_channel_id,
|
||||
always_notification_level: Chat::UserChatChannelMembership::NOTIFICATION_LEVELS[:always],
|
||||
}
|
||||
|
||||
DB.exec(<<~SQL, sql_params)
|
||||
INSERT INTO user_chat_channel_memberships(
|
||||
user_id,
|
||||
chat_channel_id,
|
||||
muted,
|
||||
following,
|
||||
desktop_notification_level,
|
||||
mobile_notification_level,
|
||||
created_at,
|
||||
updated_at
|
||||
)
|
||||
VALUES(
|
||||
unnest(array[:user_ids]),
|
||||
:chat_channel_id,
|
||||
false,
|
||||
false,
|
||||
:always_notification_level,
|
||||
:always_notification_level,
|
||||
NOW(),
|
||||
NOW()
|
||||
)
|
||||
ON CONFLICT (user_id, chat_channel_id) DO NOTHING;
|
||||
|
||||
UPDATE user_chat_channel_memberships
|
||||
SET following = true
|
||||
WHERE user_id = :acting_user_id AND chat_channel_id = :chat_channel_id;
|
||||
SQL
|
||||
end
|
||||
|
||||
def self.ensure_actor_can_communicate!(acting_user, target_users)
|
||||
# We never want to prevent the actor from communicating with themselves
|
||||
target_users = target_users.reject { |user| user.id == acting_user.id }
|
||||
|
||||
screener =
|
||||
UserCommScreener.new(acting_user: acting_user, target_user_ids: target_users.map(&:id))
|
||||
|
||||
# People blocking the actor.
|
||||
screener.preventing_actor_communication.each do |user_id|
|
||||
raise NotAllowed.new(
|
||||
I18n.t(
|
||||
"chat.errors.not_accepting_dms",
|
||||
username: target_users.find { |user| user.id == user_id }.username,
|
||||
),
|
||||
)
|
||||
end
|
||||
|
||||
# The actor cannot start DMs with people if they are not allowing anyone
|
||||
# to start DMs with them, that's no fair!
|
||||
if screener.actor_disallowing_all_pms?
|
||||
raise NotAllowed.new(I18n.t("chat.errors.actor_disallowed_dms"))
|
||||
end
|
||||
|
||||
# People the actor is blocking.
|
||||
target_users.each do |target_user|
|
||||
if screener.actor_disallowing_pms?(target_user.id)
|
||||
raise NotAllowed.new(
|
||||
I18n.t(
|
||||
"chat.errors.actor_preventing_target_user_from_dm",
|
||||
username: target_user.username,
|
||||
),
|
||||
)
|
||||
end
|
||||
|
||||
if screener.actor_ignoring?(target_user.id)
|
||||
raise NotAllowed.new(
|
||||
I18n.t("chat.errors.actor_ignoring_target_user", username: target_user.username),
|
||||
)
|
||||
end
|
||||
|
||||
if screener.actor_muting?(target_user.id)
|
||||
raise NotAllowed.new(
|
||||
I18n.t("chat.errors.actor_muting_target_user", username: target_user.username),
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user