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";