Index.cshtml.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. using SharedKernel.Helpers;
  2. using SharedKernel.Extensions;
  3. using Application.Abstractions.YouTube;
  4. using MediatR;
  5. using Microsoft.AspNetCore.Mvc;
  6. using Microsoft.AspNetCore.Mvc.RazorPages;
  7. using System.ComponentModel;
  8. using System.ComponentModel.DataAnnotations;
  9. namespace Admin.Pages.Channel.List;
  10. public class IndexModel(IMediator mediator, IYouTubeLiveStateStore liveStateStore) : PageModel
  11. {
  12. [BindProperty(SupportsGet = true)]
  13. public QueryParams Query { get; set; } = new();
  14. public sealed class QueryParams
  15. {
  16. public int? Search { get; set; }
  17. public string? Keyword { get; set; }
  18. public string? StartAt { get; set; }
  19. public string? EndAt { get; set; }
  20. public bool? IsVerified { get; set; }
  21. [Range(1, int.MaxValue)]
  22. [DisplayName("페이지 번호")]
  23. public int PageNum { get; set; } = 1;
  24. [Range(1, 100)]
  25. [DisplayName("페이지 목록 수")]
  26. public ushort PerPage { get; set; } = 20;
  27. }
  28. public int Total { get; set; } = 0;
  29. public List<(
  30. int Num,
  31. int ID,
  32. string SID,
  33. string Name,
  34. string? Handle,
  35. string? ThumbnailUrl,
  36. string YouTubeUrl,
  37. decimal PlatformFeeRate,
  38. char IsVerified,
  39. char IsActive,
  40. int MemberID,
  41. string? MemberName,
  42. string? MemberEmail,
  43. string? UpdatedAt,
  44. string CreatedAt
  45. )> List { get; set; } = [];
  46. public Pagination? Pagination { get; set; }
  47. /// <summary>현재 라이브 중인 채널 SID(=YouTube 채널 ID) 집합</summary>
  48. public HashSet<string> LiveChannelIds { get; set; } = [];
  49. public async Task OnGetAsync(CancellationToken ct)
  50. {
  51. if (!ModelState.IsValid)
  52. {
  53. return;
  54. }
  55. var result = await mediator.Send(new SearchChannels.Query(
  56. Query.Search,
  57. Query.Keyword,
  58. Query.IsVerified,
  59. Query.StartAt,
  60. Query.EndAt,
  61. Query.PageNum,
  62. Query.PerPage
  63. ), ct);
  64. Total = result.Total;
  65. List = [..result.List.Select(c => (
  66. c.Num,
  67. c.ID,
  68. c.SID,
  69. c.Name,
  70. c.Handle,
  71. c.ThumbnailUrl,
  72. c.YouTubeUrl,
  73. c.PlatformFeeRate,
  74. c.IsVerified ? 'Y' : 'N',
  75. c.IsActive ? 'Y' : 'N',
  76. c.MemberID,
  77. c.MemberName ?? "-",
  78. c.MemberEmail ?? "-",
  79. c.UpdatedAt.GetDateAt() ?? "-",
  80. c.CreatedAt.GetDateAt()
  81. ))];
  82. Pagination = new Pagination(result.Total, Query.PageNum, Query.PerPage);
  83. // Redis에서 현재 라이브 중인 채널 ID 조회 (API 호출 없음)
  84. var allLive = await liveStateStore.GetAllLiveAsync();
  85. LiveChannelIds = [..allLive.Select(l => l.ChannelId)];
  86. }
  87. public async Task<IActionResult> OnPostDeleteAsync(int[] ids, CancellationToken ct)
  88. {
  89. try
  90. {
  91. await mediator.Send(new DeleteChannel.Command(ids), ct);
  92. TempData["SuccessMessage"] = $"{ids.Length}건이 삭제되었습니다.";
  93. }
  94. catch (InvalidOperationException e)
  95. {
  96. TempData["ErrorMessages"] = e.Message;
  97. }
  98. catch (Microsoft.EntityFrameworkCore.DbUpdateException e)
  99. {
  100. var detail = e.InnerException?.Message ?? e.Message;
  101. TempData["ErrorMessages"] = $"데이터베이스 제약 조건 위반으로 삭제할 수 없습니다. 연관된 데이터를 먼저 정리해 주세요.\n상세: {detail}";
  102. }
  103. catch (Exception e)
  104. {
  105. TempData["ErrorMessages"] = e.Message;
  106. }
  107. return RedirectToPage("/Channel/List/Index", Query);
  108. }
  109. }