From 67ef788ccd2802388893247aee3b5f10b3f4e81a Mon Sep 17 00:00:00 2001 From: kwonminsooo Date: Sat, 11 Jul 2026 17:16:49 +0900 Subject: [PATCH 1/4] =?UTF-8?q?refactor:=20=ED=99=88=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/home/controller/HomeController.java | 18 +- .../api/home/dto/request/HomeEditRequest.java | 28 +++ .../backend/api/home/service/HomeService.java | 39 ++++ .../setting/controller/SettingController.java | 14 -- .../request/UpdateHomeColorRequestDTO.java | 10 - .../response/UpdateHomeColorResponseDTO.java | 3 - .../api/setting/service/SettingService.java | 13 -- .../sticker/controller/StickerController.java | 59 ------ .../dto/request/StickerCreateRequestDTO.java | 13 -- .../dto/request/StickerUpdateRequestDTO.java | 12 -- .../response/StickerCreateResponseDTO.java | 6 - .../response/StickerDeleteResponseDTO.java | 5 - .../response/StickerUpdateResponseDTO.java | 6 - .../api/sticker/service/StickerService.java | 13 -- .../sticker/service/StickerServiceImpl.java | 88 -------- .../backend/domain/letter/entity/Letter.java | 2 +- .../setting/exception/HomeColorErrorCode.java | 39 ---- .../domain/sticker/entity/UserSticker.java | 18 -- .../sticker/exception/StickerErrorCode.java | 49 ----- .../UserStickerImageQueryRepository.java | 22 -- .../backend/domain/term/entity/Term.java | 2 +- .../backend/api/home/HomeControllerTest.java | 200 ++++++++++++++++++ 22 files changed, 284 insertions(+), 375 deletions(-) create mode 100644 src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequest.java delete mode 100644 src/main/java/com/deare/backend/api/setting/dto/request/UpdateHomeColorRequestDTO.java delete mode 100644 src/main/java/com/deare/backend/api/setting/dto/response/UpdateHomeColorResponseDTO.java delete mode 100644 src/main/java/com/deare/backend/api/sticker/controller/StickerController.java delete mode 100644 src/main/java/com/deare/backend/api/sticker/dto/request/StickerCreateRequestDTO.java delete mode 100644 src/main/java/com/deare/backend/api/sticker/dto/request/StickerUpdateRequestDTO.java delete mode 100644 src/main/java/com/deare/backend/api/sticker/dto/response/StickerCreateResponseDTO.java delete mode 100644 src/main/java/com/deare/backend/api/sticker/dto/response/StickerDeleteResponseDTO.java delete mode 100644 src/main/java/com/deare/backend/api/sticker/dto/response/StickerUpdateResponseDTO.java delete mode 100644 src/main/java/com/deare/backend/api/sticker/service/StickerService.java delete mode 100644 src/main/java/com/deare/backend/api/sticker/service/StickerServiceImpl.java delete mode 100644 src/main/java/com/deare/backend/domain/setting/exception/HomeColorErrorCode.java delete mode 100644 src/main/java/com/deare/backend/domain/sticker/exception/StickerErrorCode.java delete mode 100644 src/main/java/com/deare/backend/domain/sticker/repository/UserStickerImageQueryRepository.java create mode 100644 src/test/java/com/deare/backend/api/home/HomeControllerTest.java diff --git a/src/main/java/com/deare/backend/api/home/controller/HomeController.java b/src/main/java/com/deare/backend/api/home/controller/HomeController.java index 7ebf974e..67ba801c 100644 --- a/src/main/java/com/deare/backend/api/home/controller/HomeController.java +++ b/src/main/java/com/deare/backend/api/home/controller/HomeController.java @@ -1,14 +1,14 @@ package com.deare.backend.api.home.controller; +import com.deare.backend.api.home.dto.request.HomeEditRequest; import com.deare.backend.api.home.dto.response.HomeDashboardResponse; import com.deare.backend.api.home.service.HomeService; import com.deare.backend.global.auth.util.SecurityUtil; import com.deare.backend.global.common.response.ApiResponse; import io.swagger.v3.oas.annotations.Operation; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @RestController @RequiredArgsConstructor @@ -27,4 +27,16 @@ public ApiResponse getHome() { HomeDashboardResponse res = homeService.getHome(userId); return ApiResponse.success(res); } + + @PutMapping("/edit") + @Operation( + summary = "홈 화면 편집 저장", + description = "스티커 배치 , 배경색 변경 등 홈화면 편집 내용을 저장하는 API입니다." + ) + public ApiResponseeditHome(@Valid @RequestBody HomeEditRequest request){ + Long userId = SecurityUtil.getCurrentUserId(); + homeService.editHome(userId, request); + return ApiResponse.success(null); + } + } diff --git a/src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequest.java b/src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequest.java new file mode 100644 index 00000000..e10e9a13 --- /dev/null +++ b/src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequest.java @@ -0,0 +1,28 @@ +package com.deare.backend.api.home.dto.request; + +import jakarta.validation.constraints.Pattern; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; +import java.util.List; + +@Getter +@NoArgsConstructor +public class HomeEditRequest { + @Pattern(regexp = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$", + message = "HEX 색상 코드 형식이 올바르지 않습니다.") + private String homeColor; + private List stickers; + + @Getter + @NoArgsConstructor + public static class StickerRequest { + private Long imageId; + private BigDecimal posX; + private BigDecimal posY; + private Integer posZ; + private BigDecimal rotation; + private BigDecimal scale; + } +} diff --git a/src/main/java/com/deare/backend/api/home/service/HomeService.java b/src/main/java/com/deare/backend/api/home/service/HomeService.java index 55d03760..6b024ffe 100644 --- a/src/main/java/com/deare/backend/api/home/service/HomeService.java +++ b/src/main/java/com/deare/backend/api/home/service/HomeService.java @@ -1,10 +1,14 @@ package com.deare.backend.api.home.service; +import com.deare.backend.api.home.dto.request.HomeEditRequest; import com.deare.backend.api.home.dto.response.HomeDashboardResponse; import com.deare.backend.api.home.dto.result.HomeSettingDto; import com.deare.backend.api.home.dto.result.HomeStickerDto; import com.deare.backend.api.home.dto.result.HomeUserDto; import com.deare.backend.api.home.exception.HomeErrorCode; +import com.deare.backend.domain.image.entity.Image; +import com.deare.backend.domain.image.exception.ImageErrorCode; +import com.deare.backend.domain.image.repository.ImageRepository; import com.deare.backend.domain.setting.entity.UserSetting; import com.deare.backend.domain.setting.repository.UserSettingRepository; import com.deare.backend.domain.sticker.entity.UserSticker; @@ -25,6 +29,7 @@ public class HomeService { private final UserRepository userRepository; private final UserSettingRepository userSettingRepository; private final UserStickerRepository stickerRepository; + private final ImageRepository imageRepository; @Transactional(readOnly=true) public HomeDashboardResponse getHome(Long userId) { @@ -64,6 +69,40 @@ public HomeDashboardResponse getHome(Long userId) { stickerDtos ); } + @Transactional + public void editHome(Long userId, HomeEditRequest request){ + User user = userRepository.findById(userId).orElseThrow(()->new GeneralException(HomeErrorCode.USER_NOT_FOUND)); + + UserSetting userSetting = userSettingRepository.findByUser_Id(userId).orElse(null); + + if(userSetting!=null){ + userSetting.updateHomeColor(request.getHomeColor()); + }else{ + UserSetting newSetting = UserSetting.createDefault(user, request.getHomeColor()); + userSettingRepository.save(newSetting); + } + stickerRepository.deleteAllByUserId(userId); + + List newStickers = request.getStickers().stream() + .map(dto -> { + Image image = imageRepository.findById(dto.getImageId()) + .orElseThrow(() -> new GeneralException(ImageErrorCode.IMAGE_40001)); + + return UserSticker.create( + user, + image, + dto.getPosX(), + dto.getPosY(), + dto.getPosZ(), + dto.getRotation(), + dto.getScale() + ); + }) + .toList(); + + stickerRepository.saveAll(newStickers); + + } private HomeStickerDto toStickerDto(UserSticker sticker) { return new HomeStickerDto( diff --git a/src/main/java/com/deare/backend/api/setting/controller/SettingController.java b/src/main/java/com/deare/backend/api/setting/controller/SettingController.java index 4c248171..421c9c73 100644 --- a/src/main/java/com/deare/backend/api/setting/controller/SettingController.java +++ b/src/main/java/com/deare/backend/api/setting/controller/SettingController.java @@ -1,13 +1,11 @@ package com.deare.backend.api.setting.controller; import com.deare.backend.api.setting.dto.request.UpdateFontRequestDTO; -import com.deare.backend.api.setting.dto.request.UpdateHomeColorRequestDTO; import com.deare.backend.api.setting.dto.response.*; import com.deare.backend.api.setting.service.SettingService; import com.deare.backend.global.auth.util.SecurityUtil; import com.deare.backend.global.common.response.ApiResponse; import io.swagger.v3.oas.annotations.Operation; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; @@ -47,17 +45,5 @@ public ApiResponse upgradeMembership() { Long userId = SecurityUtil.getCurrentUserId(); return ApiResponse.success(settingService.upgradeMembership(userId)); } - @PatchMapping("/homecolor") - @Operation( - summary = "홈 배경색 변경", - description = "사용자의 홈 화면 배경색을 변경하는 API입니다." - ) - public ApiResponse updateHomeColor( - @Valid @RequestBody UpdateHomeColorRequestDTO request - ) { - Long userId = SecurityUtil.getCurrentUserId(); - UpdateHomeColorResponseDTO res = settingService.updateHomeColor(userId, request); - return ApiResponse.success(res); - } } diff --git a/src/main/java/com/deare/backend/api/setting/dto/request/UpdateHomeColorRequestDTO.java b/src/main/java/com/deare/backend/api/setting/dto/request/UpdateHomeColorRequestDTO.java deleted file mode 100644 index 66e96437..00000000 --- a/src/main/java/com/deare/backend/api/setting/dto/request/UpdateHomeColorRequestDTO.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.deare.backend.api.setting.dto.request; - -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Pattern; - -public record UpdateHomeColorRequestDTO( - @NotBlank - @Pattern(regexp = "^#[0-9A-Fa-f]{6}$") - String homeColor -) {} diff --git a/src/main/java/com/deare/backend/api/setting/dto/response/UpdateHomeColorResponseDTO.java b/src/main/java/com/deare/backend/api/setting/dto/response/UpdateHomeColorResponseDTO.java deleted file mode 100644 index 4979fdf9..00000000 --- a/src/main/java/com/deare/backend/api/setting/dto/response/UpdateHomeColorResponseDTO.java +++ /dev/null @@ -1,3 +0,0 @@ -package com.deare.backend.api.setting.dto.response; - -public record UpdateHomeColorResponseDTO(String homeColor) {} diff --git a/src/main/java/com/deare/backend/api/setting/service/SettingService.java b/src/main/java/com/deare/backend/api/setting/service/SettingService.java index 7e09c642..92a32559 100644 --- a/src/main/java/com/deare/backend/api/setting/service/SettingService.java +++ b/src/main/java/com/deare/backend/api/setting/service/SettingService.java @@ -1,12 +1,10 @@ package com.deare.backend.api.setting.service; import com.deare.backend.api.setting.dto.request.UpdateFontRequestDTO; -import com.deare.backend.api.setting.dto.request.UpdateHomeColorRequestDTO; import com.deare.backend.api.setting.dto.response.*; import com.deare.backend.domain.setting.entity.enums.Font; import com.deare.backend.domain.setting.entity.enums.MembershipPlan; import com.deare.backend.domain.setting.entity.UserSetting; -import com.deare.backend.domain.setting.exception.HomeColorErrorCode; import com.deare.backend.domain.setting.exception.MembershipErrorCode; import com.deare.backend.domain.setting.exception.ThemeErrorCode; import com.deare.backend.domain.setting.repository.UserSettingRepository; @@ -89,16 +87,5 @@ private Font parseFontOrThrow422(String raw) { throw new GeneralException(ThemeErrorCode.THEME_UNPROCESSABLE_ENTITY); } } - @Transactional - public UpdateHomeColorResponseDTO updateHomeColor(Long userId, UpdateHomeColorRequestDTO request) { - - settingWriteService.ensureSettingExists(userId); - - UserSetting setting = userSettingRepository.findByUser_Id(userId) - .orElseThrow(() -> new GeneralException(HomeColorErrorCode.SETTING_NOT_FOUND )); - - setting.updateHomeColor(request.homeColor()); - return new UpdateHomeColorResponseDTO(setting.getHomeColor()); - } } diff --git a/src/main/java/com/deare/backend/api/sticker/controller/StickerController.java b/src/main/java/com/deare/backend/api/sticker/controller/StickerController.java deleted file mode 100644 index 979bb2c9..00000000 --- a/src/main/java/com/deare/backend/api/sticker/controller/StickerController.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.deare.backend.api.sticker.controller; - -import com.deare.backend.api.sticker.dto.request.StickerCreateRequestDTO; -import com.deare.backend.api.sticker.dto.request.StickerUpdateRequestDTO; -import com.deare.backend.api.sticker.dto.response.StickerCreateResponseDTO; -import com.deare.backend.api.sticker.dto.response.StickerDeleteResponseDTO; -import com.deare.backend.api.sticker.dto.response.StickerUpdateResponseDTO; -import com.deare.backend.api.sticker.service.StickerService; -import com.deare.backend.global.auth.util.SecurityUtil; -import com.deare.backend.global.common.response.ApiResponse; -import io.swagger.v3.oas.annotations.Operation; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; - -@RestController -@RequestMapping("/stickers") -@RequiredArgsConstructor -public class StickerController { - - private final StickerService stickerService; - - @PostMapping - @Operation( - summary = "스티커 추가", - description = "홈 화면에 스티커를 추가하는 API입니다." - ) - public ApiResponse createSticker( - @Valid @RequestBody StickerCreateRequestDTO request - ) { - Long userId = SecurityUtil.getCurrentUserId(); - return ApiResponse.success(stickerService.create(userId, request)); - } - - @PatchMapping("/{stickerId}") - @Operation( - summary = "스티커 수정", - description = "홈 화면에 배치된 스티커의 위치/회전/크기를 수정하는 API입니다." - ) - public ApiResponse updateSticker( - @PathVariable Long stickerId, - @Valid @RequestBody StickerUpdateRequestDTO request - ) { - Long userId = SecurityUtil.getCurrentUserId(); - return ApiResponse.success(stickerService.update(userId, stickerId, request)); - } - - @DeleteMapping("/{stickerId}") - @Operation( - summary = "스티커 삭제", - description = "홈 화면에 배치된 스티커를 삭제하는 API입니다." - ) - public ApiResponse deleteSticker( - @PathVariable Long stickerId - ) { - Long userId = SecurityUtil.getCurrentUserId(); - return ApiResponse.success(stickerService.delete(userId, stickerId)); - } -} diff --git a/src/main/java/com/deare/backend/api/sticker/dto/request/StickerCreateRequestDTO.java b/src/main/java/com/deare/backend/api/sticker/dto/request/StickerCreateRequestDTO.java deleted file mode 100644 index faa598c4..00000000 --- a/src/main/java/com/deare/backend/api/sticker/dto/request/StickerCreateRequestDTO.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.deare.backend.api.sticker.dto.request; - -import java.math.BigDecimal; - -public record StickerCreateRequestDTO( - Long imageId, - BigDecimal posX, - BigDecimal posY, - Integer posZ, - BigDecimal rotation, - BigDecimal scale -) { -} diff --git a/src/main/java/com/deare/backend/api/sticker/dto/request/StickerUpdateRequestDTO.java b/src/main/java/com/deare/backend/api/sticker/dto/request/StickerUpdateRequestDTO.java deleted file mode 100644 index a1a4ce56..00000000 --- a/src/main/java/com/deare/backend/api/sticker/dto/request/StickerUpdateRequestDTO.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.deare.backend.api.sticker.dto.request; - -import java.math.BigDecimal; - -public record StickerUpdateRequestDTO( - BigDecimal posX, - BigDecimal posY, - Integer posZ, - BigDecimal rotation, - BigDecimal scale -) { -} diff --git a/src/main/java/com/deare/backend/api/sticker/dto/response/StickerCreateResponseDTO.java b/src/main/java/com/deare/backend/api/sticker/dto/response/StickerCreateResponseDTO.java deleted file mode 100644 index d795272a..00000000 --- a/src/main/java/com/deare/backend/api/sticker/dto/response/StickerCreateResponseDTO.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.deare.backend.api.sticker.dto.response; - -public record StickerCreateResponseDTO( - Long stickerId -) { -} diff --git a/src/main/java/com/deare/backend/api/sticker/dto/response/StickerDeleteResponseDTO.java b/src/main/java/com/deare/backend/api/sticker/dto/response/StickerDeleteResponseDTO.java deleted file mode 100644 index 4c257fdb..00000000 --- a/src/main/java/com/deare/backend/api/sticker/dto/response/StickerDeleteResponseDTO.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.deare.backend.api.sticker.dto.response; - -public record StickerDeleteResponseDTO( - Long stickerId -) {} diff --git a/src/main/java/com/deare/backend/api/sticker/dto/response/StickerUpdateResponseDTO.java b/src/main/java/com/deare/backend/api/sticker/dto/response/StickerUpdateResponseDTO.java deleted file mode 100644 index 758a33cf..00000000 --- a/src/main/java/com/deare/backend/api/sticker/dto/response/StickerUpdateResponseDTO.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.deare.backend.api.sticker.dto.response; - -public record StickerUpdateResponseDTO( - Long stickerId -) { -} diff --git a/src/main/java/com/deare/backend/api/sticker/service/StickerService.java b/src/main/java/com/deare/backend/api/sticker/service/StickerService.java deleted file mode 100644 index 0077f6c5..00000000 --- a/src/main/java/com/deare/backend/api/sticker/service/StickerService.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.deare.backend.api.sticker.service; - -import com.deare.backend.api.sticker.dto.request.StickerCreateRequestDTO; -import com.deare.backend.api.sticker.dto.request.StickerUpdateRequestDTO; -import com.deare.backend.api.sticker.dto.response.StickerCreateResponseDTO; -import com.deare.backend.api.sticker.dto.response.StickerDeleteResponseDTO; -import com.deare.backend.api.sticker.dto.response.StickerUpdateResponseDTO; - -public interface StickerService { - StickerCreateResponseDTO create(Long userId, StickerCreateRequestDTO request); - StickerUpdateResponseDTO update(Long userId, Long stickerId, StickerUpdateRequestDTO request); - StickerDeleteResponseDTO delete(Long userId, Long stickerId); -} diff --git a/src/main/java/com/deare/backend/api/sticker/service/StickerServiceImpl.java b/src/main/java/com/deare/backend/api/sticker/service/StickerServiceImpl.java deleted file mode 100644 index a99ff170..00000000 --- a/src/main/java/com/deare/backend/api/sticker/service/StickerServiceImpl.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.deare.backend.api.sticker.service; - -import com.deare.backend.api.sticker.dto.request.StickerCreateRequestDTO; -import com.deare.backend.api.sticker.dto.request.StickerUpdateRequestDTO; -import com.deare.backend.api.sticker.dto.response.StickerCreateResponseDTO; -import com.deare.backend.api.sticker.dto.response.StickerDeleteResponseDTO; -import com.deare.backend.api.sticker.dto.response.StickerUpdateResponseDTO; -import com.deare.backend.domain.image.entity.Image; -import com.deare.backend.domain.image.exception.ImageErrorCode; -import com.deare.backend.domain.image.repository.ImageRepository; -import com.deare.backend.domain.sticker.entity.UserSticker; -import com.deare.backend.domain.sticker.exception.StickerErrorCode; -import com.deare.backend.domain.sticker.repository.UserStickerImageQueryRepository; -import com.deare.backend.domain.sticker.repository.UserStickerRepository; -import com.deare.backend.domain.user.entity.User; -import com.deare.backend.domain.user.exception.UserErrorCode; -import com.deare.backend.domain.user.repository.UserRepository; -import com.deare.backend.global.common.exception.GeneralException; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -@Transactional -public class StickerServiceImpl implements StickerService { - - private final UserStickerRepository userStickerRepository; - private final UserRepository userRepository; - private final ImageRepository imageRepository; - private final UserStickerImageQueryRepository userStickerImageQueryRepository; - - @Override - public StickerCreateResponseDTO create(Long userId, StickerCreateRequestDTO request) { - User user = userRepository.findById(userId) - .orElseThrow(() -> new GeneralException(UserErrorCode.USER_NOT_FOUND)); - - Image image = imageRepository.findById(request.imageId()) - .orElseThrow(() -> new GeneralException(ImageErrorCode.IMAGE_40001)); - - UserSticker sticker = UserSticker.create( - user, - image, - request.posX(), - request.posY(), - request.posZ(), - request.rotation(), - request.scale() - ); - - UserSticker saved = userStickerRepository.save(sticker); - return new StickerCreateResponseDTO(saved.getId()); - } - - @Override - public StickerUpdateResponseDTO update(Long userId, Long stickerId, StickerUpdateRequestDTO request) { - UserSticker sticker = userStickerRepository.findById(stickerId) - .orElseThrow(() -> new GeneralException(StickerErrorCode.NOT_FOUND)); - - if (!sticker.isOwnedBy(userId)) { - throw new GeneralException(StickerErrorCode.FORBIDDEN); - } - - sticker.updateTransform( - request.posX(), - request.posY(), - request.posZ(), - request.rotation(), - request.scale() - ); - - return new StickerUpdateResponseDTO(sticker.getId()); - } - - @Override - public StickerDeleteResponseDTO delete(Long userId, Long stickerId) { - UserSticker sticker = userStickerRepository.findById(stickerId) - .orElseThrow(() -> new GeneralException(StickerErrorCode.NOT_FOUND)); - - if (!sticker.isOwnedBy(userId)) { - throw new GeneralException(StickerErrorCode.FORBIDDEN); - } - - userStickerRepository.delete(sticker); - return new StickerDeleteResponseDTO(stickerId); - } -} - diff --git a/src/main/java/com/deare/backend/domain/letter/entity/Letter.java b/src/main/java/com/deare/backend/domain/letter/entity/Letter.java index 4cec7ff6..9950abbe 100644 --- a/src/main/java/com/deare/backend/domain/letter/entity/Letter.java +++ b/src/main/java/com/deare/backend/domain/letter/entity/Letter.java @@ -27,7 +27,7 @@ public class Letter extends BaseEntity { private Long id; @Lob - @Column(name="content", columnDefinition = "TEXT", nullable = false) + @Column(name="content", columnDefinition = "LONGTEXT", nullable = false) private String content; @Column(name="received_at") diff --git a/src/main/java/com/deare/backend/domain/setting/exception/HomeColorErrorCode.java b/src/main/java/com/deare/backend/domain/setting/exception/HomeColorErrorCode.java deleted file mode 100644 index 5920f38b..00000000 --- a/src/main/java/com/deare/backend/domain/setting/exception/HomeColorErrorCode.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.deare.backend.domain.setting.exception; - -import com.deare.backend.global.common.exception.BaseErrorCode; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; - -@Getter -@RequiredArgsConstructor -public enum HomeColorErrorCode implements BaseErrorCode { - - INVALID_REQUEST( - HttpStatus.BAD_REQUEST, - "HOME_COLOR_40001", - "잘못된 홈 배경색 요청입니다." - ), - - UNAUTHORIZED( - HttpStatus.UNAUTHORIZED, - "HOME_COLOR_40101", - "로그인이 필요한 요청입니다." - ), - - SETTING_NOT_FOUND( - HttpStatus.NOT_FOUND, - "HOME_COLOR_40401", - "사용자 설정 정보를 찾을 수 없습니다." - ), - - INTERNAL_ERROR( - HttpStatus.INTERNAL_SERVER_ERROR, - "HOME_COLOR_50001", - "홈 배경색 변경 중 서버 오류가 발생했습니다." - ); - - private final HttpStatus status; - private final String code; - private final String message; -} diff --git a/src/main/java/com/deare/backend/domain/sticker/entity/UserSticker.java b/src/main/java/com/deare/backend/domain/sticker/entity/UserSticker.java index bd134ff8..39c45bfc 100644 --- a/src/main/java/com/deare/backend/domain/sticker/entity/UserSticker.java +++ b/src/main/java/com/deare/backend/domain/sticker/entity/UserSticker.java @@ -61,22 +61,4 @@ public static UserSticker create( us.scale = scale; return us; } - public boolean isOwnedBy(Long userId) { - return user != null && user.getId() != null && user.getId().equals(userId); - } - - public void updateTransform( - BigDecimal posX, - BigDecimal posY, - int posZ, - BigDecimal rotation, - BigDecimal scale - ) { - this.posX = posX; - this.posY = posY; - this.posZ = posZ; - this.rotation = rotation; - this.scale = scale; - } - } diff --git a/src/main/java/com/deare/backend/domain/sticker/exception/StickerErrorCode.java b/src/main/java/com/deare/backend/domain/sticker/exception/StickerErrorCode.java deleted file mode 100644 index 5b333a82..00000000 --- a/src/main/java/com/deare/backend/domain/sticker/exception/StickerErrorCode.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.deare.backend.domain.sticker.exception; - -import com.deare.backend.global.common.exception.BaseErrorCode; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; - -@Getter -@RequiredArgsConstructor -public enum StickerErrorCode implements BaseErrorCode { - - INVALID_REQUEST( - HttpStatus.BAD_REQUEST, - "STICKER_40001", - "잘못된 요청입니다." - ), - - UNAUTHORIZED( - HttpStatus.UNAUTHORIZED, - "STICKER_40101", - "로그인이 필요한 요청입니다." - ), - FORBIDDEN( - HttpStatus.FORBIDDEN, - "STICKER_40301", - "스티커에 대한 권한이 없습니다." - ), - IMAGE_NOT_FOUND( - HttpStatus.NOT_FOUND, - "STICKER_40401", - "이미지를 찾을 수 없습니다." - ), - NOT_FOUND( - HttpStatus.NOT_FOUND, - "STICKER_40402", - "스티커를 찾을 수 없습니다." - ), - - - INTERNAL_ERROR( - HttpStatus.INTERNAL_SERVER_ERROR, - "STICKER_50001", - "스티커 생성 중 서버 오류가 발생했습니다." - ); - - private final HttpStatus status; - private final String code; - private final String message; -} diff --git a/src/main/java/com/deare/backend/domain/sticker/repository/UserStickerImageQueryRepository.java b/src/main/java/com/deare/backend/domain/sticker/repository/UserStickerImageQueryRepository.java deleted file mode 100644 index fd6fab2b..00000000 --- a/src/main/java/com/deare/backend/domain/sticker/repository/UserStickerImageQueryRepository.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.deare.backend.domain.sticker.repository; - -import com.deare.backend.domain.sticker.entity.UserSticker; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; - -import java.util.List; - -public interface UserStickerImageQueryRepository extends JpaRepository { - - @Query(""" - select us.image.id - from UserSticker us - where us.user.id = :userId - and us.image.id in :imageIds - """) - List findOwnedImageIds( - @Param("userId") Long userId, - @Param("imageIds") List imageIds - ); -} diff --git a/src/main/java/com/deare/backend/domain/term/entity/Term.java b/src/main/java/com/deare/backend/domain/term/entity/Term.java index 27b00d6b..9fe51855 100644 --- a/src/main/java/com/deare/backend/domain/term/entity/Term.java +++ b/src/main/java/com/deare/backend/domain/term/entity/Term.java @@ -26,7 +26,7 @@ public class Term extends BaseEntity { private TermType type; @Lob - @Column(name = "content", nullable = false) + @Column(name = "content", columnDefinition = "MEDIUMTEXT", nullable = false, length = 16777215) private String content; @Column(name = "is_required", nullable = false) diff --git a/src/test/java/com/deare/backend/api/home/HomeControllerTest.java b/src/test/java/com/deare/backend/api/home/HomeControllerTest.java new file mode 100644 index 00000000..fc85a427 --- /dev/null +++ b/src/test/java/com/deare/backend/api/home/HomeControllerTest.java @@ -0,0 +1,200 @@ +package com.deare.backend.api.home; + +import com.deare.backend.domain.image.entity.Image; +import com.deare.backend.domain.image.entity.enums.ContentType; +import com.deare.backend.domain.image.entity.enums.FileType; +import com.deare.backend.domain.image.repository.ImageRepository; +import com.deare.backend.domain.setting.entity.UserSetting; +import com.deare.backend.domain.setting.repository.UserSettingRepository; +import com.deare.backend.domain.sticker.entity.UserSticker; +import com.deare.backend.domain.sticker.repository.UserStickerRepository; +import com.deare.backend.domain.user.entity.User; +import com.deare.backend.domain.user.entity.enums.Provider; +import com.deare.backend.domain.user.repository.UserRepository; +import com.deare.backend.global.auth.jwt.JwtProvider; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@ActiveProfiles("test") +@SpringBootTest +@AutoConfigureMockMvc +class HomeControllerTest { + + @Autowired private MockMvc mockMvc; + @Autowired private ObjectMapper objectMapper; + @Autowired private UserRepository userRepository; + @Autowired private UserSettingRepository userSettingRepository; + @Autowired private UserStickerRepository userStickerRepository; + @Autowired private ImageRepository imageRepository; + @Autowired private JwtProvider jwtProvider; + + private User user; + private String accessToken; + private Image image1; + private Image image2; + + @BeforeEach + void setUp() { + userStickerRepository.deleteAll(); + userSettingRepository.deleteAll(); + imageRepository.deleteAll(); + userRepository.deleteAll(); + + user = userRepository.save(User.signUpUser(Provider.KAKAO, "home-user-1", "home@test.com", "홈유저")); + accessToken = jwtProvider.generateAccessToken(user); + + image1 = imageRepository.save(Image.create("key1", "https://cdn.test/1.png", "1.png", FileType.PNG, 1024L, ContentType.STICKER)); + image2 = imageRepository.save(Image.create("key2", "https://cdn.test/2.png", "2.png", FileType.PNG, 2048L, ContentType.STICKER)); + } + + private String editHomeRequest(String homeColor, List> stickers) throws Exception { + return objectMapper.writeValueAsString(Map.of( + "homeColor", homeColor, + "stickers", stickers + )); + } + + private Map stickerPayload(Long imageId, double posX, double posY, int posZ, double rotation, double scale) { + return Map.of( + "imageId", imageId, + "posX", posX, + "posY", posY, + "posZ", posZ, + "rotation", rotation, + "scale", scale + ); + } + + @Test + @DisplayName("홈 편집 - 배경색과 스티커가 한 번에 저장된다") + void editHome_success() throws Exception { + String body = editHomeRequest("#FFAA00", List.of( + stickerPayload(image1.getId(), 10.5, 20.25, 1, 45.0, 1.5) + )); + + mockMvc.perform(put("/api/v1/home/edit") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(body)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.success").value(true)); + + UserSetting setting = userSettingRepository.findByUser_Id(user.getId()).orElseThrow(); + assertThat(setting.getHomeColor()).isEqualTo("#FFAA00"); + + List stickers = userStickerRepository.findAllByUser_IdOrderByPosZAsc(user.getId()); + assertThat(stickers).hasSize(1); + assertThat(stickers.get(0).getImage().getId()).isEqualTo(image1.getId()); + assertThat(stickers.get(0).getPosZ()).isEqualTo(1); + + mockMvc.perform(get("/api/v1/home").header("Authorization", "Bearer " + accessToken)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.setting.homeColor").value("#FFAA00")) + .andExpect(jsonPath("$.data.stickers", hasSize(1))) + .andExpect(jsonPath("$.data.stickers[0].imageId").value(image1.getId())); + } + + @Test + @DisplayName("홈 편집 - UserSetting이 없는 유저도 새로 생성되며 저장된다") + void editHome_createsSettingWhenMissing() throws Exception { + assertThat(userSettingRepository.findByUser_Id(user.getId())).isEmpty(); + + String body = editHomeRequest("#123456", List.of()); + + mockMvc.perform(put("/api/v1/home/edit") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(body)) + .andExpect(status().isOk()); + + UserSetting setting = userSettingRepository.findByUser_Id(user.getId()).orElseThrow(); + assertThat(setting.getHomeColor()).isEqualTo("#123456"); + } + + @Test + @DisplayName("홈 편집 - 재저장 시 기존 스티커는 새 스티커로 완전히 교체된다") + void editHome_replacesExistingStickers() throws Exception { + String firstBody = editHomeRequest("#FFFFFF", List.of( + stickerPayload(image1.getId(), 1.0, 1.0, 1, 0.0, 1.0) + )); + mockMvc.perform(put("/api/v1/home/edit") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(firstBody)) + .andExpect(status().isOk()); + assertThat(userStickerRepository.findAllByUser_IdOrderByPosZAsc(user.getId())).hasSize(1); + + String secondBody = editHomeRequest("#000000", List.of( + stickerPayload(image2.getId(), 5.0, 5.0, 2, 90.0, 2.0) + )); + mockMvc.perform(put("/api/v1/home/edit") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(secondBody)) + .andExpect(status().isOk()); + + List stickers = userStickerRepository.findAllByUser_IdOrderByPosZAsc(user.getId()); + assertThat(stickers).hasSize(1); + assertThat(stickers.get(0).getImage().getId()).isEqualTo(image2.getId()); + + UserSetting setting = userSettingRepository.findByUser_Id(user.getId()).orElseThrow(); + assertThat(setting.getHomeColor()).isEqualTo("#000000"); + } + + @Test + @DisplayName("홈 편집 - 잘못된 HEX 색상 형식이면 400 에러") + void editHome_invalidHomeColor() throws Exception { + String body = editHomeRequest("blue", List.of()); + + mockMvc.perform(put("/api/v1/home/edit") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(body)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value("COMMON_400_VALIDATION")); + + assertThat(userSettingRepository.findByUser_Id(user.getId())).isEmpty(); + } + + @Test + @DisplayName("홈 편집 - 존재하지 않는 이미지를 스티커로 참조하면 에러") + void editHome_imageNotFound() throws Exception { + String body = editHomeRequest("#ABCDEF", List.of( + stickerPayload(999999L, 0.0, 0.0, 0, 0.0, 1.0) + )); + + mockMvc.perform(put("/api/v1/home/edit") + .header("Authorization", "Bearer " + accessToken) + .contentType(MediaType.APPLICATION_JSON) + .content(body)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value("IMAGE_40001")); + } + + @Test + @DisplayName("홈 편집 - 인증 토큰 없으면 401") + void editHome_unauthorized() throws Exception { + String body = editHomeRequest("#ABCDEF", List.of()); + + mockMvc.perform(put("/api/v1/home/edit") + .contentType(MediaType.APPLICATION_JSON) + .content(body)) + .andExpect(status().isUnauthorized()); + } +} From bf42d5165cb9678e0ab2f05635200d8dce1a4dfa Mon Sep 17 00:00:00 2001 From: kwonminsooo Date: Sat, 11 Jul 2026 17:27:49 +0900 Subject: [PATCH 2/4] =?UTF-8?q?test=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/api/home/HomeControllerTest.java | 200 ------------------ 1 file changed, 200 deletions(-) delete mode 100644 src/test/java/com/deare/backend/api/home/HomeControllerTest.java diff --git a/src/test/java/com/deare/backend/api/home/HomeControllerTest.java b/src/test/java/com/deare/backend/api/home/HomeControllerTest.java deleted file mode 100644 index fc85a427..00000000 --- a/src/test/java/com/deare/backend/api/home/HomeControllerTest.java +++ /dev/null @@ -1,200 +0,0 @@ -package com.deare.backend.api.home; - -import com.deare.backend.domain.image.entity.Image; -import com.deare.backend.domain.image.entity.enums.ContentType; -import com.deare.backend.domain.image.entity.enums.FileType; -import com.deare.backend.domain.image.repository.ImageRepository; -import com.deare.backend.domain.setting.entity.UserSetting; -import com.deare.backend.domain.setting.repository.UserSettingRepository; -import com.deare.backend.domain.sticker.entity.UserSticker; -import com.deare.backend.domain.sticker.repository.UserStickerRepository; -import com.deare.backend.domain.user.entity.User; -import com.deare.backend.domain.user.entity.enums.Provider; -import com.deare.backend.domain.user.repository.UserRepository; -import com.deare.backend.global.auth.jwt.JwtProvider; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.web.servlet.MockMvc; - -import java.util.List; -import java.util.Map; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasSize; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - -@ActiveProfiles("test") -@SpringBootTest -@AutoConfigureMockMvc -class HomeControllerTest { - - @Autowired private MockMvc mockMvc; - @Autowired private ObjectMapper objectMapper; - @Autowired private UserRepository userRepository; - @Autowired private UserSettingRepository userSettingRepository; - @Autowired private UserStickerRepository userStickerRepository; - @Autowired private ImageRepository imageRepository; - @Autowired private JwtProvider jwtProvider; - - private User user; - private String accessToken; - private Image image1; - private Image image2; - - @BeforeEach - void setUp() { - userStickerRepository.deleteAll(); - userSettingRepository.deleteAll(); - imageRepository.deleteAll(); - userRepository.deleteAll(); - - user = userRepository.save(User.signUpUser(Provider.KAKAO, "home-user-1", "home@test.com", "홈유저")); - accessToken = jwtProvider.generateAccessToken(user); - - image1 = imageRepository.save(Image.create("key1", "https://cdn.test/1.png", "1.png", FileType.PNG, 1024L, ContentType.STICKER)); - image2 = imageRepository.save(Image.create("key2", "https://cdn.test/2.png", "2.png", FileType.PNG, 2048L, ContentType.STICKER)); - } - - private String editHomeRequest(String homeColor, List> stickers) throws Exception { - return objectMapper.writeValueAsString(Map.of( - "homeColor", homeColor, - "stickers", stickers - )); - } - - private Map stickerPayload(Long imageId, double posX, double posY, int posZ, double rotation, double scale) { - return Map.of( - "imageId", imageId, - "posX", posX, - "posY", posY, - "posZ", posZ, - "rotation", rotation, - "scale", scale - ); - } - - @Test - @DisplayName("홈 편집 - 배경색과 스티커가 한 번에 저장된다") - void editHome_success() throws Exception { - String body = editHomeRequest("#FFAA00", List.of( - stickerPayload(image1.getId(), 10.5, 20.25, 1, 45.0, 1.5) - )); - - mockMvc.perform(put("/api/v1/home/edit") - .header("Authorization", "Bearer " + accessToken) - .contentType(MediaType.APPLICATION_JSON) - .content(body)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.success").value(true)); - - UserSetting setting = userSettingRepository.findByUser_Id(user.getId()).orElseThrow(); - assertThat(setting.getHomeColor()).isEqualTo("#FFAA00"); - - List stickers = userStickerRepository.findAllByUser_IdOrderByPosZAsc(user.getId()); - assertThat(stickers).hasSize(1); - assertThat(stickers.get(0).getImage().getId()).isEqualTo(image1.getId()); - assertThat(stickers.get(0).getPosZ()).isEqualTo(1); - - mockMvc.perform(get("/api/v1/home").header("Authorization", "Bearer " + accessToken)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.data.setting.homeColor").value("#FFAA00")) - .andExpect(jsonPath("$.data.stickers", hasSize(1))) - .andExpect(jsonPath("$.data.stickers[0].imageId").value(image1.getId())); - } - - @Test - @DisplayName("홈 편집 - UserSetting이 없는 유저도 새로 생성되며 저장된다") - void editHome_createsSettingWhenMissing() throws Exception { - assertThat(userSettingRepository.findByUser_Id(user.getId())).isEmpty(); - - String body = editHomeRequest("#123456", List.of()); - - mockMvc.perform(put("/api/v1/home/edit") - .header("Authorization", "Bearer " + accessToken) - .contentType(MediaType.APPLICATION_JSON) - .content(body)) - .andExpect(status().isOk()); - - UserSetting setting = userSettingRepository.findByUser_Id(user.getId()).orElseThrow(); - assertThat(setting.getHomeColor()).isEqualTo("#123456"); - } - - @Test - @DisplayName("홈 편집 - 재저장 시 기존 스티커는 새 스티커로 완전히 교체된다") - void editHome_replacesExistingStickers() throws Exception { - String firstBody = editHomeRequest("#FFFFFF", List.of( - stickerPayload(image1.getId(), 1.0, 1.0, 1, 0.0, 1.0) - )); - mockMvc.perform(put("/api/v1/home/edit") - .header("Authorization", "Bearer " + accessToken) - .contentType(MediaType.APPLICATION_JSON) - .content(firstBody)) - .andExpect(status().isOk()); - assertThat(userStickerRepository.findAllByUser_IdOrderByPosZAsc(user.getId())).hasSize(1); - - String secondBody = editHomeRequest("#000000", List.of( - stickerPayload(image2.getId(), 5.0, 5.0, 2, 90.0, 2.0) - )); - mockMvc.perform(put("/api/v1/home/edit") - .header("Authorization", "Bearer " + accessToken) - .contentType(MediaType.APPLICATION_JSON) - .content(secondBody)) - .andExpect(status().isOk()); - - List stickers = userStickerRepository.findAllByUser_IdOrderByPosZAsc(user.getId()); - assertThat(stickers).hasSize(1); - assertThat(stickers.get(0).getImage().getId()).isEqualTo(image2.getId()); - - UserSetting setting = userSettingRepository.findByUser_Id(user.getId()).orElseThrow(); - assertThat(setting.getHomeColor()).isEqualTo("#000000"); - } - - @Test - @DisplayName("홈 편집 - 잘못된 HEX 색상 형식이면 400 에러") - void editHome_invalidHomeColor() throws Exception { - String body = editHomeRequest("blue", List.of()); - - mockMvc.perform(put("/api/v1/home/edit") - .header("Authorization", "Bearer " + accessToken) - .contentType(MediaType.APPLICATION_JSON) - .content(body)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.code").value("COMMON_400_VALIDATION")); - - assertThat(userSettingRepository.findByUser_Id(user.getId())).isEmpty(); - } - - @Test - @DisplayName("홈 편집 - 존재하지 않는 이미지를 스티커로 참조하면 에러") - void editHome_imageNotFound() throws Exception { - String body = editHomeRequest("#ABCDEF", List.of( - stickerPayload(999999L, 0.0, 0.0, 0, 0.0, 1.0) - )); - - mockMvc.perform(put("/api/v1/home/edit") - .header("Authorization", "Bearer " + accessToken) - .contentType(MediaType.APPLICATION_JSON) - .content(body)) - .andExpect(status().isBadRequest()) - .andExpect(jsonPath("$.code").value("IMAGE_40001")); - } - - @Test - @DisplayName("홈 편집 - 인증 토큰 없으면 401") - void editHome_unauthorized() throws Exception { - String body = editHomeRequest("#ABCDEF", List.of()); - - mockMvc.perform(put("/api/v1/home/edit") - .contentType(MediaType.APPLICATION_JSON) - .content(body)) - .andExpect(status().isUnauthorized()); - } -} From 45b8b94cc81459eb931fa76109d35ab7d6ea0506 Mon Sep 17 00:00:00 2001 From: kwonminsooo Date: Thu, 16 Jul 2026 16:26:39 +0900 Subject: [PATCH 3/4] =?UTF-8?q?pr=20=EB=A6=AC=EB=B7=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/home/controller/HomeController.java | 6 +- .../api/home/dto/request/HomeEditRequest.java | 28 ---------- .../home/dto/request/HomeEditRequestDTO.java | 24 ++++++++ .../backend/api/home/service/HomeService.java | 55 ++++++++++++------- 4 files changed, 61 insertions(+), 52 deletions(-) delete mode 100644 src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequest.java create mode 100644 src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequestDTO.java diff --git a/src/main/java/com/deare/backend/api/home/controller/HomeController.java b/src/main/java/com/deare/backend/api/home/controller/HomeController.java index 67ba801c..8f3af607 100644 --- a/src/main/java/com/deare/backend/api/home/controller/HomeController.java +++ b/src/main/java/com/deare/backend/api/home/controller/HomeController.java @@ -1,6 +1,6 @@ package com.deare.backend.api.home.controller; -import com.deare.backend.api.home.dto.request.HomeEditRequest; +import com.deare.backend.api.home.dto.request.HomeEditRequestDTO; import com.deare.backend.api.home.dto.response.HomeDashboardResponse; import com.deare.backend.api.home.service.HomeService; import com.deare.backend.global.auth.util.SecurityUtil; @@ -28,12 +28,12 @@ public ApiResponse getHome() { return ApiResponse.success(res); } - @PutMapping("/edit") + @PutMapping @Operation( summary = "홈 화면 편집 저장", description = "스티커 배치 , 배경색 변경 등 홈화면 편집 내용을 저장하는 API입니다." ) - public ApiResponseeditHome(@Valid @RequestBody HomeEditRequest request){ + public ApiResponse editHome(@Valid @RequestBody HomeEditRequestDTO request){ Long userId = SecurityUtil.getCurrentUserId(); homeService.editHome(userId, request); return ApiResponse.success(null); diff --git a/src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequest.java b/src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequest.java deleted file mode 100644 index e10e9a13..00000000 --- a/src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequest.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.deare.backend.api.home.dto.request; - -import jakarta.validation.constraints.Pattern; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.math.BigDecimal; -import java.util.List; - -@Getter -@NoArgsConstructor -public class HomeEditRequest { - @Pattern(regexp = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$", - message = "HEX 색상 코드 형식이 올바르지 않습니다.") - private String homeColor; - private List stickers; - - @Getter - @NoArgsConstructor - public static class StickerRequest { - private Long imageId; - private BigDecimal posX; - private BigDecimal posY; - private Integer posZ; - private BigDecimal rotation; - private BigDecimal scale; - } -} diff --git a/src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequestDTO.java b/src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequestDTO.java new file mode 100644 index 00000000..e1e747c6 --- /dev/null +++ b/src/main/java/com/deare/backend/api/home/dto/request/HomeEditRequestDTO.java @@ -0,0 +1,24 @@ +package com.deare.backend.api.home.dto.request; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; + +import java.math.BigDecimal; +import java.util.List; + +public record HomeEditRequestDTO( + @NotBlank + @Pattern(regexp = "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$", + message = "HEX 색상 코드 형식이 올바르지 않습니다.") + String homeColor, List stickers +) { + @NotNull + public record StickerRequest( + Long imageId, + BigDecimal posX, + BigDecimal posY, + Integer posZ, + BigDecimal rotation, + BigDecimal scale + ){} +} \ No newline at end of file diff --git a/src/main/java/com/deare/backend/api/home/service/HomeService.java b/src/main/java/com/deare/backend/api/home/service/HomeService.java index 6b024ffe..b5d45b8d 100644 --- a/src/main/java/com/deare/backend/api/home/service/HomeService.java +++ b/src/main/java/com/deare/backend/api/home/service/HomeService.java @@ -1,6 +1,7 @@ package com.deare.backend.api.home.service; -import com.deare.backend.api.home.dto.request.HomeEditRequest; +import com.deare.backend.api.home.dto.request.HomeEditRequestDTO; +import com.deare.backend.api.home.dto.request.HomeEditRequestDTO.StickerRequest; import com.deare.backend.api.home.dto.response.HomeDashboardResponse; import com.deare.backend.api.home.dto.result.HomeSettingDto; import com.deare.backend.api.home.dto.result.HomeStickerDto; @@ -21,6 +22,8 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -70,38 +73,48 @@ public HomeDashboardResponse getHome(Long userId) { ); } @Transactional - public void editHome(Long userId, HomeEditRequest request){ - User user = userRepository.findById(userId).orElseThrow(()->new GeneralException(HomeErrorCode.USER_NOT_FOUND)); + public void editHome(Long userId, HomeEditRequestDTO request) { - UserSetting userSetting = userSettingRepository.findByUser_Id(userId).orElse(null); + User user = userRepository.findById(userId) + .orElseThrow(() -> new GeneralException(HomeErrorCode.USER_NOT_FOUND)); - if(userSetting!=null){ - userSetting.updateHomeColor(request.getHomeColor()); - }else{ - UserSetting newSetting = UserSetting.createDefault(user, request.getHomeColor()); - userSettingRepository.save(newSetting); + UserSetting userSetting = userSettingRepository.findByUser_Id(userId).orElse(null); + if (userSetting != null) { + userSetting.updateHomeColor(request.homeColor()); + } else { + userSettingRepository.save(UserSetting.createDefault(user, request.homeColor())); } + stickerRepository.deleteAllByUserId(userId); - List newStickers = request.getStickers().stream() - .map(dto -> { - Image image = imageRepository.findById(dto.getImageId()) - .orElseThrow(() -> new GeneralException(ImageErrorCode.IMAGE_40001)); + List stickerRequests = request.stickers(); + if (stickerRequests.isEmpty()) { + return; + } + + List imageIds = stickerRequests.stream() + .map(HomeEditRequestDTO.StickerRequest::imageId) + .distinct() + .toList(); + Map imageMap = imageRepository.findAllById(imageIds).stream() + .collect(Collectors.toMap(Image::getId, image -> image)); + + List newStickers = stickerRequests.stream() + .map(dto -> { + Image image = imageMap.get(dto.imageId()); + if (image == null) { + throw new GeneralException(ImageErrorCode.IMAGE_40001); + } return UserSticker.create( - user, - image, - dto.getPosX(), - dto.getPosY(), - dto.getPosZ(), - dto.getRotation(), - dto.getScale() + user, image, + dto.posX(), dto.posY(), dto.posZ(), + dto.rotation(), dto.scale() ); }) .toList(); stickerRepository.saveAll(newStickers); - } private HomeStickerDto toStickerDto(UserSticker sticker) { From 207467e838074b0152fbb5fd32d748e58d7a8440 Mon Sep 17 00:00:00 2001 From: kwonminsooo Date: Sat, 18 Jul 2026 21:43:19 +0900 Subject: [PATCH 4/4] =?UTF-8?q?term=20=EC=B6=A9=EB=8F=8C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/deare/backend/domain/term/entity/Term.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/deare/backend/domain/term/entity/Term.java b/src/main/java/com/deare/backend/domain/term/entity/Term.java index 9fe51855..da8d23a8 100644 --- a/src/main/java/com/deare/backend/domain/term/entity/Term.java +++ b/src/main/java/com/deare/backend/domain/term/entity/Term.java @@ -26,7 +26,7 @@ public class Term extends BaseEntity { private TermType type; @Lob - @Column(name = "content", columnDefinition = "MEDIUMTEXT", nullable = false, length = 16777215) + @Column(name = "content", columnDefinition = "LONGTEXT", nullable = false) private String content; @Column(name = "is_required", nullable = false) @@ -49,4 +49,4 @@ public Term(String title, TermType type, String content, boolean isRequired) { this.isRequired = isRequired; this.effectiveAt = LocalDateTime.now(); } -} +} \ No newline at end of file