Фиксы

This commit is contained in:
Халимов Рустам
2026-03-19 01:22:28 +03:00
parent 3d00bacafb
commit 282b43d4c1
11 changed files with 58 additions and 19 deletions

View File

@@ -11,8 +11,11 @@ using MediatR;
using Host.Application.Admin.Queries;
using Host.Application.Admin.Commands;
using Microsoft.AspNetCore.Authorization;
namespace Host.Controllers;
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class AdminController : ControllerBase

View File

@@ -52,7 +52,7 @@ public sealed class ChatsController : ControllerBase
var result = await _sender.Send(command, ct);
if (result.IsFailure) return BadRequest(result.Error.Description);
var chatResult = await _sender.Send(new GetChatByIdQuery(result.Value), ct);
var chatResult = await _sender.Send(new GetChatByIdQuery(_userContext.UserId, result.Value), ct);
return Ok(chatResult.Value);
}
@@ -63,7 +63,7 @@ public sealed class ChatsController : ControllerBase
var result = await _sender.Send(command, ct);
if (result.IsFailure) return BadRequest(result.Error.Description);
var chatResult = await _sender.Send(new GetChatByIdQuery(result.Value), ct);
var chatResult = await _sender.Send(new GetChatByIdQuery(_userContext.UserId, result.Value), ct);
return Ok(chatResult.Value);
}
@@ -81,7 +81,7 @@ public sealed class ChatsController : ControllerBase
var result = await _sender.Send(command, ct);
if (result.IsFailure) return BadRequest(result.Error.Description);
var chatResult = await _sender.Send(new GetChatByIdQuery(result.Value), ct);
var chatResult = await _sender.Send(new GetChatByIdQuery(_userContext.UserId, result.Value), ct);
return Ok(chatResult.Value);
}
@@ -91,7 +91,7 @@ public sealed class ChatsController : ControllerBase
var result = await _sender.Send(new GetOrCreateFavoritesCommand(_userContext.UserId), ct);
if (result.IsFailure) return BadRequest(result.Error.Description);
var chatResult = await _sender.Send(new GetChatByIdQuery(result.Value), ct);
var chatResult = await _sender.Send(new GetChatByIdQuery(_userContext.UserId, result.Value), ct);
return Ok(chatResult.Value);
}
@@ -101,7 +101,7 @@ public sealed class ChatsController : ControllerBase
var result = await _sender.Send(new UpdateChatCommand(id, _userContext.UserId, request.Name, request.Description), ct);
if (result.IsFailure) return NotFound();
var chatResult = await _sender.Send(new GetChatByIdQuery(result.Value), ct);
var chatResult = await _sender.Send(new GetChatByIdQuery(_userContext.UserId, result.Value), ct);
return Ok(chatResult.Value);
}
@@ -139,7 +139,7 @@ public sealed class ChatsController : ControllerBase
var result = await _sender.Send(new AddMembersCommand(id, _userContext.UserId, request.UserIds.ToList()), ct);
if (result.IsFailure) return NotFound();
var chatResult = await _sender.Send(new GetChatByIdQuery(result.Value), ct);
var chatResult = await _sender.Send(new GetChatByIdQuery(_userContext.UserId, result.Value), ct);
return Ok(chatResult.Value);
}
@@ -149,7 +149,7 @@ public sealed class ChatsController : ControllerBase
var result = await _sender.Send(new RemoveMemberCommand(id, _userContext.UserId, userId), ct);
if (result.IsFailure) return NotFound();
var chatResult = await _sender.Send(new GetChatByIdQuery(result.Value), ct);
var chatResult = await _sender.Send(new GetChatByIdQuery(_userContext.UserId, result.Value), ct);
return Ok(chatResult.Value);
}
@@ -163,7 +163,7 @@ public sealed class ChatsController : ControllerBase
if (result.IsFailure) return NotFound();
var chatResult = await _sender.Send(new GetChatByIdQuery(result.Value), ct);
var chatResult = await _sender.Send(new GetChatByIdQuery(_userContext.UserId, result.Value), ct);
return Ok(chatResult.Value);
}
@@ -177,7 +177,7 @@ public sealed class ChatsController : ControllerBase
if (result.IsFailure) return NotFound();
var chatResult = await _sender.Send(new GetChatByIdQuery(result.Value), ct);
var chatResult = await _sender.Send(new GetChatByIdQuery(_userContext.UserId, result.Value), ct);
return Ok(chatResult.Value);
}
@@ -187,7 +187,7 @@ public sealed class ChatsController : ControllerBase
var result = await _sender.Send(new RemoveGroupAvatarCommand(id, _userContext.UserId), ct);
if (result.IsFailure) return NotFound();
var chatResult = await _sender.Send(new GetChatByIdQuery(result.Value), ct);
var chatResult = await _sender.Send(new GetChatByIdQuery(_userContext.UserId, result.Value), ct);
return Ok(chatResult.Value);
}
}

