Мелкий рефактор
This commit is contained in:
@@ -1,6 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*.cs]
|
||||
csharp_prefer_braces = true:warning
|
||||
csharp_style_namespace_declarations = file_scoped:warning
|
||||
dotnet_diagnostic.IDE0011.severity = warning
|
||||
@@ -28,11 +28,11 @@ internal sealed class ResetUserPasswordCommandHandler : ICommandHandler<ResetUse
|
||||
var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return Result.Failure<SuccessResponse>(new Error("User.NotFound", "User not found"));
|
||||
return Result.Failure<SuccessResponse>(IdentityErrors.UserNotFound);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(request.NewPassword))
|
||||
return Result.Failure<SuccessResponse>(new Error("InvalidPassword", "Password cannot be empty"));
|
||||
return Result.Failure<SuccessResponse>(DomainErrors.InvalidPassword);
|
||||
|
||||
var hash = BCrypt.Net.BCrypt.HashPassword(request.NewPassword);
|
||||
user.ChangePassword(hash);
|
||||
|
||||
@@ -29,7 +29,7 @@ internal sealed class GetUserDetailsQueryHandler : IQueryHandler<GetUserDetailsQ
|
||||
var targetUser = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (targetUser == null)
|
||||
{
|
||||
return Result.Failure<AdminUserDetailsDto>(new Error("User.NotFound", "User not found"));
|
||||
return Result.Failure<AdminUserDetailsDto>(IdentityErrors.UserNotFound);
|
||||
}
|
||||
|
||||
var messagesCount = await _chatsDbContext.Messages.CountAsync(m => m.SenderId == request.UserId, cancellationToken);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Host.Application.Stories;
|
||||
using Knot.Shared.Kernel;
|
||||
using Knot.Shared.Kernel.Configuration;
|
||||
using Knot.Shared.Kernel.Constants;
|
||||
@@ -31,11 +32,11 @@ internal sealed class HandshakeFederationCommandHandler : ICommandHandler<Handsh
|
||||
return Task.FromResult(Result.Failure<HandshakeResponse>(new Error(Errors.DisabledByAdmin, "Federation is disabled")));
|
||||
|
||||
if (string.IsNullOrEmpty(request.Request.Domain) || string.IsNullOrEmpty(request.Request.PublicKey))
|
||||
return Task.FromResult(Result.Failure<HandshakeResponse>(new Error("Request.Invalid", "Domain and PublicKey are required")));
|
||||
return Task.FromResult(Result.Failure<HandshakeResponse>(DomainErrors.RequestInvalid));
|
||||
|
||||
var allowedList = conf.AllowedDomains?.Select(d => d.Trim().ToLower()).ToList() ?? new System.Collections.Generic.List<string>();
|
||||
if (!allowedList.Contains(request.Request.Domain.ToLowerInvariant()))
|
||||
return Task.FromResult(Result.Failure<HandshakeResponse>(new Error("Unauthorized", "Domain is not in the whitelist")));
|
||||
return Task.FromResult(Result.Failure<HandshakeResponse>(StoryErrors.Unauthorized));
|
||||
|
||||
using var rsa = RSA.Create(2048);
|
||||
var selfPublicKey = Convert.ToBase64String(rsa.ExportRSAPublicKey());
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Host.Application.Stories;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -49,7 +50,7 @@ internal sealed class AddStoryReactionCommandHandler : ICommandHandler<AddStoryR
|
||||
var story = await _context.Stories.FindAsync(new object[] { request.StoryId }, cancellationToken);
|
||||
if (story == null)
|
||||
{
|
||||
return Result.Failure<MessageResponse>(new Error("Story.NotFound", "Story not found"));
|
||||
return Result.Failure<MessageResponse>(StoryErrors.StoryNotFound);
|
||||
}
|
||||
|
||||
var existing = await _context.StoryReactions
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Host.Application.Stories;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -49,7 +50,7 @@ internal sealed class AddStoryReplyCommandHandler : ICommandHandler<AddStoryRepl
|
||||
var story = await _context.Stories.FindAsync(new object[] { request.StoryId }, cancellationToken);
|
||||
if (story == null)
|
||||
{
|
||||
return Result.Failure<MessageResponse>(new Error("Story.NotFound", "Story not found"));
|
||||
return Result.Failure<MessageResponse>(StoryErrors.StoryNotFound);
|
||||
}
|
||||
|
||||
var reply = new StoryReply(request.StoryId, request.UserId, request.Content);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Host.Application.Stories;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -24,11 +25,11 @@ internal sealed class DeleteStoryCommandHandler : ICommandHandler<DeleteStoryCom
|
||||
var story = await _context.Stories.FindAsync(new object[] { request.StoryId }, cancellationToken);
|
||||
if (story == null)
|
||||
{
|
||||
return Result.Failure<MessageResponse>(new Error("Story.NotFound", "Story not found"));
|
||||
return Result.Failure<MessageResponse>(StoryErrors.StoryNotFound);
|
||||
}
|
||||
if (story.UserId != request.UserId)
|
||||
{
|
||||
return Result.Failure<MessageResponse>(new Error("Unauthorized", "Unauthorized"));
|
||||
return Result.Failure<MessageResponse>(StoryErrors.Unauthorized);
|
||||
}
|
||||
|
||||
_context.Stories.Remove(story);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Host.Application.Stories;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
@@ -38,7 +39,7 @@ internal sealed class ViewStoryCommandHandler : ICommandHandler<ViewStoryCommand
|
||||
|
||||
if (story == null)
|
||||
{
|
||||
return Result.Failure<MessageResponse>(new Error("Story.NotFound", "Story not found"));
|
||||
return Result.Failure<MessageResponse>(StoryErrors.StoryNotFound);
|
||||
}
|
||||
|
||||
if (story.UserId == request.UserId)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Host.Application.Stories;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -33,11 +34,11 @@ internal sealed class GetStoryRepliesQueryHandler : IQueryHandler<GetStoryReplie
|
||||
|
||||
if (story == null)
|
||||
{
|
||||
return Result.Failure<List<StoryReplyDto>>(new Error("Story.NotFound", "Story not found"));
|
||||
return Result.Failure<List<StoryReplyDto>>(StoryErrors.StoryNotFound);
|
||||
}
|
||||
if (story.UserId != request.UserId)
|
||||
{
|
||||
return Result.Failure<List<StoryReplyDto>>(new Error("Unauthorized", "Unauthorized"));
|
||||
return Result.Failure<List<StoryReplyDto>>(StoryErrors.Unauthorized);
|
||||
}
|
||||
|
||||
var replies = new List<StoryReplyDto>();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Host.Application.Stories;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -33,11 +34,11 @@ internal sealed class GetStoryViewersQueryHandler : IQueryHandler<GetStoryViewer
|
||||
|
||||
if (story == null)
|
||||
{
|
||||
return Result.Failure<List<StoryViewerDto>>(new Error("Story.NotFound", "Story not found"));
|
||||
return Result.Failure<List<StoryViewerDto>>(StoryErrors.StoryNotFound);
|
||||
}
|
||||
if (story.UserId != request.UserId)
|
||||
{
|
||||
return Result.Failure<List<StoryViewerDto>>(new Error("Unauthorized", "Unauthorized"));
|
||||
return Result.Failure<List<StoryViewerDto>>(StoryErrors.Unauthorized);
|
||||
}
|
||||
|
||||
var viewerIds = story.Viewers.Select(v => v.UserId).ToList();
|
||||
|
||||
@@ -39,7 +39,7 @@ internal sealed class GetUserStoriesQueryHandler : IQueryHandler<GetUserStoriesQ
|
||||
var user = await _userRepository.GetByIdAsync(request.TargetUserId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return Result.Failure<StoryGroupDto>(new Error("User.NotFound", "User not found"));
|
||||
return Result.Failure<StoryGroupDto>(IdentityErrors.UserNotFound);
|
||||
}
|
||||
|
||||
var result = new StoryGroupDto(
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Knot.Shared.Kernel;
|
||||
|
||||
namespace Host.Application.Stories;
|
||||
|
||||
public static class StoryErrors
|
||||
{
|
||||
public static readonly Error Unauthorized = new Error("Unauthorized", "Access denied");
|
||||
public static readonly Error StoryNotFound = new Error("Story.NotFound", "Story not found");
|
||||
}
|
||||
@@ -33,7 +33,7 @@ internal sealed class UploadGroupAvatarCommandHandler : ICommandHandler<UploadGr
|
||||
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
|
||||
if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId))
|
||||
{
|
||||
return Result.Failure<Guid>(new Error("Chat.NotFound", "Chat not found or access denied"));
|
||||
return Result.Failure<Guid>(ChatErrors.ChatNotFound);
|
||||
}
|
||||
|
||||
var fileId = await _fileStorage.UploadFileAsync(request.FileStream, request.FileName, request.ContentType);
|
||||
@@ -67,7 +67,7 @@ internal sealed class CropGroupAvatarCommandHandler : ICommandHandler<CropGroupA
|
||||
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
|
||||
if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId))
|
||||
{
|
||||
return Result.Failure<Guid>(new Error("Chat.NotFound", "Chat not found or access denied"));
|
||||
return Result.Failure<Guid>(ChatErrors.ChatNotFound);
|
||||
}
|
||||
|
||||
string url;
|
||||
@@ -117,7 +117,7 @@ internal sealed class RemoveGroupAvatarCommandHandler : ICommandHandler<RemoveGr
|
||||
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
|
||||
if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId))
|
||||
{
|
||||
return Result.Failure<Guid>(new Error("Chat.NotFound", "Chat not found or access denied"));
|
||||
return Result.Failure<Guid>(ChatErrors.ChatNotFound);
|
||||
}
|
||||
|
||||
chat.UpdateAvatar(null);
|
||||
|
||||
@@ -25,7 +25,7 @@ internal sealed class ClearChatCommandHandler : ICommandHandler<ClearChatCommand
|
||||
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
|
||||
if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId))
|
||||
{
|
||||
return Result.Failure<MessageResponse>(new Error("Chat.NotFound", "Chat not found or access denied"));
|
||||
return Result.Failure<MessageResponse>(ChatErrors.ChatNotFound);
|
||||
}
|
||||
|
||||
// Currently a placeholder
|
||||
|
||||
@@ -36,7 +36,7 @@ internal sealed class GetChatByIdQueryHandler : IQueryHandler<GetChatByIdQuery,
|
||||
|
||||
if (!chat.Members.Any(m => m.UserId == request.UserId))
|
||||
{
|
||||
return Result.Failure<ChatDto?>(new Error("Chats.Forbidden", "Вы не являетесь участником этого чата."));
|
||||
return Result.Failure<ChatDto?>(ChatErrors.ChatsForbidden);
|
||||
}
|
||||
|
||||
var userIdsToFetch = new HashSet<Guid>();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -32,7 +33,7 @@ internal sealed class LeaveOrDeleteChatCommandHandler : ICommandHandler<LeaveOrD
|
||||
|
||||
if (!chat.Members.Any(m => m.UserId == request.UserId))
|
||||
{
|
||||
return Result.Failure<SuccessResponse>(new Error("Unauthorized", "Access denied"));
|
||||
return Result.Failure<SuccessResponse>(ChatErrors.Unauthorized);
|
||||
}
|
||||
|
||||
if (chat.Type == ChatType.Group)
|
||||
|
||||
@@ -28,7 +28,7 @@ internal sealed class AddMembersCommandHandler : ICommandHandler<AddMembersComma
|
||||
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
|
||||
if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId))
|
||||
{
|
||||
return Result.Failure<Guid>(new Error("Chat.NotFound", "Chat not found or access denied"));
|
||||
return Result.Failure<Guid>(ChatErrors.ChatNotFound);
|
||||
}
|
||||
|
||||
foreach (var userId in request.UserIdsToAdd)
|
||||
@@ -60,7 +60,7 @@ internal sealed class RemoveMemberCommandHandler : ICommandHandler<RemoveMemberC
|
||||
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
|
||||
if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId))
|
||||
{
|
||||
return Result.Failure<Guid>(new Error("Chat.NotFound", "Chat not found or access denied"));
|
||||
return Result.Failure<Guid>(ChatErrors.ChatNotFound);
|
||||
}
|
||||
|
||||
chat.RemoveMember(request.UserIdToRemove);
|
||||
|
||||
@@ -28,13 +28,13 @@ internal sealed class TogglePinCommandHandler : ICommandHandler<TogglePinCommand
|
||||
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
|
||||
if (chat == null)
|
||||
{
|
||||
return Result.Failure<TogglePinResponse>(new Error("Chat.NotFound", "Chat not found"));
|
||||
return Result.Failure<TogglePinResponse>(ChatErrors.ChatNotFound);
|
||||
}
|
||||
|
||||
var member = chat.Members.FirstOrDefault(m => m.UserId == request.UserId);
|
||||
if (member == null)
|
||||
{
|
||||
return Result.Failure<TogglePinResponse>(new Error("Chat.NotFound", "Member not found"));
|
||||
return Result.Failure<TogglePinResponse>(ChatErrors.ChatNotFound);
|
||||
}
|
||||
|
||||
member.TogglePin();
|
||||
|
||||
@@ -27,7 +27,7 @@ internal sealed class UpdateChatCommandHandler : ICommandHandler<UpdateChatComma
|
||||
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
|
||||
if (chat == null || !chat.Members.Any(m => m.UserId == request.UserId))
|
||||
{
|
||||
return Result.Failure<Guid>(new Error("Chat.NotFound", "Chat not found or access denied"));
|
||||
return Result.Failure<Guid>(ChatErrors.ChatNotFound);
|
||||
}
|
||||
|
||||
if (request.Name != null)
|
||||
|
||||
@@ -32,7 +32,7 @@ internal sealed class GetMessagesQueryHandler : IQueryHandler<GetMessagesQuery,
|
||||
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", "Вы не являетесь участником этого чата."));
|
||||
return Result.Failure<List<MessageDetailDto>>(ChatErrors.ChatsForbidden);
|
||||
}
|
||||
|
||||
DateTime? cursorDate = null;
|
||||
@@ -41,7 +41,7 @@ internal sealed class GetMessagesQueryHandler : IQueryHandler<GetMessagesQuery,
|
||||
cursorDate = parsed.ToUniversalTime();
|
||||
}
|
||||
|
||||
var messages = await _messageRepository.GetChatMessagesCursorAsync(request.ChatId, cursorDate, 100, cancellationToken);
|
||||
var messages = await _messageRepository.GetChatMessagesCursorAsync(request.ChatId, cursorDate, ChatConstants.DefaultMessageQueryLimit, cancellationToken);
|
||||
var result = new List<MessageDetailDto>();
|
||||
|
||||
var userIdsToFetch = new HashSet<Guid>();
|
||||
|
||||
@@ -33,10 +33,10 @@ internal sealed class GetSharedMediaQueryHandler : IQueryHandler<GetSharedMediaQ
|
||||
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", "Вы не являетесь участником этого чата."));
|
||||
return Result.Failure<List<SharedMediaDto>>(ChatErrors.ChatsForbidden);
|
||||
}
|
||||
|
||||
var messages = await _messageRepository.GetChatMessagesAsync(request.ChatId, 300, 0, cancellationToken);
|
||||
var messages = await _messageRepository.GetChatMessagesAsync(request.ChatId, ChatConstants.MaxSharedMediaQueryLimit, 0, cancellationToken);
|
||||
messages = messages.Where(m => !m.IsDeleted && !m.DeletedByUsers.Contains(request.UserId)).ToList();
|
||||
|
||||
var result = new List<SharedMediaDto>();
|
||||
|
||||
@@ -57,7 +57,7 @@ public sealed class AddReactionCommandHandler : ICommandHandler<AddReactionComma
|
||||
if (!success)
|
||||
{
|
||||
_logger.LogWarning("AddReaction: Message not found {MessageId}", request.MessageId);
|
||||
return Result.Failure(new Error("Messages.NotFound", "Message not found."));
|
||||
return Result.Failure(ChatErrors.MessagesNotFound);
|
||||
}
|
||||
|
||||
await _unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
|
||||
@@ -44,13 +44,13 @@ public sealed class SendMessageCommandHandler : ICommandHandler<SendMessageComma
|
||||
var chat = await _chatRepository.GetByIdAsync(request.ChatId, cancellationToken);
|
||||
if (chat is null)
|
||||
{
|
||||
return Result.Failure<Guid>(new Error("Chats.NotFound", "Чат не найден."));
|
||||
return Result.Failure<Guid>(ChatErrors.ChatsNotFound);
|
||||
}
|
||||
|
||||
// 2. Проверяем, является ли отправитель участником
|
||||
if (!chat.Members.Any(m => m.UserId == request.SenderId))
|
||||
{
|
||||
return Result.Failure<Guid>(new Error("Chats.Forbidden", "Вы не являетесь участником этого чата."));
|
||||
return Result.Failure<Guid>(ChatErrors.ChatsForbidden);
|
||||
}
|
||||
|
||||
// 3. Создаем сообщение
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Knot.Modules.Chats.Domain;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -27,13 +28,13 @@ internal sealed class UploadFileCommandHandler : ICommandHandler<UploadFileComma
|
||||
{
|
||||
if (request.Length == 0)
|
||||
{
|
||||
return Result.Failure<UploadFileResponseDto>(new Error("File.Empty", "No file uploaded"));
|
||||
return Result.Failure<UploadFileResponseDto>(ChatErrors.FileEmpty);
|
||||
}
|
||||
|
||||
var maxMb = _settingsService.Current.MaxFileSizeMb;
|
||||
if (request.Length > maxMb * 1024 * 1024)
|
||||
{
|
||||
return Result.Failure<UploadFileResponseDto>(new Error("File.TooLarge", $"File exceeds the maximum allowed size of {maxMb}MB."));
|
||||
return Result.Failure<UploadFileResponseDto>(ChatErrors.FileTooLarge(maxMb));
|
||||
}
|
||||
|
||||
var fileId = await _fileStorage.UploadFileAsync(request.FileStream, request.FileName, request.ContentType);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Knot.Modules.Chats.Domain;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@@ -28,12 +29,12 @@ internal sealed class AnalyzeImportCommandHandler : ICommandHandler<AnalyzeImpor
|
||||
{
|
||||
if (request.FileStream == null || request.FileStream.Length == 0)
|
||||
{
|
||||
return Result.Failure<AnalyzeImportResponseDto>(new Error("File.Empty", "No file uploaded"));
|
||||
return Result.Failure<AnalyzeImportResponseDto>(ChatErrors.FileEmpty);
|
||||
}
|
||||
|
||||
if (!request.FileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return Result.Failure<AnalyzeImportResponseDto>(new Error("File.InvalidExtension", "Must be a ZIP archive"));
|
||||
return Result.Failure<AnalyzeImportResponseDto>(ChatErrors.FileInvalidExtension);
|
||||
}
|
||||
|
||||
var token = Guid.NewGuid();
|
||||
|
||||
@@ -56,12 +56,12 @@ internal sealed class ExecuteImportCommandHandler : ICommandHandler<ExecuteImpor
|
||||
{
|
||||
if (!TelegramImportState.TempZips.TryGetValue(request.Token, out var tempPath))
|
||||
{
|
||||
return Result.Failure<ExecuteImportResponseDto>(new Error("Import.Expired", "Session not found or expired"));
|
||||
return Result.Failure<ExecuteImportResponseDto>(ChatErrors.ImportExpired);
|
||||
}
|
||||
|
||||
if (!System.IO.File.Exists(tempPath))
|
||||
{
|
||||
return Result.Failure<ExecuteImportResponseDto>(new Error("Import.Missing", "ZIP file lost"));
|
||||
return Result.Failure<ExecuteImportResponseDto>(ChatErrors.ImportMissing);
|
||||
}
|
||||
|
||||
var myId = request.CurrentUserId;
|
||||
@@ -95,7 +95,7 @@ internal sealed class ExecuteImportCommandHandler : ICommandHandler<ExecuteImpor
|
||||
var res = await _sender.Send(command, cancellationToken);
|
||||
if (res.IsFailure)
|
||||
{
|
||||
return Result.Failure<ExecuteImportResponseDto>(new Error("Import.CreateChatFailed", res.Error.Description ?? res.Error.Code));
|
||||
return Result.Failure<ExecuteImportResponseDto>(ChatErrors.ImportCreateChatFailed(res.Error.Description ?? res.Error.Code));
|
||||
}
|
||||
|
||||
chatId = res.Value;
|
||||
@@ -107,7 +107,7 @@ internal sealed class ExecuteImportCommandHandler : ICommandHandler<ExecuteImpor
|
||||
var res = await _sender.Send(command, cancellationToken);
|
||||
if (res.IsFailure)
|
||||
{
|
||||
return Result.Failure<ExecuteImportResponseDto>(new Error("Import.CreateChatFailed", res.Error.Description ?? res.Error.Code));
|
||||
return Result.Failure<ExecuteImportResponseDto>(ChatErrors.ImportCreateChatFailed(res.Error.Description ?? res.Error.Code));
|
||||
}
|
||||
|
||||
chatId = res.Value;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Knot.Modules.Chats.Domain;
|
||||
|
||||
public static class ChatConstants
|
||||
{
|
||||
public const int DefaultMessageQueryLimit = 100;
|
||||
public const int MaxSharedMediaQueryLimit = 300;
|
||||
public const int SearchMessagesLimit = 50;
|
||||
public const int MaxFileUploadSizeMb = 50;
|
||||
}
|
||||
19
apps/server-net/src/Modules/Chats/Domain/ChatErrors.cs
Normal file
19
apps/server-net/src/Modules/Chats/Domain/ChatErrors.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Knot.Shared.Kernel;
|
||||
|
||||
namespace Knot.Modules.Chats.Domain;
|
||||
|
||||
public static class ChatErrors
|
||||
{
|
||||
public static readonly Error FileEmpty = new Error("File.Empty", "No file uploaded");
|
||||
public static readonly Error FileInvalidExtension = new Error("File.InvalidExtension", "Must be a ZIP archive");
|
||||
public static readonly Error ImportExpired = new Error("Import.Expired", "Session not found or expired");
|
||||
public static readonly Error ImportMissing = new Error("Import.Missing", "ZIP file lost");
|
||||
public static readonly Error ChatNotFound = new Error("Chat.NotFound", "Chat not found or access denied");
|
||||
public static readonly Error ChatsForbidden = new Error("Chats.Forbidden", "Вы не являетесь участником этого чата.");
|
||||
public static readonly Error MessagesNotFound = new Error("Messages.NotFound", "Message not found.");
|
||||
public static readonly Error ChatsNotFound = new Error("Chats.NotFound", "Чат не найден.");
|
||||
public static readonly Error Unauthorized = new Error("Chats.Unauthorized", "Access denied");
|
||||
|
||||
public static Error ImportCreateChatFailed(string msg) => new Error("Import.CreateChatFailed", msg);
|
||||
public static Error FileTooLarge(int maxMb) => new Error("File.TooLarge", $"File exceeds the maximum allowed size of {maxMb}MB.");
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public sealed class MessageRepository : IMessageRepository
|
||||
|
||||
return await q.Where(m => m.Content != null && m.Content.Contains(query))
|
||||
.OrderByDescending(m => m.CreatedAt)
|
||||
.Take(50)
|
||||
.Take(ChatConstants.SearchMessagesLimit)
|
||||
.Include(m => m.Media)
|
||||
.Include(m => m.ReadBy)
|
||||
.Include(m => m.Reactions)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Knot.Modules.Identity.Domain;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -24,7 +25,7 @@ internal sealed class AcceptFriendRequestCommandHandler : ICommandHandler<Accept
|
||||
var friendship = await _context.Friendships.FindAsync(new object[] { request.FriendshipId }, cancellationToken);
|
||||
if (friendship == null || friendship.FriendId != request.UserId)
|
||||
{
|
||||
return Result.Failure<Guid>(new Error("Friends.NotFound", "Request not found"));
|
||||
return Result.Failure<Guid>(IdentityErrors.FriendsNotFound);
|
||||
}
|
||||
|
||||
friendship.Accept();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Knot.Modules.Identity.Domain;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -24,7 +25,7 @@ internal sealed class DeclineFriendRequestCommandHandler : ICommandHandler<Decli
|
||||
var friendship = await _context.Friendships.FindAsync(new object[] { request.FriendshipId }, cancellationToken);
|
||||
if (friendship == null || friendship.FriendId != request.UserId)
|
||||
{
|
||||
return Result.Failure(new Error("Friends.NotFound", "Request not found"));
|
||||
return Result.Failure(IdentityErrors.FriendsNotFound);
|
||||
}
|
||||
|
||||
friendship.Decline();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Knot.Modules.Identity.Domain;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -24,7 +25,7 @@ internal sealed class RemoveFriendCommandHandler : ICommandHandler<RemoveFriendC
|
||||
var friendship = await _context.Friendships.FindAsync(new object[] { request.FriendshipId }, cancellationToken);
|
||||
if (friendship == null || (friendship.UserId != request.UserId && friendship.FriendId != request.UserId))
|
||||
{
|
||||
return Result.Failure(new Error("Friends.NotFound", "Friendship not found"));
|
||||
return Result.Failure(IdentityErrors.FriendsNotFound);
|
||||
}
|
||||
|
||||
_context.Friendships.Remove(friendship);
|
||||
|
||||
@@ -25,7 +25,7 @@ internal sealed class SendFriendRequestCommandHandler : ICommandHandler<SendFrie
|
||||
{
|
||||
if (request.UserId == request.FriendId)
|
||||
{
|
||||
return Result.Failure(new Error("Friends.Self", "Cannot add yourself"));
|
||||
return Result.Failure(IdentityErrors.FriendsSelf);
|
||||
}
|
||||
|
||||
var existing = await _context.Friendships
|
||||
@@ -34,7 +34,7 @@ internal sealed class SendFriendRequestCommandHandler : ICommandHandler<SendFrie
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
return Result.Failure(new Error("Friends.Exists", "Friendship already exists"));
|
||||
return Result.Failure(IdentityErrors.FriendsExists);
|
||||
}
|
||||
|
||||
var friendship = Friendship.Create(request.UserId, request.FriendId);
|
||||
|
||||
@@ -27,7 +27,7 @@ internal sealed class CropAvatarCommandHandler : ICommandHandler<CropAvatarComma
|
||||
var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return Result.Failure<UserProfileDto>(new Error("User.NotFound", "User not found"));
|
||||
return Result.Failure<UserProfileDto>(IdentityErrors.UserNotFound);
|
||||
}
|
||||
|
||||
string avatarUrl;
|
||||
|
||||
@@ -22,7 +22,7 @@ internal sealed class DeleteAvatarCommandHandler : ICommandHandler<DeleteAvatarC
|
||||
var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return Result.Failure<UserProfileDto>(new Error("User.NotFound", "User not found"));
|
||||
return Result.Failure<UserProfileDto>(IdentityErrors.UserNotFound);
|
||||
}
|
||||
|
||||
user.UpdateAvatar(null);
|
||||
|
||||
@@ -25,7 +25,7 @@ internal sealed class UploadAvatarCommandHandler : ICommandHandler<UploadAvatarC
|
||||
var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return Result.Failure<UserProfileDto>(new Error("User.NotFound", "User not found"));
|
||||
return Result.Failure<UserProfileDto>(IdentityErrors.UserNotFound);
|
||||
}
|
||||
|
||||
var fileId = await _fileStorage.UploadFileAsync(request.FileStream, request.FileName, request.ContentType);
|
||||
|
||||
@@ -21,7 +21,7 @@ internal sealed class GetMeQueryHandler : IQueryHandler<GetMeQuery, AuthResponse
|
||||
var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return Result.Failure<AuthResponseDto>(new Error("User.NotFound", "User not found"));
|
||||
return Result.Failure<AuthResponseDto>(IdentityErrors.UserNotFound);
|
||||
}
|
||||
|
||||
var response = new AuthResponseDto(
|
||||
|
||||
@@ -20,7 +20,7 @@ internal sealed class GetUserQueryHandler : IQueryHandler<GetUserQuery, UserProf
|
||||
var user = await _userRepository.GetByIdAsync(request.Id, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return Result.Failure<UserProfileDto>(new Error("User.NotFound", "User not found"));
|
||||
return Result.Failure<UserProfileDto>(IdentityErrors.UserNotFound);
|
||||
}
|
||||
|
||||
var dto = new UserProfileDto(
|
||||
|
||||
@@ -28,7 +28,7 @@ public sealed class LoginUserCommandHandler : ICommandHandler<LoginUserCommand,
|
||||
|
||||
if (user is null || !BCrypt.Net.BCrypt.Verify(request.Password, user.PasswordHash))
|
||||
{
|
||||
return Result.Failure<AuthResponseDto>(new Error("Identity.InvalidCredentials", "Неверное имя пользователя или пароль."));
|
||||
return Result.Failure<AuthResponseDto>(IdentityErrors.IdentityInvalidCredentials);
|
||||
}
|
||||
|
||||
string token = _tokenProvider.Generate(user);
|
||||
|
||||
@@ -43,13 +43,13 @@ public sealed class RegisterUserCommandHandler : ICommandHandler<RegisterUserCom
|
||||
{
|
||||
if (!_settings.Current.EnableRegistration)
|
||||
{
|
||||
return Result.Failure<AuthResponseDto>(new Error("Identity.RegistrationDisabled", "Registration is disabled by the administrator."));
|
||||
return Result.Failure<AuthResponseDto>(IdentityErrors.IdentityRegistrationDisabled);
|
||||
}
|
||||
|
||||
// 1. Проверка уникальности username
|
||||
if (!await _userRepository.IsUsernameUniqueAsync(request.Username, cancellationToken))
|
||||
{
|
||||
return Result.Failure<AuthResponseDto>(new Error("Identity.UsernameNotUnique", "Это имя пользователя уже занято."));
|
||||
return Result.Failure<AuthResponseDto>(IdentityErrors.IdentityUsernameNotUnique);
|
||||
}
|
||||
|
||||
// 2. Хеширование пароля (здесь будет вызов сервиса, пока заглушка)
|
||||
|
||||
@@ -22,7 +22,7 @@ internal sealed class UpdateProfileCommandHandler : ICommandHandler<UpdateProfil
|
||||
var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return Result.Failure<UserProfileDto>(new Error("User.NotFound", "User not found"));
|
||||
return Result.Failure<UserProfileDto>(IdentityErrors.UserNotFound);
|
||||
}
|
||||
|
||||
user.UpdateProfile(request.DisplayName ?? user.DisplayName, request.Bio, request.Birthday);
|
||||
|
||||
@@ -22,7 +22,7 @@ internal sealed class UpdateSettingsCommandHandler : ICommandHandler<UpdateSetti
|
||||
var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
return Result.Failure<UserProfileDto>(new Error("User.NotFound", "User not found"));
|
||||
return Result.Failure<UserProfileDto>(IdentityErrors.UserNotFound);
|
||||
}
|
||||
|
||||
user.UpdateSettings(request.HideStoryViews ?? user.HideStoryViews);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using Knot.Shared.Kernel;
|
||||
|
||||
namespace Knot.Modules.Identity.Domain;
|
||||
|
||||
public static class IdentityErrors
|
||||
{
|
||||
public static readonly Error FriendsNotFound = new Error("Friends.NotFound", "Friendship not found");
|
||||
public static readonly Error FriendsSelf = new Error("Friends.Self", "Cannot add yourself");
|
||||
public static readonly Error FriendsExists = new Error("Friends.Exists", "Friendship already exists");
|
||||
public static readonly Error UserNotFound = new Error("User.NotFound", "User not found");
|
||||
public static readonly Error IdentityInvalidCredentials = new Error("Identity.InvalidCredentials", "Неверное имя пользователя или пароль.");
|
||||
public static readonly Error IdentityRegistrationDisabled = new Error("Identity.RegistrationDisabled", "Registration is disabled by the administrator.");
|
||||
public static readonly Error IdentityUsernameNotUnique = new Error("Identity.UsernameNotUnique", "Это имя пользователя уже занято.");
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Knot.Shared.Kernel;
|
||||
|
||||
public static class DomainErrors
|
||||
{
|
||||
public static readonly Error InvalidPassword = new Error("Admin.InvalidPassword", "Пароль не должен быть пустым.");
|
||||
public static readonly Error RequestInvalid = new Error("Request.Invalid", "Invalid federation request");
|
||||
}
|
||||
Reference in New Issue
Block a user