102 lines
5.2 KiB
C#
102 lines
5.2 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Swashbuckle.AspNetCore.Annotations;
|
|
using SPMS.Application.DTOs.Message;
|
|
using SPMS.Application.Interfaces;
|
|
using SPMS.Domain.Common;
|
|
using SPMS.Domain.Exceptions;
|
|
|
|
namespace SPMS.API.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("v1/in/message")]
|
|
[ApiExplorerSettings(GroupName = "message")]
|
|
public class MessageController : ControllerBase
|
|
{
|
|
private readonly IMessageValidationService _validationService;
|
|
private readonly IMessageService _messageService;
|
|
|
|
public MessageController(IMessageValidationService validationService, IMessageService messageService)
|
|
{
|
|
_validationService = validationService;
|
|
_messageService = messageService;
|
|
}
|
|
|
|
[HttpPost("save")]
|
|
[SwaggerOperation(Summary = "메시지 저장", Description = "메시지 템플릿을 저장합니다. 메시지 코드가 자동 생성됩니다. 필드명은 snake_case(title, body, image_url, link_url, link_type, data)를 사용합니다. 저장 전 validate API로 사전 검증을 권장합니다.")]
|
|
public async Task<IActionResult> SaveAsync([FromBody] MessageSaveRequestDto request)
|
|
{
|
|
var serviceId = GetServiceId();
|
|
var adminId = GetAdminId();
|
|
var result = await _messageService.SaveAsync(serviceId, adminId, request);
|
|
return Ok(ApiResponse<MessageSaveResponseDto>.Success(result, "메시지 저장 성공"));
|
|
}
|
|
|
|
[HttpPost("list")]
|
|
[SwaggerOperation(Summary = "메시지 목록 조회", Description = "메시지 목록을 페이지 단위로 조회합니다. X-Service-Code 헤더가 있으면 해당 서비스만, 없으면 전체 서비스 메시지를 반환합니다. send_status 필터(complete/pending/failed)를 지원합니다. 발송 상태는 통일된 SendStatus 규칙(pending=미발송, complete=1건 이상 성공, failed=전건 실패)으로 판정됩니다.")]
|
|
public async Task<IActionResult> GetListAsync([FromBody] MessageListRequestDto request)
|
|
{
|
|
var serviceId = GetServiceIdOrNull();
|
|
var result = await _messageService.GetListAsync(serviceId, request);
|
|
return Ok(ApiResponse<MessageListResponseDto>.Success(result));
|
|
}
|
|
|
|
[HttpPost("info")]
|
|
[SwaggerOperation(Summary = "메시지 상세 조회", Description = "메시지 코드로 상세 정보를 조회합니다. 서비스 정보(service_name, service_code), 작성자(created_by_name), 발송 상태(latest_send_status), 템플릿 변수 목록을 포함합니다. 발송 상태는 통일된 SendStatus 규칙(pending=미발송, complete=1건 이상 성공, failed=전건 실패)으로 판정됩니다.")]
|
|
public async Task<IActionResult> GetInfoAsync([FromBody] MessageInfoRequestDto request)
|
|
{
|
|
var serviceId = GetServiceId();
|
|
var result = await _messageService.GetInfoAsync(serviceId, request);
|
|
return Ok(ApiResponse<MessageInfoResponseDto>.Success(result));
|
|
}
|
|
|
|
[HttpPost("delete")]
|
|
[SwaggerOperation(Summary = "메시지 삭제", Description = "메시지를 소프트 삭제합니다. 30일 후 스케줄러에 의해 완전 삭제됩니다.")]
|
|
public async Task<IActionResult> DeleteAsync([FromBody] MessageDeleteRequestDto request)
|
|
{
|
|
var serviceId = GetServiceId();
|
|
await _messageService.DeleteAsync(serviceId, request);
|
|
return Ok(ApiResponse<object?>.Success(null, "메시지 삭제 성공"));
|
|
}
|
|
|
|
[HttpPost("validate")]
|
|
[SwaggerOperation(Summary = "메시지 유효성 검사", Description = "메시지 내용의 유효성을 검사합니다. save API와 동일한 snake_case 필드명(title, body, image_url, link_url, link_type, data)을 사용합니다. 검증 실패 시 data.errors[]에 field + message 단위로 오류가 반환됩니다.")]
|
|
public IActionResult ValidateAsync([FromBody] MessageValidateRequestDto request)
|
|
{
|
|
var result = _validationService.Validate(request);
|
|
return Ok(ApiResponse<MessageValidationResultDto>.Success(result));
|
|
}
|
|
|
|
[HttpPost("preview")]
|
|
[SwaggerOperation(Summary = "메시지 미리보기", Description = "메시지 템플릿에 변수를 치환하여 미리보기를 생성합니다. 응답에 link_type을 포함합니다.")]
|
|
public async Task<IActionResult> PreviewAsync([FromBody] MessagePreviewRequestDto request)
|
|
{
|
|
var serviceId = GetServiceId();
|
|
var result = await _messageService.PreviewAsync(serviceId, request);
|
|
return Ok(ApiResponse<MessagePreviewResponseDto>.Success(result));
|
|
}
|
|
|
|
private long GetServiceId()
|
|
{
|
|
if (HttpContext.Items.TryGetValue("ServiceId", out var serviceIdObj) && serviceIdObj is long serviceId)
|
|
return serviceId;
|
|
|
|
throw new SpmsException(ErrorCodes.BadRequest, "서비스 식별 정보가 없습니다.", 400);
|
|
}
|
|
|
|
private long? GetServiceIdOrNull()
|
|
{
|
|
if (HttpContext.Items.TryGetValue("ServiceId", out var serviceIdObj) && serviceIdObj is long serviceId)
|
|
return serviceId;
|
|
return null;
|
|
}
|
|
|
|
private long GetAdminId()
|
|
{
|
|
var adminIdClaim = User.FindFirst("adminId")?.Value;
|
|
if (string.IsNullOrEmpty(adminIdClaim) || !long.TryParse(adminIdClaim, out var adminId))
|
|
throw new SpmsException(ErrorCodes.Unauthorized, "인증 정보가 올바르지 않습니다.", 401);
|
|
|
|
return adminId;
|
|
}
|
|
}
|