Write.cshtml.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. using Domain.Entities.Members.ValueObject;
  2. using SharedKernel.Extensions;
  3. using SharedKernel.Storage;
  4. using SharedKernel.Attributes;
  5. using MediatR;
  6. using Microsoft.AspNetCore.Mvc;
  7. using Microsoft.AspNetCore.Mvc.RazorPages;
  8. using Microsoft.AspNetCore.Mvc.Rendering;
  9. using System.ComponentModel;
  10. using System.ComponentModel.DataAnnotations;
  11. namespace Admin.Pages.Member.List;
  12. public class WriteModel(IMediator mediator, IFileStorage fileStorage) : PageModel
  13. {
  14. private static readonly string[] AllowedFileExtensions = [".jpg", ".jpeg", ".png", ".gif", ".webp"];
  15. [BindProperty]
  16. public string? QueryString { get; set; }
  17. public List<SelectListItem> MemberGradeList { get; set; } = [];
  18. [BindProperty]
  19. public InputModel Input { get; set; } = new();
  20. public sealed class InputModel
  21. {
  22. [DisplayName("회원등급")]
  23. public int? MemberGradeID { get; set; }
  24. [DisplayName("이메일")]
  25. [Required(ErrorMessage = "{0}은(는) 필수입니다.")]
  26. [EmailAddress(ErrorMessage = "올바른 이메일 형식이 아닙니다.")]
  27. [StringLength(60, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
  28. public string Email { get; set; } = default!;
  29. [DisplayName("별명")]
  30. [Required(ErrorMessage = "{0}은(는) 필수입니다.")]
  31. [StringLength(20, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
  32. public string? Name { get; set; }
  33. [DisplayName("비밀번호")]
  34. [Required(ErrorMessage = "{0}은(는) 필수입니다.")]
  35. [MinLength(4, ErrorMessage = "{0}은(는) {1}자 이상 입력하세요.")]
  36. public string Password { get; set; } = default!;
  37. [DisplayName("성")]
  38. [StringLength(20, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
  39. public string? FirstName { get; set; }
  40. [DisplayName("이름")]
  41. [StringLength(40, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
  42. public string? LastName { get; set; }
  43. [DisplayName("자기소개")]
  44. [StringLength(1000, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
  45. public string? Intro { get; set; }
  46. [DisplayName("한마디")]
  47. [StringLength(50, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
  48. public string? Summary { get; set; }
  49. [DisplayName("연락처")]
  50. [StringLength(15)]
  51. public string? Phone { get; set; }
  52. [DisplayName("성별")]
  53. public Gender? Gender { get; set; }
  54. [DisplayName("생년월일")]
  55. public DateOnly? Birthday { get; set; }
  56. [DisplayName("사진")]
  57. [AllowedExtensions("jpg,jpeg,png,gif,webp", ErrorMessage = "이미지 형식은 jpg, jpeg, png, gif, webp 파일이어야 합니다.")]
  58. public IFormFile? Thumb { get; set; }
  59. [DisplayName("아이콘")]
  60. [AllowedExtensions("jpg,jpeg,png,gif,webp", ErrorMessage = "이미지 형식은 jpg, jpeg, png, gif, webp 파일이어야 합니다.")]
  61. public IFormFile? Icon { get; set; }
  62. [DisplayName("이메일 인증")]
  63. public bool IsEmailVerified { get; set; }
  64. [DisplayName("본인 인증")]
  65. public bool IsAuthCertified { get; set; }
  66. [DisplayName("차단 여부")]
  67. public bool IsDenied { get; set; }
  68. [DisplayName("관리자 여부")]
  69. public bool IsAdmin { get; set; }
  70. [DisplayName("탈퇴 여부")]
  71. public bool IsWithdraw { get; set; }
  72. // YouTube 채널 정보
  73. [DisplayName("YouTube SID")]
  74. [StringLength(24, MinimumLength = 24, ErrorMessage = "{0}은(는) {1}자여야 합니다.")]
  75. public string? YouTubeSID { get; set; }
  76. [DisplayName("YouTube 이름")]
  77. [StringLength(200, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
  78. public string? YouTubeName { get; set; }
  79. [DisplayName("YouTube 핸들")]
  80. [StringLength(30, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
  81. public string? YouTubeHandle { get; set; }
  82. [DisplayName("YouTube 주소")]
  83. [StringLength(255, ErrorMessage = "{0}은(는) {1}자 이하로 입력하세요.")]
  84. public string? YouTubeUrl { get; set; }
  85. }
  86. public async Task OnGetAsync(CancellationToken ct)
  87. {
  88. await LoadMemberGradeList(ct);
  89. QueryString = Request.QueryString.ToString();
  90. }
  91. public async Task<IActionResult> OnPostAsync(CancellationToken ct)
  92. {
  93. try
  94. {
  95. if (!ModelState.IsValid)
  96. {
  97. throw new Exception(ModelState.GetErrorMessages());
  98. }
  99. // 파일 저장 (PageModel에서 처리)
  100. string? thumbUrl = null;
  101. string? iconUrl = null;
  102. if (Input.Thumb is not null)
  103. {
  104. var thumbPath = new FileStoragePath(UploadTarget.Upload, UploadFolder.MemberThumb, 0);
  105. thumbUrl = (await fileStorage.SaveFileAsync(Input.Thumb, thumbPath, AllowedFileExtensions, ct))?.Url;
  106. }
  107. if (Input.Icon is not null)
  108. {
  109. var iconPath = new FileStoragePath(UploadTarget.Upload, UploadFolder.MemberIcon, 0);
  110. iconUrl = (await fileStorage.SaveFileAsync(Input.Icon, iconPath, AllowedFileExtensions, ct))?.Url;
  111. }
  112. await mediator.Send(new CreateMember.Command(
  113. Input.MemberGradeID,
  114. Input.Email,
  115. Input.Name,
  116. Input.Password,
  117. Input.FirstName,
  118. Input.LastName,
  119. Input.Intro,
  120. Input.Summary,
  121. Input.Phone,
  122. Input.Birthday,
  123. Input.Gender,
  124. thumbUrl,
  125. iconUrl,
  126. Input.IsEmailVerified,
  127. Input.IsAuthCertified,
  128. Input.IsDenied,
  129. Input.IsAdmin,
  130. Input.IsWithdraw,
  131. Input.YouTubeSID,
  132. Input.YouTubeName,
  133. Input.YouTubeHandle,
  134. Input.YouTubeUrl
  135. ), ct);
  136. TempData["SuccessMessage"] = "회원이 등록되었습니다.";
  137. return RedirectToPage("Index");
  138. }
  139. catch (Exception e)
  140. {
  141. TempData["ErrorMessages"] = e.Message;
  142. }
  143. await LoadMemberGradeList(ct);
  144. return Page();
  145. }
  146. private async Task LoadMemberGradeList(CancellationToken ct)
  147. {
  148. var grades = await mediator.Send(new GetMemberGrades.Query(), ct);
  149. MemberGradeList = [.. grades.List.Select(g => new SelectListItem
  150. {
  151. Value = g.ID.ToString(),
  152. Text = g.KorName
  153. })];
  154. }
  155. }