DEV: Rearchitect chat tracking state (#21550)

This moves chat tracking state calculation for channels
and threads into a central Chat::TrackingStateManager service, that
serves a similar purpose to the TopicTrackingState model
in core.

This service calls down to these query classes:

* ThreadUnreadsQuery
* ChannelUnreadsQuery

To get the unread_count and mention_count for the appropriate
channels and threads.

As well as this, this commit refactors the client-side chat
tracking state.

Now, there is a central ChatTrackingStateManager Ember Service
so all tracking is accessible and can be counted from one place,
which can also initialize tracking from an initial payload.

The actual tracking counts are now maintained in a ChatTrackingState
class that is initialized on the `.tracking` property of both channel and
thread objects.

This removes the attributes on UserChatChannelMembership and decoration
of said membership from ChannelFetcher, preferring instead to have an additional
object for tracking in the JSON.
This commit is contained in:
Martin Brennan
2023-05-16 14:51:13 +02:00
committed by GitHub
parent a2b12b6ace
commit 9953a6edd9
35 changed files with 952 additions and 176 deletions

View File

@ -4,14 +4,22 @@ module Chat
class ChannelFetcher
MAX_PUBLIC_CHANNEL_RESULTS = 50
def self.structured(guardian)
def self.structured(guardian, include_threads: false)
memberships = Chat::ChannelMembershipManager.all_for_user(guardian.user)
public_channels =
secured_public_channels(guardian, memberships, status: :open, following: true)
direct_message_channels =
secured_direct_message_channels(guardian.user.id, memberships, guardian)
{
public_channels:
secured_public_channels(guardian, memberships, status: :open, following: true),
direct_message_channels:
secured_direct_message_channels(guardian.user.id, memberships, guardian),
public_channels: public_channels,
direct_message_channels: direct_message_channels,
memberships: memberships,
tracking:
tracking_state(
public_channels.map(&:id) + direct_message_channels.map(&:id),
guardian,
include_threads: include_threads,
),
}
end
@ -151,7 +159,6 @@ module Chat
options.merge(include_archives: true, filter_on_category_name: true),
)
decorate_memberships_with_tracking_data(guardian, channels, memberships)
channels = channels.to_a
preload_custom_fields_for(channels)
channels
@ -184,32 +191,17 @@ module Chat
User.allowed_user_custom_fields(guardian) +
UserField.all.pluck(:id).map { |fid| "#{User::USER_FIELD_PREFIX}#{fid}" }
User.preload_custom_fields(channels.map { |c| c.chatable.users }.flatten, preload_fields)
decorate_memberships_with_tracking_data(guardian, channels, memberships)
channels
end
def self.decorate_memberships_with_tracking_data(guardian, channels, memberships)
unread_counts_per_channel = unread_counts(channels, guardian.user.id)
channels.each do |channel|
membership = memberships.find { |m| m.chat_channel_id == channel.id }
if membership
channel_unread_counts =
unread_counts_per_channel.find { |uc| uc.channel_id == channel.id }
membership.unread_mentions = channel_unread_counts.mention_count
membership.unread_count = channel_unread_counts.unread_count if !membership.muted
end
end
end
def self.unread_counts(channels, user_id)
Chat::ChannelUnreadsQuery.call(
channel_ids: channels.map(&:id),
user_id: user_id,
include_no_membership_channels: true,
)
def self.tracking_state(channel_ids, guardian, include_threads: false)
Chat::TrackingState.call(
channel_ids: channel_ids,
guardian: guardian,
include_missing_memberships: true,
include_threads:
SiteSetting.enable_experimental_chat_threaded_discussions && include_threads,
).report
end
def self.find_with_access_check(channel_id_or_name, guardian)