using SharedKernel.Extensions; using Application.Abstractions.Messaging; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Infrastructure.Persistence.Identity; using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace Admin.Pages.Forum.Posts.List; public class AnswerModel(IMediator mediator, UserManager userManager) : PageModel { public int ID { get; set; } public int BoardID { get; set; } public string BoardName { get; set; } = default!; public string? BoardPrefixName { get; set; } public string? BoardPrefixColor { get; set; } public string Subject { get; set; } = default!; public new string Content { get; set; } = default!; public string? Name { get; set; } public string? SID { get; set; } public bool IsSecret { get; set; } public bool IsAnswered => Answers.Count > 0; public string CreatedAt { get; set; } = default!; public List Files { get; set; } = []; public List Answers { get; set; } = []; public string? ReturnUrl { get; set; } public string? QueryString { get; set; } public sealed record FileItemView(int ID, string FileName, string Url, long? Size); public sealed record AnswerItemView(int ID, string? Name, string Content, string CreatedAt); [BindProperty] public InputModel Input { get; set; } = new(); public sealed class InputModel { [DisplayName("답변 내용")] [Required(ErrorMessage = "{0}을 입력해주세요.")] public string Content { get; set; } = null!; [DisplayName("첨부파일")] public List? Files { get; set; } } public async Task OnGetAsync(int id, CancellationToken ct) { var loaded = await LoadAsync(id, ct); if (!loaded) { return RedirectToPage("/Forum/Posts/List/Index"); } return Page(); } public async Task OnPostAsync(int id, CancellationToken ct) { if (!ModelState.IsValid) { TempData["ErrorMessages"] = ModelState.GetErrorMessages(); return RedirectToPage("/Forum/Posts/List/Answer", new { id }); } var admin = await userManager.GetUserAsync(User); var result = await mediator.Send(new CreateAnswerComment.Command( id, Input.Content, Input.Files, admin?.Email ), ct); if (result.IsFailure) { TempData["ErrorMessages"] = result.Error.Description; } else { TempData["SuccessMessage"] = "답변이 등록되었습니다."; } return RedirectToPage("/Forum/Posts/List/Answer", new { id }); } private async Task LoadAsync(int id, CancellationToken ct) { var postResult = await mediator.Send(new GetPost.Query(id), ct); if (postResult.IsFailure) { TempData["ErrorMessages"] = postResult.Error.Description; return false; } var post = postResult.Value; if (!post.IsQnA) { TempData["ErrorMessages"] = "1:1 문의 게시판의 게시글이 아닙니다."; return false; } ID = post.ID; BoardID = post.BoardID; BoardName = post.BoardName; BoardPrefixName = post.BoardPrefixName; BoardPrefixColor = post.BoardPrefixColor; Subject = post.Subject; Content = post.Content; Name = post.Name; SID = post.SID; IsSecret = post.IsSecret; CreatedAt = post.CreatedAt.GetDateAt(); Files = [..post.Files.Where(c => !c.IsDisabled).Select(c => new FileItemView(c.ID, c.FileName, c.Url, c.Size))]; // 기존 답변 (게시글의 댓글, 오래된 순) var comments = await mediator.Send(new SearchComments.Query(null, id, null, null, null, null, null, 1, 100), ct); Answers = [..comments.List .Where(c => !c.IsDeleted) .OrderBy(c => c.ID) .Select(c => new AnswerItemView(c.ID, c.Name ?? c.SID, c.Content, c.CreatedAt.GetDateAt()))]; ReturnUrl = Request.Headers.Referer.ToString(); QueryString = Request.QueryString.ToString(); return true; } }