View File

@@ -4,6 +4,7 @@ using Knot.Shared.Kernel.Storage;
namespace Host.Controllers;
[Authorize]
[ApiController]
[Route("api/files")]
public sealed class FilesController : ControllerBase

View File

@@ -11,7 +11,7 @@ using Knot.Modules.Chats.Application.Abstractions;
namespace Knot.Modules.Chats.Application.Chats.GetChatById;
public record GetChatByIdQuery(Guid ChatId) : IQuery<ChatDto?>;
public record GetChatByIdQuery(Guid UserId, Guid ChatId) : IQuery<ChatDto?>;
internal sealed class GetChatByIdQueryHandler : IQueryHandler<GetChatByIdQuery, ChatDto?>
{
@@ -31,6 +31,11 @@ internal sealed class GetChatByIdQueryHandler : IQueryHandler<GetChatByIdQuery,
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?>(new Error("Chats.Forbidden", "Вы не являетесь участником этого чата."));
}
var userIdsToFetch = new HashSet<Guid>();
foreach (var m in chat.Members) userIdsToFetch.Add(m.UserId);

View File

@@ -8,6 +8,8 @@ using Knot.Shared.Kernel;
using Knot.Modules.Chats.Application.DTOs;
using Knot.Modules.Chats.Domain;
using Knot.Modules.Chats.Application.Abstractions;
namespace Knot.Modules.Chats.Application.Messages.GetMessages;
public record GetMessagesQuery(Guid UserId, Guid ChatId, string? Cursor) : IQuery<List<MessageDetailDto>>;
@@ -16,15 +18,23 @@ internal sealed class GetMessagesQueryHandler : IQueryHandler<GetMessagesQuery,
{
private readonly IMessageRepository _messageRepository;
private readonly IUserDisplayNameProvider _userProvider;
private readonly IChatRepository _chatRepository;
public GetMessagesQueryHandler(IMessageRepository messageRepository, IUserDisplayNameProvider userProvider)
public GetMessagesQueryHandler(IMessageRepository messageRepository, IUserDisplayNameProvider userProvider, IChatRepository chatRepository)
{
_messageRepository = messageRepository;
_userProvider = userProvider;
_chatRepository = chatRepository;
}
public async Task<Result<List<MessageDetailDto>>> Handle(GetMessagesQuery request, CancellationToken cancellationToken)
{
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId))
{
return Result.Failure<List<MessageDetailDto>>(new Error("Chats.Forbidden", "Вы не являетесь участником этого чата."));
}
DateTime? cursorDate = null;
if (!string.IsNullOrEmpty(request.Cursor) && DateTime.TryParse(request.Cursor, null, System.Globalization.DateTimeStyles.RoundtripKind, out var parsed))
{

View File

@@ -9,6 +9,8 @@ using Knot.Shared.Kernel;
using Knot.Modules.Chats.Application.DTOs;
using Knot.Modules.Chats.Domain;
using Knot.Modules.Chats.Application.Abstractions;
namespace Knot.Modules.Chats.Application.Messages.GetSharedMedia;
public record GetSharedMediaQuery(Guid UserId, Guid ChatId, string? Type) : IQuery<List<SharedMediaDto>>;
@@ -17,15 +19,23 @@ internal sealed class GetSharedMediaQueryHandler : IQueryHandler<GetSharedMediaQ
{
private readonly IMessageRepository _messageRepository;
private readonly IUserDisplayNameProvider _userProvider;
private readonly IChatRepository _chatRepository;
public GetSharedMediaQueryHandler(IMessageRepository messageRepository, IUserDisplayNameProvider userProvider)
public GetSharedMediaQueryHandler(IMessageRepository messageRepository, IUserDisplayNameProvider userProvider, IChatRepository chatRepository)
{
_messageRepository = messageRepository;
_userProvider = userProvider;
_chatRepository = chatRepository;
}
public async Task<Result<List<SharedMediaDto>>> Handle(GetSharedMediaQuery request, CancellationToken cancellationToken)
{
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId))
{
return Result.Failure<List<SharedMediaDto>>(new Error("Chats.Forbidden", "Вы не являетесь участником этого чата."));
}
var messages = await _messageRepository.GetChatMessagesAsync(request.ChatId, 300, 0, cancellationToken);
messages = messages.Where(m => !m.IsDeleted && !m.DeletedByUsers.Contains(request.UserId)).ToList();

View File

@@ -25,7 +25,7 @@ internal sealed class SearchMessagesQueryHandler : IQueryHandler<SearchMessagesQ
public async Task<Result<List<SearchMessageDto>>> Handle(SearchMessagesQuery request, CancellationToken cancellationToken)
{
var messages = await _messageRepository.SearchMessagesAsync(request.Query, request.ChatId, cancellationToken);
var messages = await _messageRepository.SearchMessagesAsync(request.Query, request.ChatId, request.UserId, cancellationToken);
messages = messages.Where(m => !m.DeletedByUsers.Contains(request.UserId)).ToList();
var userIds = messages.Select(m => m.SenderId).ToList();

View File

@@ -47,8 +47,11 @@ public sealed class SendMessageCommandHandler : ICommandHandler<SendMessageComma
return Result.Failure<Guid>(new Error("Chats.NotFound", "Чат не найден."));
}
// 2. Проверяем, является ли отправитель участником (в будущем)
// if (!chat.Members.Any(m => m.UserId == request.SenderId)) ...
// 2. Проверяем, является ли отправитель участником
if (!chat.Members.Any(m => m.UserId == request.SenderId))
{
return Result.Failure<Guid>(new Error("Chats.Forbidden", "Вы не являетесь участником этого чата."));
}
// 3. Создаем сообщение
var message = Message.Create(

View File

@@ -7,7 +7,7 @@ public interface IMessageRepository
void Add(Message message);
Task<Message?> GetByIdAsync(Guid id, CancellationToken cancellationToken);
Task<List<Message>> GetChatMessagesAsync(Guid chatId, int limit, int offset, CancellationToken cancellationToken);
Task<List<Message>> SearchMessagesAsync(string query, Guid? chatId, CancellationToken cancellationToken);
Task<List<Message>> SearchMessagesAsync(string query, Guid? chatId, Guid requestingUserId, CancellationToken cancellationToken);
Task AddReadReceiptsAsync(Guid userId, List<Guid> messageIds, CancellationToken cancellationToken);
Task<bool> AddReactionAsync(Guid messageId, Guid userId, string emoji, CancellationToken cancellationToken);
Task<bool> RemoveReactionAsync(Guid messageId, Guid userId, string emoji, CancellationToken cancellationToken);

View File

@@ -58,6 +58,8 @@ public sealed class ChatsDbContext : DbContext, IChatsUnitOfWork
{
builder.ToTable("Messages");
builder.HasKey(m => m.Id);
builder.HasIndex(m => m.ChatId);
builder.HasIndex(m => new { m.ChatId, m.CreatedAt });
builder.Property(m => m.Content)
.HasConversion(

View File

@@ -58,9 +58,14 @@ public sealed class MessageRepository : IMessageRepository
.ToListAsync(cancellationToken);
}
public async Task<List<Message>> SearchMessagesAsync(string query, Guid? chatId, CancellationToken cancellationToken)
public async Task<List<Message>> SearchMessagesAsync(string query, Guid? chatId, Guid requestingUserId, CancellationToken cancellationToken)
{
var q = _dbContext.Messages.AsQueryable();
var validChatIdsQuery = _dbContext.Chats
.Where(c => c.Members.Any(m => m.UserId == requestingUserId))
.Select(c => c.Id);
var q = _dbContext.Messages.Where(m => validChatIdsQuery.Contains(m.ChatId));
if (chatId.HasValue)
{
q = q.Where(m => m.ChatId == chatId.Value);