mirror of
https://github.com/discourse/discourse.git
synced 2024-12-02 07:23:40 +08:00
10e1831139
This PR is introducing glimmer usage in the chat-live-pane, for components but also for models. RestModel usage has been dropped in favor of native classes. Other changes/additions in this PR: - sticky dates, scrolling will now keep the date separator of the current section at the top of the screen - better unread management, marking a channel as unread will correctly mark the correct message and not mark the whole channel as read. Tracking state will also now correctly return unread count and unread mentions. - adds an animation on bottom arrow - better scrolling behavior, we should now always correctly keep the scroll position while loading more - reactions are now more reactive, and will update their tooltip without needed to close/reopen it - skeleton has been improved with placeholder images and reactions - when making a reaction on the desktop message actions, the menu won't move anymore - simplify logic and stop maintaining a list of unloaded messages
272 lines
8.1 KiB
Ruby
272 lines
8.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module ChatPublisher
|
|
def self.new_messages_message_bus_channel(chat_channel_id)
|
|
"/chat/#{chat_channel_id}/new-messages"
|
|
end
|
|
|
|
def self.publish_new!(chat_channel, chat_message, staged_id)
|
|
content =
|
|
ChatMessageSerializer.new(
|
|
chat_message,
|
|
{ scope: anonymous_guardian, root: :chat_message },
|
|
).as_json
|
|
content[:type] = :sent
|
|
content[:staged_id] = staged_id
|
|
permissions = permissions(chat_channel)
|
|
|
|
MessageBus.publish("/chat/#{chat_channel.id}", content.as_json, permissions)
|
|
|
|
MessageBus.publish(
|
|
self.new_messages_message_bus_channel(chat_channel.id),
|
|
{
|
|
channel_id: chat_channel.id,
|
|
message_id: chat_message.id,
|
|
user_id: chat_message.user.id,
|
|
username: chat_message.user.username,
|
|
thread_id: chat_message.thread_id,
|
|
},
|
|
permissions,
|
|
)
|
|
end
|
|
|
|
def self.publish_processed!(chat_message)
|
|
chat_channel = chat_message.chat_channel
|
|
content = {
|
|
type: :processed,
|
|
chat_message: {
|
|
id: chat_message.id,
|
|
cooked: chat_message.cooked,
|
|
},
|
|
}
|
|
MessageBus.publish("/chat/#{chat_channel.id}", content.as_json, permissions(chat_channel))
|
|
end
|
|
|
|
def self.publish_edit!(chat_channel, chat_message)
|
|
content =
|
|
ChatMessageSerializer.new(
|
|
chat_message,
|
|
{ scope: anonymous_guardian, root: :chat_message },
|
|
).as_json
|
|
content[:type] = :edit
|
|
MessageBus.publish("/chat/#{chat_channel.id}", content.as_json, permissions(chat_channel))
|
|
end
|
|
|
|
def self.publish_refresh!(chat_channel, chat_message)
|
|
content =
|
|
ChatMessageSerializer.new(
|
|
chat_message,
|
|
{ scope: anonymous_guardian, root: :chat_message },
|
|
).as_json
|
|
content[:type] = :refresh
|
|
MessageBus.publish("/chat/#{chat_channel.id}", content.as_json, permissions(chat_channel))
|
|
end
|
|
|
|
def self.publish_reaction!(chat_channel, chat_message, action, user, emoji)
|
|
content = {
|
|
action: action,
|
|
user: BasicUserSerializer.new(user, root: false).as_json,
|
|
emoji: emoji,
|
|
type: :reaction,
|
|
chat_message_id: chat_message.id,
|
|
}
|
|
MessageBus.publish(
|
|
"/chat/message-reactions/#{chat_message.id}",
|
|
content.as_json,
|
|
permissions(chat_channel),
|
|
)
|
|
MessageBus.publish("/chat/#{chat_channel.id}", content.as_json, permissions(chat_channel))
|
|
end
|
|
|
|
def self.publish_presence!(chat_channel, user, typ)
|
|
raise NotImplementedError
|
|
end
|
|
|
|
def self.publish_delete!(chat_channel, chat_message)
|
|
MessageBus.publish(
|
|
"/chat/#{chat_channel.id}",
|
|
{ type: "delete", deleted_id: chat_message.id, deleted_at: chat_message.deleted_at },
|
|
permissions(chat_channel),
|
|
)
|
|
end
|
|
|
|
def self.publish_bulk_delete!(chat_channel, deleted_message_ids)
|
|
MessageBus.publish(
|
|
"/chat/#{chat_channel.id}",
|
|
{ typ: "bulk_delete", deleted_ids: deleted_message_ids, deleted_at: Time.zone.now },
|
|
permissions(chat_channel),
|
|
)
|
|
end
|
|
|
|
def self.publish_restore!(chat_channel, chat_message)
|
|
content =
|
|
ChatMessageSerializer.new(
|
|
chat_message,
|
|
{ scope: anonymous_guardian, root: :chat_message },
|
|
).as_json
|
|
content[:type] = :restore
|
|
MessageBus.publish("/chat/#{chat_channel.id}", content.as_json, permissions(chat_channel))
|
|
end
|
|
|
|
def self.publish_flag!(chat_message, user, reviewable, score)
|
|
# Publish to user who created flag
|
|
MessageBus.publish(
|
|
"/chat/#{chat_message.chat_channel_id}",
|
|
{
|
|
type: "self_flagged",
|
|
user_flag_status: score.status_for_database,
|
|
chat_message_id: chat_message.id,
|
|
}.as_json,
|
|
user_ids: [user.id],
|
|
)
|
|
|
|
# Publish flag with link to reviewable to staff
|
|
MessageBus.publish(
|
|
"/chat/#{chat_message.chat_channel_id}",
|
|
{ type: "flag", chat_message_id: chat_message.id, reviewable_id: reviewable.id }.as_json,
|
|
group_ids: [Group::AUTO_GROUPS[:staff]],
|
|
)
|
|
end
|
|
|
|
def self.user_tracking_state_message_bus_channel(user_id)
|
|
"/chat/user-tracking-state/#{user_id}"
|
|
end
|
|
|
|
def self.publish_user_tracking_state(user, chat_channel_id, chat_message_id)
|
|
data = { chat_channel_id: chat_channel_id, chat_message_id: chat_message_id }.merge(
|
|
ChatChannelUnreadsQuery.call(channel_id: chat_channel_id, user_id: user.id),
|
|
)
|
|
|
|
MessageBus.publish(
|
|
self.user_tracking_state_message_bus_channel(user.id),
|
|
data.as_json,
|
|
user_ids: [user.id],
|
|
)
|
|
end
|
|
|
|
def self.new_mentions_message_bus_channel(chat_channel_id)
|
|
"/chat/#{chat_channel_id}/new-mentions"
|
|
end
|
|
|
|
def self.publish_new_mention(user_id, chat_channel_id, chat_message_id)
|
|
MessageBus.publish(
|
|
self.new_mentions_message_bus_channel(chat_channel_id),
|
|
{ message_id: chat_message_id, channel_id: chat_channel_id }.as_json,
|
|
user_ids: [user_id],
|
|
)
|
|
end
|
|
|
|
NEW_CHANNEL_MESSAGE_BUS_CHANNEL = "/chat/new-channel"
|
|
|
|
def self.publish_new_channel(chat_channel, users)
|
|
users.each do |user|
|
|
# FIXME: This could generate a lot of queries depending on the amount of users
|
|
membership = chat_channel.membership_for(user)
|
|
|
|
# TODO: this event is problematic as some code will update the membership before calling it
|
|
# and other code will update it after calling it
|
|
# it means frontend must handle logic for both cases
|
|
serialized_channel =
|
|
ChatChannelSerializer.new(
|
|
chat_channel,
|
|
scope: Guardian.new(user), # We need a guardian here for direct messages
|
|
root: :channel,
|
|
membership: membership,
|
|
).as_json
|
|
|
|
MessageBus.publish(NEW_CHANNEL_MESSAGE_BUS_CHANNEL, serialized_channel, user_ids: [user.id])
|
|
end
|
|
end
|
|
|
|
def self.publish_inaccessible_mentions(
|
|
user_id,
|
|
chat_message,
|
|
cannot_chat_users,
|
|
without_membership,
|
|
too_many_members,
|
|
mentions_disabled
|
|
)
|
|
MessageBus.publish(
|
|
"/chat/#{chat_message.chat_channel_id}",
|
|
{
|
|
type: :mention_warning,
|
|
chat_message_id: chat_message.id,
|
|
cannot_see: cannot_chat_users.map { |u| { username: u.username, id: u.id } }.as_json,
|
|
without_membership:
|
|
without_membership.map { |u| { username: u.username, id: u.id } }.as_json,
|
|
groups_with_too_many_members: too_many_members.map(&:name).as_json,
|
|
group_mentions_disabled: mentions_disabled.map(&:name).as_json,
|
|
},
|
|
user_ids: [user_id],
|
|
)
|
|
end
|
|
|
|
CHANNEL_EDITS_MESSAGE_BUS_CHANNEL = "/chat/channel-edits"
|
|
|
|
def self.publish_chat_channel_edit(chat_channel, acting_user)
|
|
MessageBus.publish(
|
|
CHANNEL_EDITS_MESSAGE_BUS_CHANNEL,
|
|
{
|
|
chat_channel_id: chat_channel.id,
|
|
name: chat_channel.title(acting_user),
|
|
description: chat_channel.description,
|
|
slug: chat_channel.slug,
|
|
},
|
|
permissions(chat_channel),
|
|
)
|
|
end
|
|
|
|
CHANNEL_STATUS_MESSAGE_BUS_CHANNEL = "/chat/channel-status"
|
|
|
|
def self.publish_channel_status(chat_channel)
|
|
MessageBus.publish(
|
|
CHANNEL_STATUS_MESSAGE_BUS_CHANNEL,
|
|
{ chat_channel_id: chat_channel.id, status: chat_channel.status },
|
|
permissions(chat_channel),
|
|
)
|
|
end
|
|
|
|
CHANNEL_METADATA_MESSAGE_BUS_CHANNEL = "/chat/channel-metadata"
|
|
|
|
def self.publish_chat_channel_metadata(chat_channel)
|
|
MessageBus.publish(
|
|
CHANNEL_METADATA_MESSAGE_BUS_CHANNEL,
|
|
{ chat_channel_id: chat_channel.id, memberships_count: chat_channel.user_count },
|
|
permissions(chat_channel),
|
|
)
|
|
end
|
|
|
|
CHANNEL_ARCHIVE_STATUS_MESSAGE_BUS_CHANNEL = "/chat/channel-archive-status"
|
|
|
|
def self.publish_archive_status(
|
|
chat_channel,
|
|
archive_status:,
|
|
archived_messages:,
|
|
archive_topic_id:,
|
|
total_messages:
|
|
)
|
|
MessageBus.publish(
|
|
CHANNEL_ARCHIVE_STATUS_MESSAGE_BUS_CHANNEL,
|
|
{
|
|
chat_channel_id: chat_channel.id,
|
|
archive_failed: archive_status == :failed,
|
|
archive_completed: archive_status == :success,
|
|
archived_messages: archived_messages,
|
|
total_messages: total_messages,
|
|
archive_topic_id: archive_topic_id,
|
|
},
|
|
permissions(chat_channel),
|
|
)
|
|
end
|
|
|
|
private
|
|
|
|
def self.permissions(chat_channel)
|
|
{ user_ids: chat_channel.allowed_user_ids, group_ids: chat_channel.allowed_group_ids }
|
|
end
|
|
|
|
def self.anonymous_guardian
|
|
Guardian.new(nil)
|
|
end
|
|
end
|