Handler.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using Application.Abstractions.Messaging;
  2. using Application.Abstractions.Data;
  3. using SharedKernel.Storage;
  4. using Microsoft.EntityFrameworkCore;
  5. namespace Application.Features.Admin.Forum.Post.Create;
  6. public sealed class Handler(IAppDbContext db, IFileStorage fileStorage) : ICommandHandler<Command>
  7. {
  8. private static readonly string[] AllowedImageExtensions = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"];
  9. private static readonly string[] AllowedFileExtensions = [".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp", ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt", ".zip", ".rar", ".7z", ".hwp", ".hwpx", ".csv"];
  10. public async Task Handle(Command request, CancellationToken ct)
  11. {
  12. if (!await db.Board.AnyAsync(x => x.ID == request.BoardID, ct))
  13. {
  14. throw new KeyNotFoundException("게시판을 찾을 수 없습니다.");
  15. }
  16. var post = new Domain.Entities.Forum.Posts.Post
  17. {
  18. BoardID = request.BoardID,
  19. BoardPrefixID = request.BoardPrefixID,
  20. MemberID = null,
  21. Subject = request.Subject,
  22. Content = request.Content ?? string.Empty,
  23. IsNotice = request.IsNotice,
  24. IsSecret = request.IsSecret,
  25. IsAnonymous = request.IsAnonymous,
  26. Name = "관리자"
  27. };
  28. await db.Post.AddAsync(post, ct);
  29. await db.SaveChangesAsync(ct);
  30. var uploadPath = new FileStoragePath(UploadTarget.Upload, UploadFolder.Post, post.ID);
  31. // 썸네일 처리
  32. if (request.ThumbnailFile is not null)
  33. {
  34. var result = await fileStorage.SaveFileAsync(request.ThumbnailFile, uploadPath, AllowedImageExtensions, ct);
  35. post.Thumbnail = result?.Url;
  36. }
  37. // 파일 처리
  38. if (request.Files is { Count: > 0 })
  39. {
  40. byte fileCount = 0;
  41. foreach (var file in request.Files)
  42. {
  43. var result = await fileStorage.SaveFileAsync(file, uploadPath, AllowedFileExtensions, ct);
  44. if (result is not null)
  45. {
  46. var ext = Path.GetExtension(file.FileName).ToLowerInvariant();
  47. await db.PostFile.AddAsync(new Domain.Entities.Forum.Posts.PostFile
  48. {
  49. BoardID = request.BoardID,
  50. PostID = post.ID,
  51. UUID = Guid.NewGuid(),
  52. FileName = file.FileName,
  53. HashedName = result.FileName,
  54. Path = uploadPath.ToRelativePath(),
  55. Url = result.Url,
  56. Extension = ext,
  57. ContentType = file.ContentType,
  58. Size = result.Size
  59. }, ct);
  60. fileCount++;
  61. }
  62. }
  63. post.Files = fileCount;
  64. }
  65. // 태그 처리
  66. if (request.Tags is { Count: > 0 })
  67. {
  68. byte tagCount = 0;
  69. foreach (var tagName in request.Tags)
  70. {
  71. if (string.IsNullOrWhiteSpace(tagName))
  72. {
  73. continue;
  74. }
  75. var name = tagName.Trim();
  76. var slug = name.ToLowerInvariant().Replace(' ', '-');
  77. var tag = await db.Tag.FirstOrDefaultAsync(x => x.Name == name, ct);
  78. if (tag is null)
  79. {
  80. tag = new Domain.Entities.Forum.Posts.Tag
  81. {
  82. Name = name,
  83. Slug = slug
  84. };
  85. await db.Tag.AddAsync(tag, ct);
  86. await db.SaveChangesAsync(ct);
  87. }
  88. tag.UsageCount++;
  89. tag.UpdatedAt = DateTime.UtcNow;
  90. await db.PostTag.AddAsync(new Domain.Entities.Forum.Posts.PostTag
  91. {
  92. BoardID = request.BoardID,
  93. PostID = post.ID,
  94. TagID = tag.ID
  95. }, ct);
  96. tagCount++;
  97. }
  98. post.Tags = tagCount;
  99. }
  100. await db.SaveChangesAsync(ct);
  101. // Board 게시글 카운트 증가
  102. var board = await db.Board.FirstOrDefaultAsync(x => x.ID == request.BoardID, ct);
  103. if (board is not null)
  104. {
  105. board.Posts++;
  106. board.UpdatedAt = DateTime.UtcNow;
  107. // BoardGroup 게시글 카운트 증가
  108. var boardGroup = await db.BoardGroup.FirstOrDefaultAsync(x => x.ID == board.BoardGroupID, ct);
  109. if (boardGroup is not null)
  110. {
  111. boardGroup.Posts++;
  112. boardGroup.UpdatedAt = DateTime.UtcNow;
  113. }
  114. await db.SaveChangesAsync(ct);
  115. }
  116. }
  117. }