diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostController.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostController.java index c47d52c2..bea6ec56 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostController.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostController.java @@ -4,6 +4,7 @@ import java.util.List; +import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; import org.sopt.pawkey.backendapi.domain.post.api.dto.request.PostCreateRequestDto; import org.sopt.pawkey.backendapi.domain.post.api.dto.response.PostRegisterResponseDto; import org.sopt.pawkey.backendapi.domain.post.api.dto.response.PostResponseDto; @@ -12,7 +13,6 @@ import org.sopt.pawkey.backendapi.domain.post.application.facade.command.PostRegisterFacade; import org.sopt.pawkey.backendapi.domain.post.application.facade.query.PostQueryFacade; import org.sopt.pawkey.backendapi.domain.review.api.dto.response.ReviewResponseDto; -import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; import org.sopt.pawkey.backendapi.global.response.ApiResponse; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostFilterController.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostFilterController.java index 01a0d4fb..6d3dc207 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostFilterController.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostFilterController.java @@ -2,12 +2,12 @@ import static org.sopt.pawkey.backendapi.global.constants.AppConstants.*; +import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; import org.sopt.pawkey.backendapi.domain.category.api.dto.response.CategorySelectListResponseDto; import org.sopt.pawkey.backendapi.domain.category.application.facade.query.CategorySelectFacade; import org.sopt.pawkey.backendapi.domain.post.api.dto.request.FilterPostsRequestDto; import org.sopt.pawkey.backendapi.domain.post.api.dto.response.PostListResponseDto; import org.sopt.pawkey.backendapi.domain.post.application.facade.query.PostQueryFacade; -import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; import org.sopt.pawkey.backendapi.global.response.ApiResponse; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostLikeController.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostLikeController.java index 2d063f7e..d5ab073d 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostLikeController.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/controller/PostLikeController.java @@ -2,8 +2,8 @@ import static org.sopt.pawkey.backendapi.global.constants.AppConstants.*; -import org.sopt.pawkey.backendapi.domain.post.application.facade.command.PostLikeFacade; import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; +import org.sopt.pawkey.backendapi.domain.post.application.facade.command.PostLikeFacade; import org.sopt.pawkey.backendapi.global.response.ApiResponse; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/application/service/PostService.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/application/service/PostService.java index 456d4528..2f3bbd6d 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/application/service/PostService.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/application/service/PostService.java @@ -56,7 +56,6 @@ public PostEntity savePost(UserEntity writer, post.getPostImageEntityList().add(postImage); } - pet.incrementWalkCount(); postRepository.save(post); return post; } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/domain/repository/PostLikeRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/domain/repository/PostLikeRepository.java index 95e874af..2156e937 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/domain/repository/PostLikeRepository.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/domain/repository/PostLikeRepository.java @@ -1,7 +1,6 @@ package org.sopt.pawkey.backendapi.domain.post.domain.repository; import java.util.List; -import java.util.Optional; import org.sopt.pawkey.backendapi.domain.post.infra.persistence.entity.PostLikeEntity; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/entity/PostImageEntity.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/entity/PostImageEntity.java index 0fc4044b..ebd3e7e3 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/entity/PostImageEntity.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/entity/PostImageEntity.java @@ -1,6 +1,5 @@ package org.sopt.pawkey.backendapi.domain.post.infra.persistence.entity; -import org.hibernate.annotations.BatchSize; import org.sopt.pawkey.backendapi.domain.image.domain.model.ImageType; import org.sopt.pawkey.backendapi.domain.image.infra.persistence.entity.ImageEntity; import org.sopt.pawkey.backendapi.global.infra.persistence.entity.BaseEntity; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostLikeRepositoryImpl.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostLikeRepositoryImpl.java index 70ee2444..dfec3dd2 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostLikeRepositoryImpl.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostLikeRepositoryImpl.java @@ -1,7 +1,6 @@ package org.sopt.pawkey.backendapi.domain.post.infra.persistence.repository; import java.util.List; -import java.util.Optional; import org.sopt.pawkey.backendapi.domain.post.domain.repository.PostLikeRepository; import org.sopt.pawkey.backendapi.domain.post.infra.persistence.entity.PostLikeEntity; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/SpringDataPostLikeRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/SpringDataPostLikeRepository.java index 9be6c6eb..1a4f8040 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/SpringDataPostLikeRepository.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/SpringDataPostLikeRepository.java @@ -1,7 +1,6 @@ package org.sopt.pawkey.backendapi.domain.post.infra.persistence.repository; import java.util.List; -import java.util.Optional; import org.sopt.pawkey.backendapi.domain.post.infra.persistence.entity.PostLikeEntity; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/auth/api/controller/AuthController.java b/src/main/java/org/sopt/pawkey/backendapi/domain/auth/api/controller/AuthController.java index 3c4653de..cf5f759a 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/auth/api/controller/AuthController.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/auth/api/controller/AuthController.java @@ -2,22 +2,20 @@ import static org.sopt.pawkey.backendapi.global.constants.AppConstants.*; -import org.sopt.pawkey.backendapi.domain.auth.api.dto.request.AppleLoginRequestDTO; -import org.sopt.pawkey.backendapi.domain.auth.application.service.login.verifier.test.KakaoAuthService; -import org.sopt.pawkey.backendapi.domain.user.application.facade.UserLoginFacade; import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; +import org.sopt.pawkey.backendapi.domain.auth.api.dto.request.AppleLoginRequestDTO; import org.sopt.pawkey.backendapi.domain.auth.api.dto.request.LoginRequestDTO; import org.sopt.pawkey.backendapi.domain.auth.api.dto.request.LogoutRequestDTO; import org.sopt.pawkey.backendapi.domain.auth.api.dto.request.RefreshTokenRequestDTO; import org.sopt.pawkey.backendapi.domain.auth.api.dto.request.WithdrawRequestDTO; import org.sopt.pawkey.backendapi.domain.auth.api.dto.response.SocialLoginResponseDTO; import org.sopt.pawkey.backendapi.domain.auth.api.dto.response.TokenResponseDTO; +import org.sopt.pawkey.backendapi.domain.auth.application.service.login.verifier.test.KakaoAuthService; import org.sopt.pawkey.backendapi.domain.auth.application.service.token.TokenService; - +import org.sopt.pawkey.backendapi.domain.user.application.facade.UserLoginFacade; import org.sopt.pawkey.backendapi.domain.user.application.facade.UserWithdrawFacade; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; - import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/auth/application/service/login/verifier/apple/AppleTokenVerifier.java b/src/main/java/org/sopt/pawkey/backendapi/domain/auth/application/service/login/verifier/apple/AppleTokenVerifier.java index fbcb32bb..eb36f8d6 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/auth/application/service/login/verifier/apple/AppleTokenVerifier.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/auth/application/service/login/verifier/apple/AppleTokenVerifier.java @@ -1,32 +1,34 @@ package org.sopt.pawkey.backendapi.domain.auth.application.service.login.verifier.apple; -import com.fasterxml.jackson.databind.ObjectMapper; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.ExpiredJwtException; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.MalformedJwtException; -import io.jsonwebtoken.SignatureException; // io.jsonwebtoken.SignatureException을 import합니다. -import io.jsonwebtoken.io.Decoders; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; +import java.security.PublicKey; +import java.util.HashMap; +import java.util.Map; +import org.sopt.pawkey.backendapi.domain.auth.exception.AuthBusinessException; +import org.sopt.pawkey.backendapi.domain.auth.exception.AuthErrorCode; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.*; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; -// 커스텀 예외 및 오류 코드 -import org.sopt.pawkey.backendapi.domain.auth.exception.AuthBusinessException; -import org.sopt.pawkey.backendapi.domain.auth.exception.AuthErrorCode; -// 의존성 서비스 (AppleAuthKeyService) +import com.fasterxml.jackson.databind.ObjectMapper; -import java.security.PublicKey; // 명확성을 위해 PublicKey를 명시적으로 import합니다. -import java.util.Map; -import java.util.HashMap; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.MalformedJwtException; +import io.jsonwebtoken.SignatureException; +import io.jsonwebtoken.io.Decoders; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; @Slf4j @Service @RequiredArgsConstructor diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/auth/application/service/withdraw/GoogleWithdrawService.java b/src/main/java/org/sopt/pawkey/backendapi/domain/auth/application/service/withdraw/GoogleWithdrawService.java index 12ac3587..f48f8a7c 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/auth/application/service/withdraw/GoogleWithdrawService.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/auth/application/service/withdraw/GoogleWithdrawService.java @@ -2,6 +2,7 @@ import org.sopt.pawkey.backendapi.domain.auth.exception.AuthBusinessException; import org.sopt.pawkey.backendapi.domain.auth.exception.AuthErrorCode; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -9,7 +10,7 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; -import org.springframework.beans.factory.annotation.Value; + import lombok.RequiredArgsConstructor; @Service("GOOGLE") diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/auth/infra/persistence/entity/AppleRefreshTokenEntity.java b/src/main/java/org/sopt/pawkey/backendapi/domain/auth/infra/persistence/entity/AppleRefreshTokenEntity.java index 52c9348c..3add0439 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/auth/infra/persistence/entity/AppleRefreshTokenEntity.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/auth/infra/persistence/entity/AppleRefreshTokenEntity.java @@ -4,12 +4,10 @@ import org.sopt.pawkey.backendapi.domain.auth.infra.persistence.converter.AppleRefreshTokenEncryptor; import org.springframework.data.annotation.CreatedDate; -import org.springframework.data.jpa.domain.support.AuditingEntityListener; import jakarta.persistence.Column; import jakarta.persistence.Convert; import jakarta.persistence.Entity; -import jakarta.persistence.EntityListeners; import jakarta.persistence.Id; import jakarta.persistence.Table; import lombok.AccessLevel; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/controller/PetController.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/controller/PetController.java index 46af8642..d2b27a57 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/controller/PetController.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/controller/PetController.java @@ -2,15 +2,7 @@ import static org.sopt.pawkey.backendapi.global.constants.AppConstants.*; -import java.util.List; - -import org.sopt.pawkey.backendapi.domain.pet.api.dto.response.PetTraitCategoryListResponseDto; -import org.sopt.pawkey.backendapi.domain.pet.application.dto.response.PetTraitCategoryResult; import org.sopt.pawkey.backendapi.domain.pet.application.service.PetQueryService; -import org.sopt.pawkey.backendapi.global.response.ApiResponse; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -18,16 +10,9 @@ @RestController @RequiredArgsConstructor -@RequestMapping(API_PREFIX + "/pets/traits") +@RequestMapping(API_PREFIX + "/pets") public class PetController { private final PetQueryService petQueryService; - @GetMapping("/categories") - public ResponseEntity> getPetTraitCategories() { - List resultList = petQueryService.getAllPetTraitCategories(); - PetTraitCategoryListResponseDto response = PetTraitCategoryListResponseDto.from(resultList); - - return ResponseEntity.status(HttpStatus.OK).body(ApiResponse.success(response)); - } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/request/PetRequestDto.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/request/PetRequestDto.java index 45aea85a..6c1db0b5 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/request/PetRequestDto.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/request/PetRequestDto.java @@ -1,25 +1,25 @@ package org.sopt.pawkey.backendapi.domain.pet.api.dto.request; -import java.util.List; +import java.time.LocalDate; -import org.sopt.pawkey.backendapi.domain.pet.application.dto.SelectedOptionForPetTraitCategory; import org.sopt.pawkey.backendapi.domain.pet.application.dto.request.CreatePetCommand; +import com.fasterxml.jackson.annotation.JsonFormat; + import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; -import jakarta.validation.constraints.Positive; public record PetRequestDto( @NotBlank(message = "반려동물 이름은 필수값입니다.") String name, - @NotBlank(message = "성별은 필수값입니다.") @Pattern(regexp = "^(M|F)$", message = "성별은 M 또는 F이어야 합니다.") String gender, - @Positive(message = "나이는 양수여야 합니다.") int age, - boolean isAgeKnown, + @NotBlank(message = "성별은 필수값입니다.") + @Pattern(regexp = "^(M|F)$", message = "성별은 M 또는 F이어야 합니다.") String gender, + @NotNull(message = "생년월일은 필수값입니다.") + @JsonFormat(pattern = "yyyy-MM-dd") LocalDate birth, boolean isNeutered, - @NotBlank(message = "품종은 필수값입니다.") String breed, - @NotNull(message = "반려동물 성향은 필수값입니다.") List petTraits + @NotBlank(message = "품종은 필수값입니다.") String breed ) { public CreatePetCommand toCommand() { - return CreatePetCommand.of(name, gender, age, isAgeKnown, isNeutered, breed, petTraits); + return CreatePetCommand.of(name, gender, birth, isNeutered, breed); } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/request/UpdatePetRequestDto.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/request/UpdatePetRequestDto.java new file mode 100644 index 00000000..a4b834cf --- /dev/null +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/request/UpdatePetRequestDto.java @@ -0,0 +1,28 @@ +package org.sopt.pawkey.backendapi.domain.pet.api.dto.request; + +import java.time.LocalDate; + +import org.sopt.pawkey.backendapi.domain.pet.application.dto.request.UpdatePetCommand; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PastOrPresent; +import jakarta.validation.constraints.Pattern; + +public record UpdatePetRequestDto( + @NotBlank String name, + + @PastOrPresent(message = "생년월일은 현재 또는 과거 날짜여야 합니다") + @NotNull LocalDate birth, + + @Pattern(regexp = "^(M|F)$", message = "성별은 M 또는 F이어야 합니다.") + @NotBlank String gender, + + @NotNull Boolean isNeutered, + + @NotBlank String breed +) { + public UpdatePetCommand toCommand() { + return new UpdatePetCommand(name, birth, gender, isNeutered, breed); + } +} \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/response/PetProfileResponseDto.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/response/PetProfileResponseDto.java index d6778898..11612e01 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/response/PetProfileResponseDto.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/response/PetProfileResponseDto.java @@ -1,22 +1,53 @@ package org.sopt.pawkey.backendapi.domain.pet.api.dto.response; -import java.util.List; +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; + +import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetEntity; public record PetProfileResponseDto( Long petId, + String imageUrl, String name, + LocalDate birth, + long age, String gender, boolean isNeutered, - int age, - boolean isAgeKnown, String breed, - String imageUrl, - List traits, - int walkCount + + // 추후 dbti 엔티티 생성 시에, dbti 소개 문구로 변경할 예정 + String dbti ) { - public record TraitDto( - String category, - String option - ) { + public static PetProfileResponseDto from(PetEntity pet) { + return new PetProfileResponseDto( + pet.getPetId(), + pet.getProfileImage() != null ? pet.getProfileImage().getImageUrl() : null, + pet.getName(), + pet.getBirth(), + calculateAgeInMonths(pet.getBirth()), + convertGender(pet.getGender()), + pet.isNeutered(), + pet.getBreed(), + parseDbti(pet.getDbti()) + ); + } + + private static long calculateAgeInMonths(LocalDate birth) { + if (birth == null) + return 0; + return ChronoUnit.MONTHS.between(birth, LocalDate.now()); + } + + private static String convertGender(String gender) { + if ("M".equals(gender)) { + return "남아"; + } else if ("F".equals(gender)) { + return "여아"; + } + throw new IllegalArgumentException("올바르지 않은 성별 값입니다: " + gender); + } + + private static String parseDbti(String dbti) { + return (dbti == null || dbti.isBlank()) ? "DBTI 검사 미완료" : dbti; } } \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/response/PetTraitCategoryListResponseDto.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/response/PetTraitCategoryListResponseDto.java deleted file mode 100644 index 96681e82..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/response/PetTraitCategoryListResponseDto.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.api.dto.response; - -import java.util.List; - -import org.sopt.pawkey.backendapi.domain.pet.application.dto.response.PetTraitCategoryResult; - -public record PetTraitCategoryListResponseDto( - List petTraitCategoryList -) { - public static PetTraitCategoryListResponseDto from(List results) { - return new PetTraitCategoryListResponseDto( - results.stream() - .map(PetTraitCategoryResponseDto::from) - .toList() - ); - } -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/response/PetTraitCategoryResponseDto.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/response/PetTraitCategoryResponseDto.java deleted file mode 100644 index 56d8d84f..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/api/dto/response/PetTraitCategoryResponseDto.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.api.dto.response; - -import java.util.List; - -import org.sopt.pawkey.backendapi.domain.pet.application.dto.response.PetTraitCategoryResult; - -public record PetTraitCategoryResponseDto( - Long petTraitCategoryId, - String petTraitCategoryName, - List petTraitCategoryOptions -) { - public static PetTraitCategoryResponseDto from(PetTraitCategoryResult result) { - return new PetTraitCategoryResponseDto( - result.id(), - result.name(), - result.options().stream() - .map(PetTraitCategoryOptionResponseDto::from) - .toList() - ); - } - - public record PetTraitCategoryOptionResponseDto( - Long petTraitCategoryOptionId, - String petTraitCategoryOptionText - ) { - public static PetTraitCategoryOptionResponseDto from(PetTraitCategoryResult.PetTraitOptionResult result) { - return new PetTraitCategoryOptionResponseDto( - result.id(), - result.text() - ); - } - } -} \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/SelectedOptionForPetTraitCategory.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/SelectedOptionForPetTraitCategory.java deleted file mode 100644 index a49c7ab0..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/SelectedOptionForPetTraitCategory.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.application.dto; - -public record SelectedOptionForPetTraitCategory( - Long traitCategoryId, - Long traitOptionId -) { -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/request/CreatePetCommand.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/request/CreatePetCommand.java index 59bea9f1..b06772f9 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/request/CreatePetCommand.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/request/CreatePetCommand.java @@ -1,18 +1,21 @@ package org.sopt.pawkey.backendapi.domain.pet.application.dto.request; -import java.util.List; +import java.time.LocalDate; -import org.sopt.pawkey.backendapi.domain.pet.application.dto.SelectedOptionForPetTraitCategory; - -public record CreatePetCommand(String name, - String gender, - int age, - boolean isAgeKnown, - boolean isNeutered, - String breed, - List petTraits) { - public static CreatePetCommand of(String name, String gender, int age, boolean isAgeKnown, boolean isNeutered, - String breed, List petTraits) { - return new CreatePetCommand(name, gender, age, isAgeKnown, isNeutered, breed, petTraits); +public record CreatePetCommand( + String name, + String gender, + LocalDate birth, + boolean isNeutered, + String breed +) { + public static CreatePetCommand of( + String name, + String gender, + LocalDate birth, + boolean isNeutered, + String breed + ) { + return new CreatePetCommand(name, gender, birth, isNeutered, breed); } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/request/UpdatePetCommand.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/request/UpdatePetCommand.java new file mode 100644 index 00000000..2e686f1e --- /dev/null +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/request/UpdatePetCommand.java @@ -0,0 +1,12 @@ +package org.sopt.pawkey.backendapi.domain.pet.application.dto.request; + +import java.time.LocalDate; + +public record UpdatePetCommand( + String name, + LocalDate birth, + String gender, + boolean isNeutered, + String breed +) { +} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/response/PetTraitCategoryResult.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/response/PetTraitCategoryResult.java deleted file mode 100644 index 73978bfd..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/dto/response/PetTraitCategoryResult.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.application.dto.response; - -import java.util.List; - -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitCategoryEntity; -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitOptionEntity; - -public record PetTraitCategoryResult( - Long id, - String name, - List options -) { - - //상위 - 강아지 특성 카테고리(상세 옵션 포함) - public static PetTraitCategoryResult fromEntity(PetTraitCategoryEntity petTraitCategory) { - return new PetTraitCategoryResult( - petTraitCategory.getId(), - petTraitCategory.getCategoryName(), - petTraitCategory.getPetTraitOptionEntityList().stream() - .map(PetTraitOptionResult::fromEntity) - .toList() - ); - } - - //하위 - 강아지 카테고리 별 상세 옵션 - public record PetTraitOptionResult( - Long id, - String text - ) { - public static PetTraitOptionResult fromEntity(PetTraitOptionEntity entity) { - return new PetTraitOptionResult(entity.getId(), entity.getOptionText()); - } - } -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/service/PetQueryService.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/service/PetQueryService.java index 7fd89c77..c1fb4d42 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/service/PetQueryService.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/service/PetQueryService.java @@ -2,9 +2,12 @@ import java.util.List; -import org.sopt.pawkey.backendapi.domain.pet.application.dto.response.PetTraitCategoryResult; +import org.sopt.pawkey.backendapi.domain.pet.api.dto.response.PetProfileResponseDto; import org.sopt.pawkey.backendapi.domain.pet.domain.repository.PetRepository; -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitCategoryEntity; +import org.sopt.pawkey.backendapi.domain.pet.exception.PetBusinessException; +import org.sopt.pawkey.backendapi.domain.pet.exception.PetErrorCode; +import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetEntity; +import org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity.UserEntity; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; @@ -15,11 +18,19 @@ public class PetQueryService { private final PetRepository petRepository; - public List getAllPetTraitCategories() { - List petTraitCategoryEntityList = petRepository.findAllPetTraitCategoriesWithOptions(); + public List getPetProfiles(UserEntity user) { + List petEntityList = petRepository.findAllPetsByUserId(user.getUserId()); - return petTraitCategoryEntityList.stream() - .map(PetTraitCategoryResult::fromEntity) // static fromDomain() 메서드 있다고 가정 + return petEntityList.stream() + .map(PetProfileResponseDto::from) .toList(); } + + public PetProfileResponseDto getPetProfile(Long petId) { + PetEntity pet = petRepository.findById(petId) + .orElseThrow(() -> new PetBusinessException(PetErrorCode.PET_NOT_FOUND)); + + return PetProfileResponseDto.from(pet); + } + } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/service/PetService.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/service/PetService.java index 20121144..8c0a6383 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/service/PetService.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/application/service/PetService.java @@ -1,19 +1,16 @@ package org.sopt.pawkey.backendapi.domain.pet.application.service; -import java.util.List; - -import org.sopt.pawkey.backendapi.domain.image.infra.persistence.entity.ImageEntity; import org.sopt.pawkey.backendapi.domain.pet.application.dto.request.CreatePetCommand; +import org.sopt.pawkey.backendapi.domain.pet.application.dto.request.UpdatePetCommand; import org.sopt.pawkey.backendapi.domain.pet.domain.repository.PetRepository; -import org.sopt.pawkey.backendapi.domain.pet.domain.repository.PetTraitOptionRepository; -import org.sopt.pawkey.backendapi.domain.pet.domain.repository.PetTraitSelectedRepository; import org.sopt.pawkey.backendapi.domain.pet.exception.PetBusinessException; import org.sopt.pawkey.backendapi.domain.pet.exception.PetErrorCode; import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetEntity; -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitOptionEntity; -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitSelectedEntity; +import org.sopt.pawkey.backendapi.domain.user.exception.UserBusinessException; +import org.sopt.pawkey.backendapi.domain.user.exception.UserErrorCode; import org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity.UserEntity; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; @@ -22,39 +19,35 @@ public class PetService { private final PetRepository petRepository; - private final PetTraitOptionRepository petTraitOptionRepository; - private final PetTraitSelectedRepository petTraitSelectedRepository; - public PetEntity savePet(CreatePetCommand command, UserEntity user, ImageEntity profileImage) { + public PetEntity savePet(CreatePetCommand command, UserEntity user) { PetEntity pet = PetEntity.builder() .name(command.name()) .gender(command.gender()) - .age(command.age()) - .isAgeKnown(command.isAgeKnown()) + .birth(command.birth()) .isNeutered(command.isNeutered()) .breed(command.breed()) - .profileImage(profileImage) .user(user) .build(); - PetEntity savedPet = petRepository.save(pet); - - //성향 저장 - - List selectedTraits = command.petTraits().stream() - .map(dto -> { - PetTraitOptionEntity option = petTraitOptionRepository.findById(dto.traitOptionId()) - .orElseThrow(() -> new PetBusinessException(PetErrorCode.CATEGORY_OPTION_NOT_FOUND)); - - return PetTraitSelectedEntity.builder() - .pet(savedPet) - .petTraitOption(option) - .build(); - }) - .toList(); - - selectedTraits.forEach(petTraitSelectedRepository::save); + return petRepository.save(pet); + } - return savedPet; + @Transactional + public void updatePetInfo(Long userId, Long petId, UpdatePetCommand command) { + PetEntity pet = petRepository.findById(petId) + .orElseThrow(() -> new PetBusinessException(PetErrorCode.PET_NOT_FOUND)); + + if (!pet.getUser().getUserId().equals(userId)) { + throw new UserBusinessException(UserErrorCode.UNAUTHORIZED_ACCESS); + } + + pet.updateProfile( + command.name(), + command.birth(), + command.gender(), + command.isNeutered(), + command.breed() + ); } -} +} \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/domain/repository/PetRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/domain/repository/PetRepository.java index 0c549c6f..fa7131aa 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/domain/repository/PetRepository.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/domain/repository/PetRepository.java @@ -1,18 +1,15 @@ package org.sopt.pawkey.backendapi.domain.pet.domain.repository; import java.util.List; +import java.util.Optional; import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetEntity; -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitCategoryEntity; public interface PetRepository { - List findAllPetTraitCategoriesWithOptions(); PetEntity save(PetEntity pet); List findAllPetsByUserId(Long userId); -} - - - + Optional findById(Long petId); +} \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/domain/repository/PetTraitOptionRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/domain/repository/PetTraitOptionRepository.java deleted file mode 100644 index 5e270271..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/domain/repository/PetTraitOptionRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.domain.repository; - -import java.util.Optional; - -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitOptionEntity; - -public interface PetTraitOptionRepository { - Optional findById(Long optionId); -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/domain/repository/PetTraitSelectedRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/domain/repository/PetTraitSelectedRepository.java deleted file mode 100644 index d3fb7a49..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/domain/repository/PetTraitSelectedRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.domain.repository; - -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitSelectedEntity; - -public interface PetTraitSelectedRepository { - void save(PetTraitSelectedEntity entity); -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/exception/PetErrorCode.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/exception/PetErrorCode.java index 40998098..ab2a8156 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/exception/PetErrorCode.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/exception/PetErrorCode.java @@ -5,7 +5,7 @@ public enum PetErrorCode implements ErrorCode { - CATEGORY_OPTION_NOT_FOUND("P40401", "존재하지 않는 성향 옵션입니다.", HttpStatus.NOT_FOUND); + PET_NOT_FOUND("P40401", "반려견이 존재하지 않습니다.", HttpStatus.NOT_FOUND); private final String code; private final String message; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetEntity.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetEntity.java index 2a7a5da0..a077a164 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetEntity.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetEntity.java @@ -1,13 +1,11 @@ package org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity; -import java.util.ArrayList; -import java.util.List; +import java.time.LocalDate; import org.sopt.pawkey.backendapi.domain.image.infra.persistence.entity.ImageEntity; import org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity.UserEntity; import org.sopt.pawkey.backendapi.global.infra.persistence.entity.BaseEntity; -import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -16,9 +14,9 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; +import jakarta.validation.constraints.PastOrPresent; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -41,11 +39,9 @@ public class PetEntity extends BaseEntity { @Column(name = "gender", nullable = false, length = 10) private String gender; - @Column(name = "age") - private int age; - - @Column(name = "is_age_known", nullable = false) - private boolean isAgeKnown; + @Column(name = "birth", nullable = false) + @PastOrPresent(message = "생년월일은 현재 또는 과거 날짜여야 합니다") + private LocalDate birth; //Image 연관관계 추가 @OneToOne @@ -61,39 +57,35 @@ public class PetEntity extends BaseEntity { @Column(name = "breed", length = 50) private String breed; - @Column(name = "walk_count", nullable = false) - private int walkCount; - - @OneToMany(mappedBy = "pet", cascade = CascadeType.ALL, orphanRemoval = true) - private List petTraitSelectedEntityList = new ArrayList<>(); + @Column(name = "dbti") + private String dbti; @Builder public PetEntity(Long petId, String name, String gender, - int age, - boolean isAgeKnown, + LocalDate birth, ImageEntity profileImage, UserEntity user, boolean isNeutered, String breed, - int walkCount, - List petTraitSelectedEntityList) { + String dbti) { this.petId = petId; this.name = name; this.gender = gender; - this.age = age; - this.isAgeKnown = isAgeKnown; + this.birth = birth; this.profileImage = profileImage; this.user = user; this.isNeutered = isNeutered; this.breed = breed; - this.walkCount = walkCount; - this.petTraitSelectedEntityList = - petTraitSelectedEntityList != null ? petTraitSelectedEntityList : new ArrayList<>(); + this.dbti = dbti; } - public void incrementWalkCount() { - this.walkCount++; + public void updateProfile(String name, LocalDate birth, String gender, boolean isNeutered, String breed) { + this.name = name; + this.birth = birth; + this.gender = gender; + this.isNeutered = isNeutered; + this.breed = breed; } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetTraitCategoryEntity.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetTraitCategoryEntity.java deleted file mode 100644 index ec85363c..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetTraitCategoryEntity.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity; - -import java.util.ArrayList; -import java.util.List; - -import org.sopt.pawkey.backendapi.global.infra.persistence.entity.BaseEntity; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Table(name = "pet_trait_category") -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PROTECTED) -public class PetTraitCategoryEntity extends BaseEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "pet_trait_category_id") - private Long id; - - @Column(name = "name", nullable = false, length = 50) - private String categoryName; - - @OneToMany(mappedBy = "petTraitCategory", cascade = CascadeType.ALL, orphanRemoval = true) - private List petTraitOptionEntityList = new ArrayList<>(); - - @Builder - public PetTraitCategoryEntity(Long id, String categoryName) { - this.id = id; - this.categoryName = categoryName; - this.petTraitOptionEntityList = new ArrayList<>(); - } -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetTraitOptionEntity.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetTraitOptionEntity.java deleted file mode 100644 index 83fb24e6..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetTraitOptionEntity.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity; - -import java.util.ArrayList; -import java.util.List; - -import org.sopt.pawkey.backendapi.global.infra.persistence.entity.BaseEntity; - -import jakarta.persistence.CascadeType; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; -import jakarta.persistence.Table; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Table(name = "pet_trait_option") -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PROTECTED) -public class PetTraitOptionEntity extends BaseEntity { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "pet_trait_option_id") - private Long id; - - //PetTraitCategory 연관관계 - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "pet_trait_category_id") - private PetTraitCategoryEntity petTraitCategory; - - @Column(name = "option_text", nullable = false, length = 50) - private String optionText; - - @OneToMany(mappedBy = "petTraitOption", cascade = CascadeType.ALL, orphanRemoval = true) - private List petTraitSelectedEntityList = new ArrayList<>(); - - @Builder - public PetTraitOptionEntity(Long id, - PetTraitCategoryEntity petTraitCategory, - String optionText) { - this.id = id; - this.petTraitCategory = petTraitCategory; - this.optionText = optionText; - this.petTraitSelectedEntityList = new ArrayList<>(); - } -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetTraitSelectedEntity.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetTraitSelectedEntity.java deleted file mode 100644 index 8fcbbda0..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/entity/PetTraitSelectedEntity.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity; - -import org.sopt.pawkey.backendapi.global.infra.persistence.entity.BaseEntity; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Entity -@Table(name = "pet_trait_selected") -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public class PetTraitSelectedEntity extends BaseEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "pet_trait_selected_id") - private Long id; - - //Pet 연관관계 - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "pet_id") - private PetEntity pet; - - //PetTraitOption 연관관계 - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "pet_trait_option_id") - private PetTraitOptionEntity petTraitOption; - - @Builder - public PetTraitSelectedEntity(Long id, - PetEntity pet, - PetTraitOptionEntity petTraitOption) { - this.id = id; - this.pet = pet; - this.petTraitOption = petTraitOption; - } -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/PetRepositoryImpl.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/PetRepositoryImpl.java index e31565b6..f54a8457 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/PetRepositoryImpl.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/PetRepositoryImpl.java @@ -1,10 +1,10 @@ package org.sopt.pawkey.backendapi.domain.pet.infra.persistence.repository; import java.util.List; +import java.util.Optional; import org.sopt.pawkey.backendapi.domain.pet.domain.repository.PetRepository; import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetEntity; -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitCategoryEntity; import org.springframework.stereotype.Repository; import lombok.RequiredArgsConstructor; @@ -13,19 +13,11 @@ @RequiredArgsConstructor public class PetRepositoryImpl implements PetRepository { - private final SpringDataPetTraitCategoryRepository springDataPetTraitCategoryRepository; private final SpringDataPetRepository springDataPetRepository; private final SpringDataPetRepository petRepository; - @Override - public List findAllPetTraitCategoriesWithOptions() { - - return springDataPetTraitCategoryRepository.findAllWithOptions(); - - } - @Override public PetEntity save(PetEntity pet) { return springDataPetRepository.save(pet); @@ -35,4 +27,9 @@ public List findAllPetsByUserId(Long userId) { return petRepository.findAllByUser_UserId(userId); } + @Override + public Optional findById(Long petId) { + return springDataPetRepository.findById(petId); + } + } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/PetTraitOptionRepositoryImpl.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/PetTraitOptionRepositoryImpl.java deleted file mode 100644 index 3b898899..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/PetTraitOptionRepositoryImpl.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.infra.persistence.repository; - -import java.util.Optional; - -import org.sopt.pawkey.backendapi.domain.pet.domain.repository.PetTraitOptionRepository; -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitOptionEntity; -import org.springframework.stereotype.Repository; - -import lombok.RequiredArgsConstructor; - -@Repository -@RequiredArgsConstructor -public class PetTraitOptionRepositoryImpl implements PetTraitOptionRepository { - - private final SpringDataPetTraitOptionRepository jpaRepository; - - @Override - public Optional findById(Long optionId) { - return jpaRepository.findById(optionId); - } -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/PetTraitSelectedRepositoryImpl.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/PetTraitSelectedRepositoryImpl.java deleted file mode 100644 index 25de3df0..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/PetTraitSelectedRepositoryImpl.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.infra.persistence.repository; - -import org.sopt.pawkey.backendapi.domain.pet.domain.repository.PetTraitSelectedRepository; -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitSelectedEntity; -import org.springframework.stereotype.Repository; - -import lombok.RequiredArgsConstructor; - -@Repository -@RequiredArgsConstructor -public class PetTraitSelectedRepositoryImpl implements PetTraitSelectedRepository { - - private final SpringDataPetTraitSelectedRepository jpaRepository; - - @Override - public void save(PetTraitSelectedEntity entity) { - jpaRepository.save(entity); - } -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetRepository.java index fd74439c..1a5b942c 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetRepository.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetRepository.java @@ -9,8 +9,7 @@ public interface SpringDataPetRepository extends JpaRepository { @EntityGraph(attributePaths = { - "profileImage", - "petTraitSelectedEntityList.petTraitOption.petTraitCategory" + "profileImage" }) List findAllByUser_UserId(Long userId); } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetTraitCategoryRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetTraitCategoryRepository.java deleted file mode 100644 index f38efe0b..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetTraitCategoryRepository.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.infra.persistence.repository; - -import java.util.List; - -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitCategoryEntity; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; - -public interface SpringDataPetTraitCategoryRepository extends JpaRepository { - @Query("SELECT DISTINCT c FROM PetTraitCategoryEntity c " + - "JOIN FETCH c.petTraitOptionEntityList") - List findAllWithOptions(); -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetTraitOptionRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetTraitOptionRepository.java deleted file mode 100644 index 84769a51..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetTraitOptionRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.infra.persistence.repository; - -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitOptionEntity; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface SpringDataPetTraitOptionRepository extends JpaRepository { -} diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetTraitSelectedRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetTraitSelectedRepository.java deleted file mode 100644 index 84d8c9ab..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/pet/infra/persistence/repository/SpringDataPetTraitSelectedRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.pet.infra.persistence.repository; - -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitSelectedEntity; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface SpringDataPetTraitSelectedRepository extends JpaRepository { -} - - - diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/region/api/controller/RegionController.java b/src/main/java/org/sopt/pawkey/backendapi/domain/region/api/controller/RegionController.java index bca07b9f..e811875a 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/region/api/controller/RegionController.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/region/api/controller/RegionController.java @@ -2,6 +2,7 @@ import static org.sopt.pawkey.backendapi.global.constants.AppConstants.*; +import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; import org.sopt.pawkey.backendapi.domain.region.api.dto.GetRegionCoordinatesResponseDto; import org.sopt.pawkey.backendapi.domain.region.api.dto.GetRegionListResponseDto; import org.sopt.pawkey.backendapi.domain.region.api.dto.GetRegionResponseDto; @@ -13,7 +14,6 @@ import org.sopt.pawkey.backendapi.domain.region.application.facade.query.GetRegionCoordinatesFacade; import org.sopt.pawkey.backendapi.domain.region.application.facade.query.GetRegionFacade; import org.sopt.pawkey.backendapi.domain.region.application.facade.query.GetRegionListFacade; -import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; import org.sopt.pawkey.backendapi.global.exception.BusinessException; import org.sopt.pawkey.backendapi.global.response.ApiResponse; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/review/api/controller/ReviewController.java b/src/main/java/org/sopt/pawkey/backendapi/domain/review/api/controller/ReviewController.java index c036eb34..6adf2cc3 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/review/api/controller/ReviewController.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/review/api/controller/ReviewController.java @@ -2,10 +2,10 @@ import static org.sopt.pawkey.backendapi.global.constants.AppConstants.*; +import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; import org.sopt.pawkey.backendapi.domain.review.api.dto.request.ReviewCreateRequestDto; import org.sopt.pawkey.backendapi.domain.review.application.dto.command.ReviewRegisterCommand; import org.sopt.pawkey.backendapi.domain.review.application.facade.ReviewRegisterFacade; -import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; import org.sopt.pawkey.backendapi.global.response.ApiResponse; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/routes/api/controller/RouteController.java b/src/main/java/org/sopt/pawkey/backendapi/domain/routes/api/controller/RouteController.java index f03426e1..d09d6625 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/routes/api/controller/RouteController.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/routes/api/controller/RouteController.java @@ -2,6 +2,7 @@ import static org.sopt.pawkey.backendapi.global.constants.AppConstants.*; +import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; import org.sopt.pawkey.backendapi.domain.routes.api.dto.GetRouteInfoForPostResponse; import org.sopt.pawkey.backendapi.domain.routes.api.dto.GetSharedRouteMapDataResponseDto; import org.sopt.pawkey.backendapi.domain.routes.api.dto.RouteRegisterRequest; @@ -14,7 +15,6 @@ import org.sopt.pawkey.backendapi.domain.routes.application.facade.command.RouteRegisterFacade; import org.sopt.pawkey.backendapi.domain.routes.application.facade.query.GetRouteInfoForPostFacade; import org.sopt.pawkey.backendapi.domain.routes.application.facade.query.GetSharedRouteMapDataFacade; -import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; import org.sopt.pawkey.backendapi.global.response.ApiResponse; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/controller/UserController.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/controller/UserController.java index e7cacca6..8f425a73 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/controller/UserController.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/controller/UserController.java @@ -4,35 +4,37 @@ import java.util.List; +import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; +import org.sopt.pawkey.backendapi.domain.pet.api.dto.request.UpdatePetRequestDto; import org.sopt.pawkey.backendapi.domain.pet.api.dto.response.PetProfileResponseDto; import org.sopt.pawkey.backendapi.domain.post.api.dto.response.PostCardResponseDto; import org.sopt.pawkey.backendapi.domain.user.api.dto.request.CreateUserRequestDto; +import org.sopt.pawkey.backendapi.domain.user.api.dto.request.UpdateUserInfoRequestDto; import org.sopt.pawkey.backendapi.domain.user.api.dto.request.UpdateUserRegionRequestDto; import org.sopt.pawkey.backendapi.domain.user.api.dto.response.ListResponseWrapper; import org.sopt.pawkey.backendapi.domain.user.api.dto.response.UserInfoResponseDto; import org.sopt.pawkey.backendapi.domain.user.api.dto.response.UserRegisterResponseDto; import org.sopt.pawkey.backendapi.domain.user.application.dto.request.UserRegisterCommand; +import org.sopt.pawkey.backendapi.domain.user.application.facade.UpdateUserInfoFacade; import org.sopt.pawkey.backendapi.domain.user.application.facade.UserRegisterFacade; import org.sopt.pawkey.backendapi.domain.user.application.facade.command.UpdateUserRegionFacade; +import org.sopt.pawkey.backendapi.domain.user.application.facade.command.UserPetCommandFacade; import org.sopt.pawkey.backendapi.domain.user.application.facade.query.UserLikedPostQueryFacade; import org.sopt.pawkey.backendapi.domain.user.application.facade.query.UserPetQueryFacade; import org.sopt.pawkey.backendapi.domain.user.application.facade.query.UserQueryFacade; import org.sopt.pawkey.backendapi.domain.user.application.facade.query.UserWrittenPostQueryFacade; -import org.sopt.pawkey.backendapi.domain.auth.annotation.UserId; import org.sopt.pawkey.backendapi.global.response.ApiResponse; -import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.validation.Valid; @@ -44,7 +46,9 @@ public class UserController { private final UserPetQueryFacade userPetQueryFacade; + private final UserPetCommandFacade userPetCommandFacade; private final UpdateUserRegionFacade updateUserRegionFacade; + private final UpdateUserInfoFacade updateUserInfoFacade; private final UserLikedPostQueryFacade userLikedPostQueryFacade; private final UserWrittenPostQueryFacade userWrittenPostQueryFacade; private final UserRegisterFacade userRegisterFacade; @@ -58,47 +62,63 @@ public class UserController { @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "유효하지 않은 강아지 성향 카테고리 선택입니다.", content = @Content(mediaType = "application/json")), @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "강아지 프로필 이미지 파일 형식 또는 용량 오류", content = @Content(mediaType = "application/json")), @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "500", description = "서버 내부 오류", content = @Content(mediaType = "application/json"))}) - - @PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}) + @PostMapping public ResponseEntity> createUser( - @RequestPart("data") @Validated CreateUserRequestDto requestDto, - @RequestPart("pet_profile") MultipartFile image) { + @Parameter(hidden = true) @UserId Long userId, + @RequestBody @Valid CreateUserRequestDto requestDto) { UserRegisterCommand command = requestDto.toCommand(); - UserRegisterResponseDto response = userRegisterFacade.execute(command, image); + UserRegisterResponseDto response = userRegisterFacade.execute(userId, command); return ResponseEntity.ok(ApiResponse.success(response)); - } - @Operation(summary = "내가 좋아요한 게시물 조회", description = "사용자가 좋아요를 누른 게시물 목록을 반환합니다.", tags = {"Users"}) + @Operation(summary = "유저 정보 조회", description = "마이페이지에서 유저 상세 정보를 조회합니다.", tags = {"Users"}) @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"), @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "사용자 없음"), @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "500", description = "서버 오류") }) - @GetMapping("/me/likes") - public ResponseEntity>> getMyLikedPosts( - @UserId Long userId + @GetMapping("/me/userInfo") + public ResponseEntity> getUserProfile( + @Parameter(hidden = true) @UserId Long userId ) { - List likedPosts = userLikedPostQueryFacade.getLikedPosts(userId); - return ResponseEntity.ok(ApiResponse.success(ListResponseWrapper.from(likedPosts))); + UserInfoResponseDto response = userQueryFacade.getUserInfo(userId); + return ResponseEntity.ok(ApiResponse.success(response)); } - @Operation(summary = "마이페이지 유저 정보 조회", description = "마이페이지에서 유저 상세 정보를 조회합니다.", tags = {"Users"}) + @PatchMapping("/me/userInfo") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "수정 성공"), @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "사용자 없음"), @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "500", description = "서버 오류") }) - @GetMapping("/me/userInfo") - public ResponseEntity> getUserProfile( - @UserId Long userId + @Operation(summary = "유저 정보 수정", description = "이름, 성별, 생년월일을 수정합니다.", tags = {"Users"}) + public ResponseEntity> updateUserInfo( + @Parameter(hidden = true) @UserId Long userId, + @Valid @RequestBody UpdateUserInfoRequestDto requestDto ) { - UserInfoResponseDto response = userQueryFacade.getUserInfo(userId); + UserInfoResponseDto response = updateUserInfoFacade.execute(userId, requestDto.toCommand()); return ResponseEntity.ok(ApiResponse.success(response)); } + @PatchMapping("/me/regions") + @Operation(summary = "유저 소속 지역 수정 성공", description = "유저가 소속된 지역(region)을 수정합니다.", tags = {"Users"}) + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "유저 소속 지역 수정 성공"), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "유효하지 않은 요청 (R40001: 지역구분이 동이 아닌 경우)"), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "리소스 찾을 수 없음(U40401, R40401)") + }) + public ResponseEntity> updateRegion( + @UserId Long userId, + @Valid @RequestBody UpdateUserRegionRequestDto updateUserRegionRequestDto + ) { + updateUserRegionFacade.execute(userId, updateUserRegionRequestDto.toCommand()); + + return ResponseEntity.ok( + ApiResponse.success()); + } + @Operation(summary = "내가 작성한 게시물 조회", description = "사용자가 작성한 게시물 목록을 반환합니다.", tags = {"Users"}) @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"), @@ -113,6 +133,20 @@ public ResponseEntity>> get return ResponseEntity.ok(ApiResponse.success(ListResponseWrapper.from(myPosts))); } + @Operation(summary = "내가 좋아요한 게시물 조회", description = "사용자가 좋아요를 누른 게시물 목록을 반환합니다.", tags = {"Users"}) + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "사용자 없음"), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "500", description = "서버 오류") + }) + @GetMapping("/me/likes") + public ResponseEntity>> getMyLikedPosts( + @UserId Long userId + ) { + List likedPosts = userLikedPostQueryFacade.getLikedPosts(userId); + return ResponseEntity.ok(ApiResponse.success(ListResponseWrapper.from(likedPosts))); + } + @Operation(summary = "유저 반려견 프로필 조회", description = "유저가 등록한 반려견 목록을 조회합니다.", tags = {"Users"}) @ApiResponses({ @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"), @@ -121,27 +155,26 @@ public ResponseEntity>> get }) @GetMapping("/me/pets") public ResponseEntity>> getMyPets( - @UserId Long userId + @Parameter(hidden = true) @UserId Long userId ) { List petDtos = userPetQueryFacade.getUserPets(userId); return ResponseEntity.ok(ApiResponse.success(petDtos)); } - @PatchMapping("/me/regions") - @Operation(summary = "유저 소속 지역 수정 성공", description = "유저가 소속된 지역(region)을 수정합니다.", tags = {"Users"}) + @PatchMapping("/me/pets/{petId}") + @Operation(summary = "반려견 정보 수정", description = "특정 반려견의 프로필 정보를 수정합니다.", tags = {"Users"}) @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "유저 소속 지역 수정 성공"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "유효하지 않은 요청 (R40001: 지역구분이 동이 아닌 경우)"), - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "리소스 찾을 수 없음(U40401, R40401)") + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "수정 성공"), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "해당 반려견에 대한 수정 권한이 없음"), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "반려견 정보를 찾을 수 없음") }) - public ResponseEntity> updateRegion( - @UserId Long userId, - @Valid @RequestBody UpdateUserRegionRequestDto updateUserRegionRequestDto + public ResponseEntity> updatePetInfo( + @Parameter(hidden = true) @UserId Long userId, + @PathVariable Long petId, + @Valid @RequestBody UpdatePetRequestDto requestDto ) { - updateUserRegionFacade.execute(userId, updateUserRegionRequestDto.toCommand()); - - return ResponseEntity.ok( - ApiResponse.success()); + PetProfileResponseDto response = userPetCommandFacade.updatePetInfo(userId, petId, requestDto.toCommand()); + return ResponseEntity.ok(ApiResponse.success(response)); } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/request/CreateUserRequestDto.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/request/CreateUserRequestDto.java index 5fe51398..c8c380b5 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/request/CreateUserRequestDto.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/request/CreateUserRequestDto.java @@ -1,29 +1,34 @@ package org.sopt.pawkey.backendapi.domain.user.api.dto.request; +import java.time.LocalDate; + import org.sopt.pawkey.backendapi.domain.pet.api.dto.request.PetRequestDto; import org.sopt.pawkey.backendapi.domain.user.application.dto.request.CreateUserCommand; import org.sopt.pawkey.backendapi.domain.user.application.dto.request.UserRegisterCommand; +import com.fasterxml.jackson.annotation.JsonFormat; + +import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; -import jakarta.validation.constraints.Size; public record CreateUserRequestDto( - - @NotNull(message = "로그인 아이디는 필수값입니다.") String loginId, - @Size(min = 1, max = 50, message = "비밀번호는 1자 이상 50자 이하여야 합니다.") String password, @NotNull(message = "이름은 필수값입니다.") String name, + + @NotNull(message = "생년월일은 필수값입니다.") + @JsonFormat(pattern = "yyyy-MM-dd") LocalDate birth, + @NotNull(message = "성별은 필수값입니다.") - @Pattern(regexp = "^(M|F)$", message = "성별은 MALE 또는 FEMALE이어야 합니다.") String gender, - @NotNull(message = "나이는 필수값입니다.") int age, + @Pattern(regexp = "^(M|F)$", message = "성별은 M 또는 F이어야 합니다.") String gender, + @NotNull(message = "활동 지역은 필수값입니다.") Long regionId, - @NotNull(message = "강아지 정보 입력은 필수값입니다.") PetRequestDto pet + @Valid @NotNull(message = "강아지 정보 입력은 필수값입니다.") PetRequestDto pet ) { - public UserRegisterCommand toCommand() { + return new UserRegisterCommand( - CreateUserCommand.of(loginId, password, name, gender, age, regionId), + CreateUserCommand.of(name, birth, gender, regionId), pet.toCommand() ); } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/request/UpdateUserInfoRequestDto.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/request/UpdateUserInfoRequestDto.java new file mode 100644 index 00000000..6288163f --- /dev/null +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/request/UpdateUserInfoRequestDto.java @@ -0,0 +1,27 @@ +package org.sopt.pawkey.backendapi.domain.user.api.dto.request; + +import java.time.LocalDate; + +import org.sopt.pawkey.backendapi.domain.user.application.dto.request.UpdateUserInfoCommand; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PastOrPresent; +import jakarta.validation.constraints.Pattern; + +public record UpdateUserInfoRequestDto( + @NotBlank(message = "닉네임은 필수 입력 사항입니다.") + String name, + + @NotNull(message = "생년월일은 필수 입력 사항입니다.") + @PastOrPresent(message = "생년월일은 현재 또는 과거 날짜여야 합니다") + LocalDate birth, + + @Pattern(regexp = "^(M|F)$", message = "성별은 M 또는 F이어야 합니다.") + @NotBlank(message = "성별 선택은 필수 사항입니다.") + String gender +) { + public UpdateUserInfoCommand toCommand() { + return new UpdateUserInfoCommand(name, birth, gender); + } +} \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/response/UserInfoResponseDto.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/response/UserInfoResponseDto.java index b2411b26..52045025 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/response/UserInfoResponseDto.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/response/UserInfoResponseDto.java @@ -1,20 +1,31 @@ package org.sopt.pawkey.backendapi.domain.user.api.dto.response; +import java.time.LocalDate; + import org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity.UserEntity; public record UserInfoResponseDto( String name, - String gender, - int age, - String activeRegion + String email, + LocalDate birth, + String gender ) { - public static UserInfoResponseDto from(UserEntity user) { + public static UserInfoResponseDto of(UserEntity user, String email) { return new UserInfoResponseDto( user.getName(), - user.getGender(), - user.getAge(), - user.getRegion().getFullRegionName() - + email, + user.getBirth(), + parseGender(user.getGender()) ); } + + private static String parseGender(String gender) { + if (gender == null) + return "미선택"; + return switch (gender.toUpperCase()) { + case "M" -> "남성"; + case "F" -> "여성"; + default -> gender; + }; + } } \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/response/UserRegisterResponseDto.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/response/UserRegisterResponseDto.java index 0cccedf7..3585e6db 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/response/UserRegisterResponseDto.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/dto/response/UserRegisterResponseDto.java @@ -5,19 +5,13 @@ public record UserRegisterResponseDto( Long userId, - String userName, - String loginId, - Long petId, - String petName + Long petId ) { public static UserRegisterResponseDto from(UserEntity user, PetEntity pet) { return new UserRegisterResponseDto( user.getUserId(), - user.getName(), - user.getLoginId(), - pet.getPetId(), - pet.getName() + pet.getPetId() ); } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/dto/request/CreateUserCommand.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/dto/request/CreateUserCommand.java index f7ff30b6..063439b5 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/dto/request/CreateUserCommand.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/dto/request/CreateUserCommand.java @@ -1,16 +1,15 @@ package org.sopt.pawkey.backendapi.domain.user.application.dto.request; +import java.time.LocalDate; + public record CreateUserCommand( - String loginId, - String password, String name, + LocalDate birth, String gender, - int age, Long regionId ) { - public static CreateUserCommand of(String loginId, String password, String name, String gender, int age, - Long regionId) { - return new CreateUserCommand(loginId, password, name, gender, age, regionId); + public static CreateUserCommand of(String name, LocalDate birth, String gender, Long regionId) { + return new CreateUserCommand(name, birth, gender, regionId); } -} +} \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/dto/request/UpdateUserInfoCommand.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/dto/request/UpdateUserInfoCommand.java new file mode 100644 index 00000000..4113e270 --- /dev/null +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/dto/request/UpdateUserInfoCommand.java @@ -0,0 +1,11 @@ +package org.sopt.pawkey.backendapi.domain.user.application.dto.request; + +import java.time.LocalDate; + +public record UpdateUserInfoCommand( + String name, + LocalDate birth, + String gender + +) { +} \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UpdateUserInfoFacade.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UpdateUserInfoFacade.java new file mode 100644 index 00000000..2645514a --- /dev/null +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UpdateUserInfoFacade.java @@ -0,0 +1,24 @@ +package org.sopt.pawkey.backendapi.domain.user.application.facade; + +import org.sopt.pawkey.backendapi.domain.user.api.dto.response.UserInfoResponseDto; +import org.sopt.pawkey.backendapi.domain.user.application.dto.request.UpdateUserInfoCommand; +import org.sopt.pawkey.backendapi.domain.user.application.service.UserQueryService; +import org.sopt.pawkey.backendapi.domain.user.application.service.UserService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class UpdateUserInfoFacade { + + private final UserService userService; + private final UserQueryService userQueryService; + + @Transactional + public UserInfoResponseDto execute(Long userId, UpdateUserInfoCommand command) { + userService.updateUserInfo(userId, command); + return userQueryService.getUserInfo(userId); + } +} \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserLoginFacade.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserLoginFacade.java index a07562d3..354a56d0 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserLoginFacade.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserLoginFacade.java @@ -2,18 +2,18 @@ import java.util.Map; +import org.sopt.pawkey.backendapi.domain.auth.api.dto.response.SocialLoginResponseDTO; +import org.sopt.pawkey.backendapi.domain.auth.api.dto.response.TokenResponseDTO; +import org.sopt.pawkey.backendapi.domain.auth.application.service.login.verifier.apple.AppleTokenVerifier; +import org.sopt.pawkey.backendapi.domain.auth.application.service.login.verifier.google.GoogleTokenVerifier; +import org.sopt.pawkey.backendapi.domain.auth.application.service.login.verifier.kakao.KakaoTokenVerifier; import org.sopt.pawkey.backendapi.domain.auth.application.service.token.AppleRefreshTokenService; +import org.sopt.pawkey.backendapi.domain.auth.application.service.token.TokenService; import org.sopt.pawkey.backendapi.domain.auth.domain.Provider; import org.sopt.pawkey.backendapi.domain.auth.exception.AuthBusinessException; import org.sopt.pawkey.backendapi.domain.auth.exception.AuthErrorCode; import org.sopt.pawkey.backendapi.domain.user.api.dto.result.UserCreationResult; import org.sopt.pawkey.backendapi.domain.user.application.service.UserService; -import org.sopt.pawkey.backendapi.domain.auth.api.dto.response.SocialLoginResponseDTO; -import org.sopt.pawkey.backendapi.domain.auth.api.dto.response.TokenResponseDTO; -import org.sopt.pawkey.backendapi.domain.auth.application.service.token.TokenService; -import org.sopt.pawkey.backendapi.domain.auth.application.service.login.verifier.apple.AppleTokenVerifier; -import org.sopt.pawkey.backendapi.domain.auth.application.service.login.verifier.google.GoogleTokenVerifier; -import org.sopt.pawkey.backendapi.domain.auth.application.service.login.verifier.kakao.KakaoTokenVerifier; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserRegisterFacade.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserRegisterFacade.java index 79ae58df..a978afce 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserRegisterFacade.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserRegisterFacade.java @@ -1,7 +1,5 @@ package org.sopt.pawkey.backendapi.domain.user.application.facade; -import org.sopt.pawkey.backendapi.domain.image.application.service.command.ImageService; -import org.sopt.pawkey.backendapi.domain.image.infra.persistence.entity.ImageEntity; import org.sopt.pawkey.backendapi.domain.pet.application.service.PetService; import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetEntity; import org.sopt.pawkey.backendapi.domain.region.application.service.RegionService; @@ -12,7 +10,6 @@ import org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity.UserEntity; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; import lombok.RequiredArgsConstructor; @@ -22,26 +19,15 @@ public class UserRegisterFacade { private final UserService userService; - private final ImageService imageService; private final PetService petService; private final RegionService regionService; - public UserRegisterResponseDto execute(UserRegisterCommand command, MultipartFile petProfileImage) { - ImageEntity imageEntity = null; - try { - RegionEntity region = regionService.getDongTypeRegionByIdOrThrow(command.userCommand().regionId()); - UserEntity user = userService.saveUser(command.userCommand(), region); + public UserRegisterResponseDto execute(Long currentUserId, UserRegisterCommand command) { + RegionEntity region = regionService.getDongTypeRegionByIdOrThrow(command.userCommand().regionId()); + UserEntity user = userService.saveUser(currentUserId, command.userCommand(), region); - imageEntity = imageService.storePetProfileImage(petProfileImage); - PetEntity pet = petService.savePet(command.petCommand(), user, imageEntity); - - return UserRegisterResponseDto.from(user, pet); - } catch (Exception e) { - if (imageEntity != null) { - imageService.deleteImage(imageEntity); - } - throw e; - } + PetEntity pet = petService.savePet(command.petCommand(), user); + return UserRegisterResponseDto.from(user, pet); } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserWithdrawFacade.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserWithdrawFacade.java index a0c01bdd..aa5cb671 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserWithdrawFacade.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/UserWithdrawFacade.java @@ -1,10 +1,10 @@ package org.sopt.pawkey.backendapi.domain.user.application.facade; +import org.sopt.pawkey.backendapi.domain.auth.application.service.token.TokenService; +import org.sopt.pawkey.backendapi.domain.auth.application.service.withdraw.SocialWithdrawServiceFactory; import org.sopt.pawkey.backendapi.domain.auth.domain.Provider; import org.sopt.pawkey.backendapi.domain.user.application.service.SocialAccountService; import org.sopt.pawkey.backendapi.domain.user.application.service.UserDeletionService; -import org.sopt.pawkey.backendapi.domain.auth.application.service.token.TokenService; -import org.sopt.pawkey.backendapi.domain.auth.application.service.withdraw.SocialWithdrawServiceFactory; import org.springframework.stereotype.Service; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/command/UserPetCommandFacade.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/command/UserPetCommandFacade.java new file mode 100644 index 00000000..123f41db --- /dev/null +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/command/UserPetCommandFacade.java @@ -0,0 +1,24 @@ +package org.sopt.pawkey.backendapi.domain.user.application.facade.command; + +import org.sopt.pawkey.backendapi.domain.pet.api.dto.response.PetProfileResponseDto; +import org.sopt.pawkey.backendapi.domain.pet.application.dto.request.UpdatePetCommand; +import org.sopt.pawkey.backendapi.domain.pet.application.service.PetQueryService; +import org.sopt.pawkey.backendapi.domain.pet.application.service.PetService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class UserPetCommandFacade { + + private final PetService petService; + private final PetQueryService petQueryService; + + @Transactional + public PetProfileResponseDto updatePetInfo(Long userId, Long petId, UpdatePetCommand command) { + petService.updatePetInfo(userId, petId, command); + return petQueryService.getPetProfile(petId); + } +} \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserPetQueryFacade.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserPetQueryFacade.java index dd762c9f..653ae284 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserPetQueryFacade.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserPetQueryFacade.java @@ -3,7 +3,7 @@ import java.util.List; import org.sopt.pawkey.backendapi.domain.pet.api.dto.response.PetProfileResponseDto; -import org.sopt.pawkey.backendapi.domain.user.application.service.UserPetQueryService; +import org.sopt.pawkey.backendapi.domain.pet.application.service.PetQueryService; import org.sopt.pawkey.backendapi.domain.user.application.service.UserService; import org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity.UserEntity; import org.springframework.stereotype.Service; @@ -16,13 +16,13 @@ @Transactional(readOnly = true) public class UserPetQueryFacade { - private final UserPetQueryService userPetQueryService; + private final PetQueryService petQueryService; private final UserService userService; public List getUserPets(Long userId) { UserEntity user = userService.findById(userId); - return userPetQueryService.getPetProfiles(user); + return petQueryService.getPetProfiles(user); } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserQueryFacade.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserQueryFacade.java index d35107a1..f43d2091 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserQueryFacade.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserQueryFacade.java @@ -2,7 +2,6 @@ import org.sopt.pawkey.backendapi.domain.user.api.dto.response.UserInfoResponseDto; import org.sopt.pawkey.backendapi.domain.user.application.service.UserQueryService; -import org.sopt.pawkey.backendapi.domain.user.application.service.UserService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -12,7 +11,6 @@ @RequiredArgsConstructor @Transactional(readOnly = true) public class UserQueryFacade { - private final UserService userService; private final UserQueryService userQueryService; public UserInfoResponseDto getUserInfo(Long userId) { diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/SocialAccountService.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/SocialAccountService.java index f7c91e96..0b886d5a 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/SocialAccountService.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/SocialAccountService.java @@ -1,9 +1,9 @@ package org.sopt.pawkey.backendapi.domain.user.application.service; +import org.sopt.pawkey.backendapi.domain.auth.domain.Provider; import org.sopt.pawkey.backendapi.domain.auth.domain.repository.AppleRefreshTokenRepository; import org.sopt.pawkey.backendapi.domain.user.domain.repository.SocialAccountRepository; import org.springframework.stereotype.Service; -import org.sopt.pawkey.backendapi.domain.auth.domain.Provider; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserPetQueryService.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserPetQueryService.java deleted file mode 100644 index 4926e52a..00000000 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserPetQueryService.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.sopt.pawkey.backendapi.domain.user.application.service; - -import java.util.List; - -import org.sopt.pawkey.backendapi.domain.pet.api.dto.response.PetProfileResponseDto; -import org.sopt.pawkey.backendapi.domain.pet.domain.repository.PetRepository; -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetEntity; -import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetTraitSelectedEntity; -import org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity.UserEntity; -import org.springframework.stereotype.Service; - -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -public class UserPetQueryService { - - private final PetRepository petRepository; - - public List getPetProfiles(UserEntity user) { - List petEntityList = petRepository.findAllPetsByUserId(user.getUserId()); - - return petEntityList.stream() - .map(pet -> new PetProfileResponseDto( - pet.getPetId(), - pet.getName(), - pet.getGender(), - pet.isNeutered(), - pet.getAge(), - pet.isAgeKnown(), - pet.getBreed(), - pet.getProfileImage() != null ? pet.getProfileImage().getImageUrl() : null, - pet.getPetTraitSelectedEntityList().stream() - .map(PetTraitSelectedEntity::getPetTraitOption) - .map(option -> new PetProfileResponseDto.TraitDto( - option.getPetTraitCategory().getCategoryName(), - option.getOptionText() - )) - .toList(), - pet.getWalkCount() - )) - .toList(); - } -} \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserQueryService.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserQueryService.java index 591e1556..873df97d 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserQueryService.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserQueryService.java @@ -1,25 +1,35 @@ package org.sopt.pawkey.backendapi.domain.user.application.service; import org.sopt.pawkey.backendapi.domain.user.api.dto.response.UserInfoResponseDto; +import org.sopt.pawkey.backendapi.domain.user.domain.repository.SocialAccountRepository; import org.sopt.pawkey.backendapi.domain.user.domain.repository.UserRepository; import org.sopt.pawkey.backendapi.domain.user.exception.UserBusinessException; import org.sopt.pawkey.backendapi.domain.user.exception.UserErrorCode; +import org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity.SocialAccountEntity; import org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity.UserEntity; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import lombok.RequiredArgsConstructor; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class UserQueryService { private final UserRepository userRepository; + private final SocialAccountRepository socialAccountRepository; public UserInfoResponseDto getUserInfo(Long userId) { UserEntity user = userRepository.findById(userId) .orElseThrow(() -> new UserBusinessException(UserErrorCode.USER_NOT_FOUND)); - return UserInfoResponseDto.from(user); + + String email = socialAccountRepository.findByUser_UserId(userId) + .map(SocialAccountEntity::getPrimaryEmail) + .orElse(""); + + return UserInfoResponseDto.of(user, email); } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserService.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserService.java index 1d04ab5a..c68e29c5 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserService.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserService.java @@ -6,6 +6,7 @@ import org.sopt.pawkey.backendapi.domain.region.infra.persistence.entity.RegionEntity; import org.sopt.pawkey.backendapi.domain.user.api.dto.result.UserCreationResult; import org.sopt.pawkey.backendapi.domain.user.application.dto.request.CreateUserCommand; +import org.sopt.pawkey.backendapi.domain.user.application.dto.request.UpdateUserInfoCommand; import org.sopt.pawkey.backendapi.domain.user.domain.repository.SocialAccountRepository; import org.sopt.pawkey.backendapi.domain.user.domain.repository.UserRepository; import org.sopt.pawkey.backendapi.domain.user.exception.UserBusinessException; @@ -24,27 +25,22 @@ public class UserService { private final UserRepository userRepository; private final SocialAccountRepository socialAccountRepository; + @Transactional(readOnly = true) public UserEntity findById(final Long id) { return userRepository.findById(id) .orElseThrow(() -> new UserBusinessException(UserErrorCode.USER_NOT_FOUND)); } - public UserEntity saveUser(CreateUserCommand command, RegionEntity region) { + @Transactional + public UserEntity saveUser(Long userId, CreateUserCommand command, RegionEntity region) { - if (userRepository.existsByLoginId(command.loginId())) { - throw new UserBusinessException(UserErrorCode.USER_DUPLICATE_LOGIN_ID); - } + UserEntity user = userRepository.findById(userId) + .orElseThrow(() -> new UserBusinessException(UserErrorCode.USER_NOT_FOUND)); - UserEntity user = UserEntity.builder() - .loginId(command.loginId()) - .password(command.password()) - .name(command.name()) - .gender(command.gender()) - .age(command.age()) - .region(region) - .build(); + user.updateProfile(command.name(), command.gender(), command.birth()); + user.updateRegion(region); - return userRepository.save(user); + return user; } public void updateUserRegion(UserEntity user, RegionEntity region) { @@ -70,11 +66,9 @@ public UserCreationResult findOrCreateUserBySocialId(Provider provider, String p // 3-1. 새로운 User 엔티티 생성 (최소 정보만으로 생성) UserEntity newUser = userRepository.save(UserEntity.builder() - .loginId(platform.toLowerCase() + "_" + platformUserId) - .password("social-login-default-password") // 소셜 사용자는 비밀번호가 없지만, NOT NULL일 경우 빈 문자열 또는 임시값 지정 .name(platform + " User") - .gender("MALE") - .age(1) + .gender(null) + .birth(null) .region(null) .build()); @@ -95,6 +89,17 @@ public UserCreationResult findOrCreateUserBySocialId(Provider provider, String p } } + @Transactional + public void updateUserInfo(Long userId, UpdateUserInfoCommand command) { + UserEntity user = userRepository.findById(userId) + .orElseThrow(() -> new UserBusinessException(UserErrorCode.USER_NOT_FOUND)); + + user.updateProfile( + command.name(), + command.gender(), + command.birth() + ); + } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/domain/repository/SocialAccountRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/domain/repository/SocialAccountRepository.java index c9fc47be..408847aa 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/domain/repository/SocialAccountRepository.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/domain/repository/SocialAccountRepository.java @@ -11,4 +11,6 @@ public interface SocialAccountRepository { SocialAccountEntity save(SocialAccountEntity socialAccount); Optional findByUser_UserIdAndPlatform(Long userId, String platform); + + Optional findByUser_UserId(Long userId); } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/exception/UserErrorCode.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/exception/UserErrorCode.java index c0e37913..f37395a8 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/exception/UserErrorCode.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/exception/UserErrorCode.java @@ -11,7 +11,8 @@ public enum UserErrorCode implements ErrorCode { USER_DUPLICATE_LOGIN_ID(HttpStatus.CONFLICT, "U40901", "중복된 로그인 아이디입니다."), USER_NOT_FOUND(HttpStatus.NOT_FOUND, "U40401", "유저를 찾을 수 없습니다."), - USER_PET_NOT_REGISTERED(HttpStatus.NOT_FOUND, "U40402", "유저에게 등록된 반려견이 존재하지 않습니다."); + USER_PET_NOT_REGISTERED(HttpStatus.NOT_FOUND, "U40402", "유저에게 등록된 반려견이 존재하지 않습니다."), + UNAUTHORIZED_ACCESS(HttpStatus.FORBIDDEN, "U40301", "해당 리소스에 대한 접근 권한이 없습니다."); private final HttpStatus status; private final String code; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/SocialAccountRepositoryImpl.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/SocialAccountRepositoryImpl.java index 2d1fb06a..2f9d9e02 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/SocialAccountRepositoryImpl.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/SocialAccountRepositoryImpl.java @@ -27,4 +27,9 @@ public SocialAccountEntity save(SocialAccountEntity socialAccount) { public Optional findByUser_UserIdAndPlatform(Long userId, String platform) { return jpaRepository.findByUser_UserIdAndPlatform(userId, platform); } + + @Override + public Optional findByUser_UserId(Long userId) { + return jpaRepository.findByUser_UserId(userId); + } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/SpringDataSocialAccountRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/SpringDataSocialAccountRepository.java index 8cdc0637..011b5bde 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/SpringDataSocialAccountRepository.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/SpringDataSocialAccountRepository.java @@ -9,4 +9,6 @@ public interface SpringDataSocialAccountRepository extends JpaRepository findByPlatformAndPlatformUserId(String platform, String platformUserId); Optional findByUser_UserIdAndPlatform(Long userId, String platform); + + Optional findByUser_UserId(Long userId); } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/entity/SocialAccountEntity.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/entity/SocialAccountEntity.java index 9b1001d0..72fb1624 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/entity/SocialAccountEntity.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/entity/SocialAccountEntity.java @@ -28,7 +28,7 @@ public class SocialAccountEntity extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(fetch = FetchType.LAZY) // 1:1의 관계로 변경 됨에 따라 수정 필요! @JoinColumn(name = "user_id", nullable = false) private UserEntity user; diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/entity/UserEntity.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/entity/UserEntity.java index d97a6ca9..30345959 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/entity/UserEntity.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/infra/persistence/entity/UserEntity.java @@ -1,10 +1,12 @@ package org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; import java.util.Objects; import org.hibernate.annotations.BatchSize; +import org.hibernate.annotations.DynamicUpdate; import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetEntity; import org.sopt.pawkey.backendapi.domain.post.infra.persistence.entity.PostLikeEntity; import org.sopt.pawkey.backendapi.domain.region.infra.persistence.entity.RegionEntity; @@ -14,6 +16,7 @@ import org.sopt.pawkey.backendapi.global.infra.persistence.entity.BaseEntity; import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; @@ -35,18 +38,21 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PROTECTED) @Builder +@DynamicUpdate public class UserEntity extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long userId; - private String loginId; - private String password; - + @Column(name = "name") private String name; - private String gender; - private int age; + + @Column(name = "gender", length = 1) + private String gender; // 'M' or 'F' + + @Column(name = "birth") + private LocalDate birth; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "region_id", nullable = true) @@ -65,16 +71,12 @@ public class UserEntity extends BaseEntity { private List postLikeEntityList = new ArrayList<>(); @Builder - public UserEntity(Long userId, - String name, - String gender, - int age, - RegionEntity region) { + public UserEntity(Long userId, String name, String gender, LocalDate birth, RegionEntity region) { this.userId = userId; this.name = name; this.gender = gender; - this.age = age; - + this.birth = birth; + this.region = region; } public PetEntity getPet() { @@ -84,6 +86,7 @@ public PetEntity getPet() { } public PetEntity getPetOrThrow() { + PetEntity pet = getPet(); if (pet == null) { throw new UserBusinessException(UserErrorCode.USER_PET_NOT_REGISTERED); @@ -112,5 +115,11 @@ public int hashCode() { public void updateRegion(RegionEntity region) { this.region = region; } + + public void updateProfile(String name, String gender, LocalDate birth) { + this.name = name; + this.gender = gender; + this.birth = birth; + } }