discourse/plugins/chat/lib/direct_message_channel_creator.rb
Gerhard Schlager 7ef482a292
REFACTOR: Fix pluralized strings in chat plugin (#20357)
* FIX: Use pluralized string

* REFACTOR: Fix misuse of pluralized string

* REFACTOR: Fix misuse of pluralized string

* DEV: Remove linting of `one` key in MessageFormat string, it doesn't work

* REFACTOR: Fix misuse of pluralized string

This also ensures that the URL works on subfolder and shows the site setting link only for admins instead of staff. The string is quite complicated, so the best option was to switch to MessageFormat.

* REFACTOR: Fix misuse of pluralized string

* FIX: Use pluralized string

This also ensures that the URL works on subfolder and shows the site setting link only for admins instead of staff.

* REFACTOR: Correctly pluralize reaction tooltips in chat

This also ensures that maximum 5 usernames are shown and fixes the number of "others" which was off by 1 if the current user reacted on a message.

* REFACTOR: Use translatable string as comma separator

* DEV: Add comment to translation to clarify the meaning of `%{identifier}`

* REFACTOR: Use translatable comma separator and use explicit interpolation keys

* REFACTOR: Don't interpolate lowercase channel status

* REFACTOR: Fix misuse of pluralized string

* REFACTOR: Don't interpolate channel status

* REFACTOR: Use %{count} interpolation key

* REFACTOR: Fix misuse of pluralized string

* REFACTOR: Correctly pluralize DM chat channel titles
2023-02-20 10:31:02 +01:00

131 lines
4.2 KiB
Ruby

# frozen_string_literal: true
module Chat::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 = DirectMessage.for_user_ids(target_users.map(&:id))
if direct_message
chat_channel = ChatChannel.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 = 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)
ChatPublisher.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 themself.
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: 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 themself.
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