BoardSeeder.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. using Application.Abstractions.Data;
  2. using Domain.Entities.Forum.ValueObject;
  3. using Microsoft.EntityFrameworkCore;
  4. using BoardEntity = Domain.Entities.Forum.Boards.Board;
  5. using BoardGroupEntity = Domain.Entities.Forum.Boards.BoardGroup;
  6. using BoardMetaEntity = Domain.Entities.Forum.Boards.BoardMeta;
  7. namespace Application.Helpers;
  8. /// <summary>
  9. /// 물리 게시판 lazy 시드 (d2 §③ M3) — 코드별 물리 Board 행이 없으면 BoardGroup+Board+BoardMeta 를 생성하고 Board.ID 를 반환한다.
  10. /// 종목 가상보드(CreatePost 의 ResolveStockBoardID)와 동일한 패턴이며, 수익인증(proof)/장전브리핑(briefing) 처럼
  11. /// 물리 보드가 필요한 곳에서 재사용한다. 마이그레이션 데이터 시드 대신 최초 사용 시점 provisioning 을 택해
  12. /// (예측 채점처럼) 시드 여부와 무관하게 항상 존재를 보장한다.
  13. /// </summary>
  14. public static class BoardSeeder
  15. {
  16. /// <summary>수익인증 게시판 코드 — 이미지 필수(RequireImage), 사진/동영상 레이아웃.</summary>
  17. public const string ProofBoardCode = "proof";
  18. /// <summary>장전 브리핑 게시판 코드 — 공지 리스트(IsNotice 발행).</summary>
  19. public const string BriefingBoardCode = "briefing";
  20. /// <summary>고객지원(공지) 게시판 코드 — 상단 네비 "고객지원" 대상.</summary>
  21. public const string NoticeBoardCode = "notice";
  22. /// <summary>고객지원 게시판(Code="notice")을 해석 — 없으면 기본 리스트로 lazy 시드하고 Board.ID 반환.</summary>
  23. public static Task<int> ResolveNoticeBoardIDAsync(IAppDbContext db, CancellationToken ct)
  24. {
  25. return ResolveAsync(db, NoticeBoardCode, "고객지원", meta =>
  26. {
  27. meta.List = new Domain.Entities.Forum.Boards.BoardMetaList { Layout = BoardLayout.Default, PerPage = 20 };
  28. meta.View = new Domain.Entities.Forum.Boards.BoardMetaView { AllowLike = true, AllowBookmark = true };
  29. meta.Write = new Domain.Entities.Forum.Boards.BoardMetaWrite { AllowEditor = true, AllowImage = true };
  30. meta.Comment = new Domain.Entities.Forum.Boards.BoardMetaComment { EnableComment = true, AllowLike = true };
  31. }, ct);
  32. }
  33. /// <summary>피드 게시판 코드 — 피드 시스템 대상(SeedFeedBoard 마이그레이션과 동일 코드).</summary>
  34. public const string FeedBoardCode = "feed";
  35. /// <summary>피드 게시판(Code="feed")을 해석 — 없으면 Feed 레이아웃으로 lazy 시드. BoardGroup 만 남은 재빌드 상태를 복구.</summary>
  36. public static Task<int> ResolveFeedBoardIDAsync(IAppDbContext db, CancellationToken ct)
  37. {
  38. return ResolveAsync(db, FeedBoardCode, "피드", meta =>
  39. {
  40. meta.List = new Domain.Entities.Forum.Boards.BoardMetaList { Layout = BoardLayout.Feed, PerPage = 20 };
  41. meta.View = new Domain.Entities.Forum.Boards.BoardMetaView { AllowLike = true, AllowBookmark = true };
  42. meta.Write = new Domain.Entities.Forum.Boards.BoardMetaWrite { AllowEditor = true, AllowImage = true };
  43. meta.Comment = new Domain.Entities.Forum.Boards.BoardMetaComment { EnableComment = true, AllowLike = true };
  44. }, ct);
  45. }
  46. /// <summary>수익인증 게시판(Code="proof")을 해석 — 없으면 이미지 필수·사진/동영상 레이아웃으로 lazy 시드하고 Board.ID 반환.</summary>
  47. public static Task<int> ResolveProofBoardIDAsync(IAppDbContext db, CancellationToken ct)
  48. {
  49. return ResolveAsync(db, ProofBoardCode, "수익인증", meta =>
  50. {
  51. meta.List = new Domain.Entities.Forum.Boards.BoardMetaList { Layout = BoardLayout.Media, PerPage = 20 };
  52. meta.View = new Domain.Entities.Forum.Boards.BoardMetaView { AllowLike = true, AllowBookmark = true, ShowMemberThumb = true };
  53. meta.Write = new Domain.Entities.Forum.Boards.BoardMetaWrite { AllowEditor = true, AllowImage = true, RequireImage = true };
  54. meta.Comment = new Domain.Entities.Forum.Boards.BoardMetaComment { EnableComment = true, AllowLike = true };
  55. }, ct);
  56. }
  57. /// <summary>장전 브리핑 게시판(Code="briefing")을 해석 — 없으면 공지 리스트로 lazy 시드하고 Board.ID 반환.</summary>
  58. public static Task<int> ResolveBriefingBoardIDAsync(IAppDbContext db, CancellationToken ct)
  59. {
  60. return ResolveAsync(db, BriefingBoardCode, "장전 시황", meta =>
  61. {
  62. meta.List = new Domain.Entities.Forum.Boards.BoardMetaList { Layout = BoardLayout.Default, PerPage = 20 };
  63. meta.View = new Domain.Entities.Forum.Boards.BoardMetaView { AllowLike = true, AllowBookmark = true };
  64. meta.Write = new Domain.Entities.Forum.Boards.BoardMetaWrite { AllowEditor = true, AllowImage = true };
  65. meta.Comment = new Domain.Entities.Forum.Boards.BoardMetaComment { EnableComment = true, AllowLike = true };
  66. }, ct);
  67. }
  68. private static async Task<int> ResolveAsync(IAppDbContext db, string code, string name, Action<BoardMetaEntity> configureMeta, CancellationToken ct)
  69. {
  70. var existing = await db.Board.AsNoTracking().Where(c => c.Code == code).Select(c => (int?)c.ID).FirstOrDefaultAsync(ct);
  71. if (existing is int id)
  72. {
  73. return id;
  74. }
  75. var group = await db.BoardGroup.FirstOrDefaultAsync(c => c.Code == code, ct);
  76. if (group is null)
  77. {
  78. group = new BoardGroupEntity { Code = code, Name = name };
  79. await db.BoardGroup.AddAsync(group, ct);
  80. await db.SaveChangesAsync(ct);
  81. }
  82. var board = new BoardEntity
  83. {
  84. BoardGroupID = group.ID,
  85. Code = code,
  86. Name = name,
  87. IsActive = true,
  88. IsSearch = true
  89. };
  90. await db.Board.AddAsync(board, ct);
  91. await db.SaveChangesAsync(ct);
  92. var meta = new BoardMetaEntity { BoardID = board.ID };
  93. configureMeta(meta);
  94. await db.BoardMeta.AddAsync(meta, ct);
  95. await db.SaveChangesAsync(ct);
  96. return board.ID;
  97. }
  98. }