From e1bab0cce6ae37ac17ea7955a4b09150a2d3ad40 Mon Sep 17 00:00:00 2001 From: SEAN Date: Tue, 10 Feb 2026 09:44:36 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20API=20=EA=B5=AC=ED=98=84=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SPMS.API/Controllers/ServiceController.cs | 16 +++++ .../DTOs/Service/UpdateServiceRequestDto.cs | 20 ++++++ .../Interfaces/IServiceManagementService.cs | 1 + .../Services/ServiceManagementService.cs | 66 +++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 SPMS.Application/DTOs/Service/UpdateServiceRequestDto.cs diff --git a/SPMS.API/Controllers/ServiceController.cs b/SPMS.API/Controllers/ServiceController.cs index 71202fa..7c94cb4 100644 --- a/SPMS.API/Controllers/ServiceController.cs +++ b/SPMS.API/Controllers/ServiceController.cs @@ -41,6 +41,22 @@ public class ServiceController : ControllerBase return Ok(ApiResponse.Success(result)); } + [HttpPost("update")] + [SwaggerOperation( + Summary = "서비스 수정", + Description = "기존 서비스의 정보를 수정합니다. 서비스명, 설명, 웹훅 URL, 태그를 변경할 수 있습니다.")] + [SwaggerResponse(200, "수정 성공", typeof(ApiResponse))] + [SwaggerResponse(400, "변경된 내용 없음")] + [SwaggerResponse(401, "인증되지 않은 요청")] + [SwaggerResponse(403, "권한 없음")] + [SwaggerResponse(404, "서비스를 찾을 수 없음")] + [SwaggerResponse(409, "이미 존재하는 서비스명")] + public async Task UpdateAsync([FromBody] UpdateServiceRequestDto request) + { + var result = await _serviceManagementService.UpdateAsync(request); + return Ok(ApiResponse.Success(result)); + } + [HttpPost("list")] [SwaggerOperation( Summary = "서비스 목록 조회", diff --git a/SPMS.Application/DTOs/Service/UpdateServiceRequestDto.cs b/SPMS.Application/DTOs/Service/UpdateServiceRequestDto.cs new file mode 100644 index 0000000..2ed7b55 --- /dev/null +++ b/SPMS.Application/DTOs/Service/UpdateServiceRequestDto.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace SPMS.Application.DTOs.Service; + +public class UpdateServiceRequestDto +{ + [Required(ErrorMessage = "서비스 코드는 필수입니다.")] + public string ServiceCode { get; set; } = string.Empty; + + [StringLength(100, ErrorMessage = "서비스명은 100자 이내여야 합니다.")] + public string? ServiceName { get; set; } + + [StringLength(500, ErrorMessage = "설명은 500자 이내여야 합니다.")] + public string? Description { get; set; } + + [StringLength(500, ErrorMessage = "웹훅 URL은 500자 이내여야 합니다.")] + public string? WebhookUrl { get; set; } + + public string? Tags { get; set; } +} diff --git a/SPMS.Application/Interfaces/IServiceManagementService.cs b/SPMS.Application/Interfaces/IServiceManagementService.cs index 0b65d33..5d01a8c 100644 --- a/SPMS.Application/Interfaces/IServiceManagementService.cs +++ b/SPMS.Application/Interfaces/IServiceManagementService.cs @@ -5,6 +5,7 @@ namespace SPMS.Application.Interfaces; public interface IServiceManagementService { Task CreateAsync(CreateServiceRequestDto request, long adminId); + Task UpdateAsync(UpdateServiceRequestDto request); Task GetListAsync(ServiceListRequestDto request); Task GetByServiceCodeAsync(string serviceCode); Task ChangeStatusAsync(string serviceCode, ChangeServiceStatusRequestDto request); diff --git a/SPMS.Application/Services/ServiceManagementService.cs b/SPMS.Application/Services/ServiceManagementService.cs index 3a8cacb..d382fdd 100644 --- a/SPMS.Application/Services/ServiceManagementService.cs +++ b/SPMS.Application/Services/ServiceManagementService.cs @@ -77,6 +77,72 @@ public class ServiceManagementService : IServiceManagementService }; } + public async Task UpdateAsync(UpdateServiceRequestDto request) + { + var service = await _serviceRepository.GetByServiceCodeAsync(request.ServiceCode); + if (service is null) + { + throw new SpmsException( + ErrorCodes.NotFound, + "서비스를 찾을 수 없습니다.", + 404); + } + + var hasChanges = false; + + // ServiceName 변경 + if (request.ServiceName != null && request.ServiceName != service.ServiceName) + { + var nameExists = await _serviceRepository.ServiceNameExistsAsync(request.ServiceName); + if (nameExists) + { + throw new SpmsException( + ErrorCodes.Conflict, + "이미 존재하는 서비스명입니다.", + 409); + } + service.ServiceName = request.ServiceName; + hasChanges = true; + } + + // Description 변경 + if (request.Description != null && request.Description != service.Description) + { + service.Description = request.Description; + hasChanges = true; + } + + // WebhookUrl 변경 + if (request.WebhookUrl != null && request.WebhookUrl != service.WebhookUrl) + { + service.WebhookUrl = request.WebhookUrl; + hasChanges = true; + } + + // Tags 변경 + if (request.Tags != null && request.Tags != service.Tags) + { + service.Tags = request.Tags; + hasChanges = true; + } + + if (!hasChanges) + { + throw new SpmsException( + ErrorCodes.NoChange, + "변경된 내용이 없습니다.", + 400); + } + + service.UpdatedAt = DateTime.UtcNow; + + _serviceRepository.Update(service); + await _unitOfWork.SaveChangesAsync(); + + var serviceWithIps = await _serviceRepository.GetByIdWithIpsAsync(service.Id); + return MapToDto(serviceWithIps ?? service); + } + private async Task GenerateUniqueServiceCodeAsync() { const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";