From ef6d71a9212b4a764081f0527369a86acd3c1e9c Mon Sep 17 00:00:00 2001 From: SEAN Date: Tue, 10 Feb 2026 17:27:56 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EB=AF=B8?= =?UTF-8?q?=EB=A6=AC=EB=B3=B4=EA=B8=B0=20API=20=EA=B5=AC=ED=98=84=20(#120)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - POST /v1/in/message/preview 엔드포인트 추가 - MessageService: 메시지 조회 → 변수 치환 → 미리보기 데이터 반환 - IMessageService 인터페이스 정의 (향후 CRUD 확장용) Closes #120 --- SPMS.API/Controllers/MessageController.cs | 13 ++++- .../DTOs/Message/MessagePreviewRequestDto.cs | 11 +++++ .../DTOs/Message/MessagePreviewResponseDto.cs | 9 ++++ SPMS.Application/DependencyInjection.cs | 1 + .../Interfaces/IMessageService.cs | 8 ++++ SPMS.Application/Services/MessageService.cs | 48 +++++++++++++++++++ 6 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 SPMS.Application/DTOs/Message/MessagePreviewRequestDto.cs create mode 100644 SPMS.Application/DTOs/Message/MessagePreviewResponseDto.cs create mode 100644 SPMS.Application/Interfaces/IMessageService.cs create mode 100644 SPMS.Application/Services/MessageService.cs diff --git a/SPMS.API/Controllers/MessageController.cs b/SPMS.API/Controllers/MessageController.cs index 00ecc5f..22806fd 100644 --- a/SPMS.API/Controllers/MessageController.cs +++ b/SPMS.API/Controllers/MessageController.cs @@ -12,10 +12,12 @@ namespace SPMS.API.Controllers; public class MessageController : ControllerBase { private readonly IMessageValidationService _validationService; + private readonly IMessageService _messageService; - public MessageController(IMessageValidationService validationService) + public MessageController(IMessageValidationService validationService, IMessageService messageService) { _validationService = validationService; + _messageService = messageService; } [HttpPost("validate")] @@ -26,6 +28,15 @@ public class MessageController : ControllerBase return Ok(ApiResponse.Success(result)); } + [HttpPost("preview")] + [SwaggerOperation(Summary = "메시지 미리보기", Description = "메시지 템플릿에 변수를 치환하여 미리보기를 생성합니다.")] + public async Task PreviewAsync([FromBody] MessagePreviewRequestDto request) + { + var serviceId = GetServiceId(); + var result = await _messageService.PreviewAsync(serviceId, request); + return Ok(ApiResponse.Success(result)); + } + private long GetServiceId() { if (HttpContext.Items.TryGetValue("ServiceId", out var serviceIdObj) && serviceIdObj is long serviceId) diff --git a/SPMS.Application/DTOs/Message/MessagePreviewRequestDto.cs b/SPMS.Application/DTOs/Message/MessagePreviewRequestDto.cs new file mode 100644 index 0000000..ee9172e --- /dev/null +++ b/SPMS.Application/DTOs/Message/MessagePreviewRequestDto.cs @@ -0,0 +1,11 @@ +using System.ComponentModel.DataAnnotations; + +namespace SPMS.Application.DTOs.Message; + +public class MessagePreviewRequestDto +{ + [Required] + public string MessageCode { get; set; } = string.Empty; + + public Dictionary? Variables { get; set; } +} diff --git a/SPMS.Application/DTOs/Message/MessagePreviewResponseDto.cs b/SPMS.Application/DTOs/Message/MessagePreviewResponseDto.cs new file mode 100644 index 0000000..5dcb15e --- /dev/null +++ b/SPMS.Application/DTOs/Message/MessagePreviewResponseDto.cs @@ -0,0 +1,9 @@ +namespace SPMS.Application.DTOs.Message; + +public class MessagePreviewResponseDto +{ + public string Title { get; set; } = string.Empty; + public string Body { get; set; } = string.Empty; + public string? ImageUrl { get; set; } + public string? LinkUrl { get; set; } +} diff --git a/SPMS.Application/DependencyInjection.cs b/SPMS.Application/DependencyInjection.cs index 91cbc95..4446192 100644 --- a/SPMS.Application/DependencyInjection.cs +++ b/SPMS.Application/DependencyInjection.cs @@ -20,6 +20,7 @@ public static class DependencyInjection services.AddScoped(); services.AddScoped(); services.AddSingleton(); + services.AddScoped(); return services; } diff --git a/SPMS.Application/Interfaces/IMessageService.cs b/SPMS.Application/Interfaces/IMessageService.cs new file mode 100644 index 0000000..ecdf8cb --- /dev/null +++ b/SPMS.Application/Interfaces/IMessageService.cs @@ -0,0 +1,8 @@ +using SPMS.Application.DTOs.Message; + +namespace SPMS.Application.Interfaces; + +public interface IMessageService +{ + Task PreviewAsync(long serviceId, MessagePreviewRequestDto request); +} diff --git a/SPMS.Application/Services/MessageService.cs b/SPMS.Application/Services/MessageService.cs new file mode 100644 index 0000000..6848dbc --- /dev/null +++ b/SPMS.Application/Services/MessageService.cs @@ -0,0 +1,48 @@ +using SPMS.Application.DTOs.Message; +using SPMS.Application.Interfaces; +using SPMS.Domain.Common; +using SPMS.Domain.Exceptions; +using SPMS.Domain.Interfaces; + +namespace SPMS.Application.Services; + +public class MessageService : IMessageService +{ + private readonly IMessageRepository _messageRepository; + + public MessageService(IMessageRepository messageRepository) + { + _messageRepository = messageRepository; + } + + public async Task PreviewAsync(long serviceId, MessagePreviewRequestDto request) + { + var message = await _messageRepository.GetByMessageCodeAndServiceAsync(request.MessageCode, serviceId); + if (message == null) + throw new SpmsException(ErrorCodes.MessageNotFound, "존재하지 않는 메시지 코드입니다.", 404); + + var title = ApplyVariables(message.Title, request.Variables); + var body = ApplyVariables(message.Body, request.Variables); + + return new MessagePreviewResponseDto + { + Title = title, + Body = body, + ImageUrl = message.ImageUrl, + LinkUrl = message.LinkUrl + }; + } + + private static string ApplyVariables(string template, Dictionary? variables) + { + if (variables == null || variables.Count == 0) + return template; + + var result = template; + foreach (var (key, value) in variables) + { + result = result.Replace($"{{{{{key}}}}}", value); + } + return result; + } +} -- 2.45.1