diff --git a/src/main/java/com/indayvidual/server/domain/todo/controller/TodoCategoryController.java b/src/main/java/com/indayvidual/server/domain/todo/controller/TodoCategoryController.java index a708575..ebc0034 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/controller/TodoCategoryController.java +++ b/src/main/java/com/indayvidual/server/domain/todo/controller/TodoCategoryController.java @@ -46,6 +46,19 @@ public ApiResponse> getCategories() { SuccessStatus.GET_CATEGORIES_SUCCESS.getMessage()); } + @Operation(summary = "카테고리 수정", description = "카테고리 제목과 색상을 수정합니다.") + @PatchMapping("/{categoryId}") + public ApiResponse updateCategoryTitleAndColor( + @PathVariable Long categoryId, + @RequestBody @Valid CategoryCreateRequestDTO request + ) { + Long userId = Utils.getUserId(); + return ApiResponse.onSuccess( + categoryCommandService.updateCategoryTitleAndColor(request, userId, categoryId), + SuccessStatus.UPDATE_CATEGORY_SUCCESS.getCode(), + SuccessStatus.UPDATE_CATEGORY_SUCCESS.getMessage()); + } + @Operation(summary = "카테고리 삭제", description = """ 카테고리를 삭제합니다.\n **카테고리 내 할 일도 모두 삭제됩니다.**""") diff --git a/src/main/java/com/indayvidual/server/domain/todo/dto/request/CategoryCreateRequestDTO.java b/src/main/java/com/indayvidual/server/domain/todo/dto/request/CategoryCreateRequestDTO.java index 9a6c83a..e9d7c71 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/dto/request/CategoryCreateRequestDTO.java +++ b/src/main/java/com/indayvidual/server/domain/todo/dto/request/CategoryCreateRequestDTO.java @@ -1,6 +1,7 @@ package com.indayvidual.server.domain.todo.dto.request; import jakarta.validation.constraints.NotBlank; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -8,7 +9,7 @@ @NoArgsConstructor public class CategoryCreateRequestDTO { - @NotBlank(message = "title 은 비어 있을 수 없습니다.") + @NotBlank(message = "name 은 비어 있을 수 없습니다.") private String name; @NotBlank(message = "color 은 비어 있을 수 없습니다.") diff --git a/src/main/java/com/indayvidual/server/domain/todo/entity/Category.java b/src/main/java/com/indayvidual/server/domain/todo/entity/Category.java index 0d93397..3020507 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/entity/Category.java +++ b/src/main/java/com/indayvidual/server/domain/todo/entity/Category.java @@ -2,6 +2,8 @@ import com.indayvidual.server.common.BaseEntity; import com.indayvidual.server.domain.user.entity.User; +import com.indayvidual.server.global.api.code.status.ErrorStatus; +import com.indayvidual.server.global.exception.GeneralException; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -14,8 +16,10 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; @Entity +@Slf4j @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Category extends BaseEntity { @@ -35,12 +39,16 @@ public class Category extends BaseEntity { private String color; // --- 도메인 로직 --- - public static Category create(User user, String title, String color) { - return Category.builder() - .user(user) - .title(title) - .color(color) - .build(); + public void updateTitle(String title) { + if (title == null || title.isBlank()) throw new GeneralException(ErrorStatus.TASK_CATEGORY_TITLE_EMPTY); + log.debug("[CATEGORY] 제목 변경 - before: {}, after: {}", this.title, title); + this.title = title; + } + + public void updateColor(String color) { + log.debug("[CATEGORY] 색상 변경 - before: {}, after: {}", this.color, color); + if (color == null || !color.startsWith("#")) throw new GeneralException(ErrorStatus.COLOR_INVALID); + this.color = color; } @Builder diff --git a/src/main/java/com/indayvidual/server/domain/todo/service/category/CategoryCommandService.java b/src/main/java/com/indayvidual/server/domain/todo/service/category/CategoryCommandService.java index a7195b2..5eeaaae 100644 --- a/src/main/java/com/indayvidual/server/domain/todo/service/category/CategoryCommandService.java +++ b/src/main/java/com/indayvidual/server/domain/todo/service/category/CategoryCommandService.java @@ -39,6 +39,20 @@ public CategoryResponseDTO create(CategoryCreateRequestDTO request, Long userId) return categoryConverter.toResponse(saved); } + @Transactional + public CategoryResponseDTO updateCategoryTitleAndColor(CategoryCreateRequestDTO request, Long userId, Long categoryId) { + + User user = userRepository.findById(userId) + .orElseThrow(() -> new GeneralException(ErrorStatus.USER_NOT_FOUND)); + + Category category = categoryRepository.findByIdAndUserId(categoryId, userId) + .orElseThrow(() -> new GeneralException(ErrorStatus.TASK_CATEGORY_NOT_FOUND)); + + category.updateTitle(request.getName()); + category.updateColor(request.getColor()); + return categoryConverter.toResponse(category); + } + @Transactional public void delete(Long userId, Long categoryId) { Category category = categoryRepository.findByIdAndUserId(categoryId, userId) diff --git a/src/main/java/com/indayvidual/server/global/api/code/status/ErrorStatus.java b/src/main/java/com/indayvidual/server/global/api/code/status/ErrorStatus.java index 44dd368..4f1410d 100644 --- a/src/main/java/com/indayvidual/server/global/api/code/status/ErrorStatus.java +++ b/src/main/java/com/indayvidual/server/global/api/code/status/ErrorStatus.java @@ -286,9 +286,15 @@ public enum ErrorStatus implements BaseErrorCode { // ===== 할 일 관련 에러 (TASK) ===== // 할 일 카테고리 TASK_CATEGORY_NOT_FOUND(HttpStatus.NOT_FOUND, "TASK4041", "카테고리를 찾을 수 없습니다."), + TASK_CATEGORY_TITLE_EMPTY(HttpStatus.BAD_REQUEST, "TASK4001", "카테고리 이름이 비어있습니다."), + + // 할 일 TASK_NOT_FOUND(HttpStatus.NOT_FOUND, "TASK4042", "할 일을 찾을 수 없습니다."), TASK_FORBIDDEN(HttpStatus.FORBIDDEN, "TASK4031", "해당 할 일에 대한 권한이 없습니다."), - TASK_INVALID_ORDER(HttpStatus.BAD_REQUEST, "TASK4001", "유효하지 않은 할 일 순서 요청입니다."); + TASK_INVALID_ORDER(HttpStatus.BAD_REQUEST, "TASK4002", "유효하지 않은 할 일 순서 요청입니다."), + + // ===== 색상 관련 에러 (COLOR) ===== + COLOR_INVALID(HttpStatus.BAD_REQUEST, "COLOR4001", "유효하지 않은 색상 코드 형식입니다."); private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/com/indayvidual/server/global/api/code/status/SuccessStatus.java b/src/main/java/com/indayvidual/server/global/api/code/status/SuccessStatus.java index 40c3e70..b89defc 100644 --- a/src/main/java/com/indayvidual/server/global/api/code/status/SuccessStatus.java +++ b/src/main/java/com/indayvidual/server/global/api/code/status/SuccessStatus.java @@ -31,6 +31,7 @@ public enum SuccessStatus implements BaseCode { // 할 일 관련 응답 CREATE_CATEGORY_SUCCESS(HttpStatus.CREATED, "CREATE_CATEGORY_SUCCESS", "카테고리 등록 성공"), + UPDATE_CATEGORY_SUCCESS(HttpStatus.CREATED, "UPDATE_CATEGORY_SUCCESS", "카테고리 수정 성공"), GET_CATEGORIES_SUCCESS(HttpStatus.OK, "GET_CATEGORIES_SUCCESS", "카테고리 목록 조회 성공"), DELETE_CATEGORY_SUCCESS(HttpStatus.OK, "DELETE_CATEGORY_SUCCESS", "카테고리 삭제 성공"), CREATE_TASK_SUCCESS(HttpStatus.CREATED, "CREATE_TASK_SUCCESS", "할일 등록 성공"),