160 lines
5.9 KiB
C#
160 lines
5.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Knot.Contracts.Messaging.Application.Abstractions;
|
|
using Knot.Contracts.Messaging.Domain;
|
|
using Knot.Modules.Conversations.Application.Abstractions;
|
|
using Knot.Modules.Conversations.Application.DTOs;
|
|
using Knot.Modules.Conversations.Domain;
|
|
using Knot.Shared.Kernel;
|
|
using MediatR;
|
|
|
|
namespace Knot.Modules.Conversations.Application.Chats.GetChatById;
|
|
|
|
public record GetChatByIdQuery(Guid UserId, Guid ChatId) : IQuery<ChatDto?>;
|
|
|
|
internal sealed class GetChatByIdQueryHandler : IQueryHandler<GetChatByIdQuery, ChatDto?>
|
|
{
|
|
private readonly IChatRepository _chatRepository;
|
|
private readonly IUserDisplayNameProvider _userProvider;
|
|
private readonly IMessageRepository _messageRepository;
|
|
private readonly IMessageReactionRepository _reactionRepository;
|
|
|
|
public GetChatByIdQueryHandler(IChatRepository chatRepository, IUserDisplayNameProvider userProvider, IMessageRepository messageRepository, IMessageReactionRepository reactionRepository)
|
|
{
|
|
_chatRepository = chatRepository;
|
|
_userProvider = userProvider;
|
|
_messageRepository = messageRepository;
|
|
_reactionRepository = reactionRepository;
|
|
}
|
|
|
|
public async Task<Result<ChatDto?>> Handle(GetChatByIdQuery request, CancellationToken cancellationToken)
|
|
{
|
|
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
|
|
if (chat == null)
|
|
{
|
|
return Result.Success<ChatDto?>(null);
|
|
}
|
|
|
|
if (!chat.Members.Any(m => m.UserId == request.UserId))
|
|
{
|
|
return Result.Failure<ChatDto?>(ChatErrors.ChatsForbidden);
|
|
}
|
|
|
|
var userIdsToFetch = new HashSet<Guid>();
|
|
foreach (var member in chat.Members)
|
|
{
|
|
userIdsToFetch.Add(member.UserId);
|
|
}
|
|
|
|
var latestMessage = await _messageRepository.GetLatestChatMessageAsync(chat.Id, cancellationToken);
|
|
var latestReactions = latestMessage != null
|
|
? await _reactionRepository.GetReactionsForMessageAsync(latestMessage.Id, cancellationToken)
|
|
: new List<MessageReaction>();
|
|
|
|
if (latestMessage != null)
|
|
{
|
|
userIdsToFetch.Add(latestMessage.SenderId);
|
|
foreach (var reaction in latestReactions)
|
|
{
|
|
userIdsToFetch.Add(reaction.UserId);
|
|
}
|
|
}
|
|
|
|
var usersInfo = await _userProvider.GetUsersInfoAsync(userIdsToFetch, cancellationToken);
|
|
|
|
var members = new List<ChatMemberDto>();
|
|
foreach (var member in chat.Members)
|
|
{
|
|
usersInfo.TryGetValue(member.UserId, out var user);
|
|
members.Add(new ChatMemberDto(
|
|
member.Id,
|
|
member.UserId,
|
|
member.Role,
|
|
member.IsPinned,
|
|
user != null ? new ChatUserDto(
|
|
user.Id,
|
|
user.Username,
|
|
user.DisplayName,
|
|
user.Avatar,
|
|
false,
|
|
DateTime.UtcNow
|
|
) : null
|
|
));
|
|
}
|
|
|
|
var messagesList = new List<ChatMessageDto>();
|
|
if (latestMessage != null)
|
|
{
|
|
usersInfo.TryGetValue(latestMessage.SenderId, out var senderObj);
|
|
|
|
var reactionsWithUser = new List<ReactionDto>();
|
|
foreach (var reaction in latestReactions)
|
|
{
|
|
usersInfo.TryGetValue(reaction.UserId, out var reactionUser);
|
|
reactionsWithUser.Add(new ReactionDto(
|
|
reaction.Id,
|
|
reaction.Emoji,
|
|
reaction.UserId,
|
|
reactionUser != null
|
|
? new MessageSenderDto(reactionUser.Id, reactionUser.Username, reactionUser.DisplayName, reactionUser.Avatar)
|
|
: new MessageSenderDto(reaction.UserId, "unknown", "Unknown", null)
|
|
));
|
|
}
|
|
|
|
var readByList = chat.Members
|
|
.Where(m => m.LastReadSequenceId >= latestMessage.SequenceId && m.UserId != latestMessage.SenderId)
|
|
.Select(m => new ReadByDto(m.UserId))
|
|
.ToList();
|
|
|
|
messagesList.Add(new ChatMessageDto(
|
|
latestMessage.Id,
|
|
latestMessage.ChatId,
|
|
latestMessage.SenderId,
|
|
latestMessage.Content,
|
|
latestMessage.Type,
|
|
latestMessage.ReplyToId,
|
|
latestMessage.Quote,
|
|
latestMessage.StoryId,
|
|
latestMessage.StoryMediaUrl,
|
|
latestMessage.StoryMediaType,
|
|
latestMessage.IsEdited,
|
|
latestMessage.IsDeleted,
|
|
latestMessage.CreatedAt,
|
|
latestMessage.SequenceId,
|
|
latestMessage.Media.Select(media => new MediaDto(media.Id, media.Type, media.Url, media.Filename, media.Size)).ToList(),
|
|
senderObj != null ? new MessageSenderDto(
|
|
senderObj.Id,
|
|
senderObj.Username,
|
|
senderObj.DisplayName,
|
|
senderObj.Avatar
|
|
) : new MessageSenderDto(latestMessage.SenderId, "unknown", "Unknown", null),
|
|
reactionsWithUser,
|
|
readByList
|
|
));
|
|
}
|
|
|
|
var currentMember = chat.Members.First(m => m.UserId == request.UserId);
|
|
var unreadCount = (int)Math.Max(0, chat.LastMessageSequenceId - currentMember.LastReadSequenceId);
|
|
|
|
var dto = new ChatDto(
|
|
chat.Id,
|
|
chat.Type.ToString().ToLowerInvariant(),
|
|
chat.Type == ChatType.Favorites ? "Избранное" : (chat.Type == ChatType.Personal ? null : chat.Name),
|
|
chat.Description,
|
|
chat.Avatar,
|
|
chat.CreatedAt,
|
|
members,
|
|
messagesList,
|
|
unreadCount
|
|
);
|
|
|
|
return Result.Success<ChatDto?>(dto);
|
|
}
|
|
}
|
|
|
|
|
|
|