Handler.cs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. using Application.Abstractions.Data;
  2. using Application.Abstractions.Messaging;
  3. using Domain.Entities.Donations.ValueObject;
  4. using Microsoft.EntityFrameworkCore;
  5. using SharedKernel.Results;
  6. using SharedKernel.Storage;
  7. namespace Application.Features.Api.ChannelTitle.UploadIcon;
  8. internal sealed class Handler(IAppDbContext db, IFileStorage fileStorage) : ICommandHandler<Command, Result<string>>
  9. {
  10. private static readonly string[] AllowedExtensions = [".gif", ".jpg", ".jpeg", ".png", ".webp"];
  11. private static readonly string[] AllowedContentTypes = ["image/gif", "image/jpeg", "image/png", "image/webp"];
  12. public async Task<Result<string>> Handle(Command r, CancellationToken ct)
  13. {
  14. if (r.File is null || r.File.Length == 0)
  15. {
  16. return Result.Failure<string>(Error.Problem("ChannelTitle.UploadIcon.Empty", "파일이 비어 있습니다."));
  17. }
  18. var maxSizeBytes = (long)DonationConstants.Title.MaxIconFileSizeMB * 1024 * 1024;
  19. if (r.File.Length > maxSizeBytes)
  20. {
  21. return Result.Failure<string>(Error.Problem("ChannelTitle.UploadIcon.FileTooLarge", $"파일 크기는 {DonationConstants.Title.MaxIconFileSizeMB}MB 이하여야 합니다."));
  22. }
  23. if (!string.IsNullOrEmpty(r.File.ContentType) && !AllowedContentTypes.Contains(r.File.ContentType.ToLowerInvariant()))
  24. {
  25. return Result.Failure<string>(Error.Problem("ChannelTitle.UploadIcon.InvalidType", "이미지 파일(gif, jpeg, png, webp)만 업로드할 수 있습니다."));
  26. }
  27. var channel = await db.Channel.AsNoTracking().FirstOrDefaultAsync(c => c.ID == r.ChannelID, ct);
  28. if (channel is null)
  29. {
  30. return Result.Failure<string>(Error.NotFound("ChannelTitle.UploadIcon.ChannelNotFound", "채널을 찾을 수 없습니다."));
  31. }
  32. if (channel.MemberID != r.MemberID)
  33. {
  34. return Result.Failure<string>(Error.Forbidden("ChannelTitle.UploadIcon.Forbidden", "본인 채널만 업로드할 수 있습니다."));
  35. }
  36. var path = new FileStoragePath(UploadTarget.Upload, UploadFolder.ChannelTitle, r.ChannelID);
  37. var result = await fileStorage.SaveFileAsync(r.File, path, AllowedExtensions, ct);
  38. if (result is null)
  39. {
  40. return Result.Failure<string>(Error.Problem("ChannelTitle.UploadIcon.Failed", "파일 업로드에 실패했습니다. 허용된 확장자(gif, jpeg, png, webp)인지 확인하세요."));
  41. }
  42. return Result.Success(result.Url);
  43. }
  44. }