diff --git a/src/main/java/org/hankki/hankkiserver/api/advice/GlobalExceptionHandler.java b/src/main/java/org/hankki/hankkiserver/api/advice/GlobalExceptionHandler.java index 44e6cad8..79484a6d 100644 --- a/src/main/java/org/hankki/hankkiserver/api/advice/GlobalExceptionHandler.java +++ b/src/main/java/org/hankki/hankkiserver/api/advice/GlobalExceptionHandler.java @@ -7,7 +7,6 @@ import org.hankki.hankkiserver.common.exception.ConflictException; import org.hankki.hankkiserver.common.exception.NotFoundException; import org.hankki.hankkiserver.common.exception.UnauthorizedException; - import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; diff --git a/src/main/java/org/hankki/hankkiserver/api/auth/controller/AuthController.java b/src/main/java/org/hankki/hankkiserver/api/auth/controller/AuthController.java index 10fa22cf..309e22f0 100644 --- a/src/main/java/org/hankki/hankkiserver/api/auth/controller/AuthController.java +++ b/src/main/java/org/hankki/hankkiserver/api/auth/controller/AuthController.java @@ -1,6 +1,7 @@ package org.hankki.hankkiserver.api.auth.controller; import jakarta.annotation.Nullable; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.hankki.hankkiserver.auth.UserId; import org.hankki.hankkiserver.api.dto.HankkiResponse; @@ -22,7 +23,7 @@ public class AuthController { @PostMapping("/auth/login") public HankkiResponse login( @RequestHeader(HttpHeaders.AUTHORIZATION) final String token, - @RequestBody final UserLoginRequest request) { + @Valid @RequestBody final UserLoginRequest request) { final UserLoginResponse response = authService.login(token, request); return HankkiResponse.success(CommonSuccessCode.OK, response); } diff --git a/src/main/java/org/hankki/hankkiserver/api/auth/controller/request/UserLoginRequest.java b/src/main/java/org/hankki/hankkiserver/api/auth/controller/request/UserLoginRequest.java index 7caafcc1..27310e49 100644 --- a/src/main/java/org/hankki/hankkiserver/api/auth/controller/request/UserLoginRequest.java +++ b/src/main/java/org/hankki/hankkiserver/api/auth/controller/request/UserLoginRequest.java @@ -1,10 +1,12 @@ package org.hankki.hankkiserver.api.auth.controller.request; import jakarta.annotation.Nullable; +import jakarta.validation.constraints.NotNull; public record UserLoginRequest( @Nullable String name, + @NotNull String platform ) { } diff --git a/src/main/java/org/hankki/hankkiserver/api/store/controller/StoreController.java b/src/main/java/org/hankki/hankkiserver/api/store/controller/StoreController.java index 09e9e9d5..c52b2665 100644 --- a/src/main/java/org/hankki/hankkiserver/api/store/controller/StoreController.java +++ b/src/main/java/org/hankki/hankkiserver/api/store/controller/StoreController.java @@ -2,21 +2,17 @@ import lombok.RequiredArgsConstructor; import org.hankki.hankkiserver.api.dto.HankkiResponse; -import org.hankki.hankkiserver.api.store.service.StoreQueryService; -import org.hankki.hankkiserver.api.store.service.response.*; -import org.hankki.hankkiserver.common.code.CommonSuccessCode; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.hankki.hankkiserver.auth.UserId; +import org.hankki.hankkiserver.api.store.controller.request.StoreDuplicateValidationRequest; import org.hankki.hankkiserver.api.store.service.HeartCommandService; +import org.hankki.hankkiserver.api.store.service.StoreQueryService; import org.hankki.hankkiserver.api.store.service.command.StoreDeleteCommand; import org.hankki.hankkiserver.api.store.service.command.StorePostCommand; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.hankki.hankkiserver.api.store.service.command.StoreValidationCommand; +import org.hankki.hankkiserver.api.store.service.response.*; +import org.hankki.hankkiserver.auth.UserId; +import org.hankki.hankkiserver.common.code.CommonSuccessCode; import org.springframework.web.bind.annotation.*; - @RestController @RequiredArgsConstructor @RequestMapping("/api/v1") @@ -59,4 +55,10 @@ public HankkiResponse createHeartStore(@UserId final Long u public HankkiResponse deleteHeartStore(@UserId final Long userId, @PathVariable final Long id) { return HankkiResponse.success(CommonSuccessCode.OK, heartCommandService.deleteHeart(StoreDeleteCommand.of(userId, id))); } + + @GetMapping("/stores/validate") + public HankkiResponse validateDuplicatedStore(@RequestBody final StoreDuplicateValidationRequest request) { + storeQueryService.validateDuplicatedStore(StoreValidationCommand.of(request)); + return HankkiResponse.success(CommonSuccessCode.OK); + } } diff --git a/src/main/java/org/hankki/hankkiserver/api/store/controller/request/StoreDuplicateValidationRequest.java b/src/main/java/org/hankki/hankkiserver/api/store/controller/request/StoreDuplicateValidationRequest.java new file mode 100644 index 00000000..2e310c42 --- /dev/null +++ b/src/main/java/org/hankki/hankkiserver/api/store/controller/request/StoreDuplicateValidationRequest.java @@ -0,0 +1,8 @@ +package org.hankki.hankkiserver.api.store.controller.request; + +public record StoreDuplicateValidationRequest( + long universityId, + double latitude, + double longitude +) { +} diff --git a/src/main/java/org/hankki/hankkiserver/api/store/service/HeartFinder.java b/src/main/java/org/hankki/hankkiserver/api/store/service/HeartFinder.java index 34a6a9dd..95c4feca 100644 --- a/src/main/java/org/hankki/hankkiserver/api/store/service/HeartFinder.java +++ b/src/main/java/org/hankki/hankkiserver/api/store/service/HeartFinder.java @@ -1,14 +1,11 @@ package org.hankki.hankkiserver.api.store.service; import lombok.RequiredArgsConstructor; -import org.hankki.hankkiserver.domain.heart.model.Heart; import org.hankki.hankkiserver.domain.heart.repository.HeartRepository; import org.hankki.hankkiserver.domain.store.model.Store; import org.hankki.hankkiserver.domain.user.model.User; import org.springframework.stereotype.Component; -import java.util.Optional; - @Component @RequiredArgsConstructor public class HeartFinder { diff --git a/src/main/java/org/hankki/hankkiserver/api/store/service/StoreFinder.java b/src/main/java/org/hankki/hankkiserver/api/store/service/StoreFinder.java index 27710468..bc38aca8 100644 --- a/src/main/java/org/hankki/hankkiserver/api/store/service/StoreFinder.java +++ b/src/main/java/org/hankki/hankkiserver/api/store/service/StoreFinder.java @@ -7,6 +7,8 @@ import org.hankki.hankkiserver.domain.store.repository.StoreRepository; import org.springframework.stereotype.Component; +import java.util.Optional; + @Component @RequiredArgsConstructor public class StoreFinder { @@ -27,4 +29,8 @@ protected Store findByIdWithHeartAndIsDeletedFalse(final Long id) { return storeRepository.findByIdWithHeartAndIsDeletedFalse(id) .orElseThrow(() -> new NotFoundException(StoreErrorCode.STORE_NOT_FOUND)); } + + protected Optional findByLatitudeAndLongitude(final double latitude, final double longitude) { + return storeRepository.findByPoint_LatitudeAndPoint_Longitude(latitude, longitude); + } } diff --git a/src/main/java/org/hankki/hankkiserver/api/store/service/StoreQueryService.java b/src/main/java/org/hankki/hankkiserver/api/store/service/StoreQueryService.java index 21ca9ab7..be4e8fbf 100644 --- a/src/main/java/org/hankki/hankkiserver/api/store/service/StoreQueryService.java +++ b/src/main/java/org/hankki/hankkiserver/api/store/service/StoreQueryService.java @@ -1,11 +1,14 @@ package org.hankki.hankkiserver.api.store.service; - import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.hankki.hankkiserver.api.menu.service.MenuFinder; import org.hankki.hankkiserver.api.store.parameter.PriceCategory; import org.hankki.hankkiserver.api.store.parameter.SortOption; +import org.hankki.hankkiserver.api.store.service.command.StoreValidationCommand; import org.hankki.hankkiserver.api.store.service.response.*; +import org.hankki.hankkiserver.common.code.StoreErrorCode; +import org.hankki.hankkiserver.common.exception.ConflictException; import org.hankki.hankkiserver.domain.heart.model.Heart; import org.hankki.hankkiserver.domain.store.model.Store; import org.hankki.hankkiserver.domain.store.model.StoreCategory; @@ -18,9 +21,11 @@ @Service @RequiredArgsConstructor +@Slf4j public class StoreQueryService { private final StoreFinder storeFinder; + private final UniversityStoreFinder universityStoreFinder; private final MenuFinder menuFinder; @Transactional(readOnly = true) @@ -74,4 +79,21 @@ private boolean isLiked(final Long id, final Store store) { private static boolean isLiked(final Long id, final Heart heart) { return heart.getUser().getId().equals(id); } + + @Transactional(readOnly = true) + public void validateDuplicatedStore(final StoreValidationCommand command) { + storeFinder.findByLatitudeAndLongitude(command.latitude(), command.longitude()) + .ifPresent(store -> findUniversityStore(command.universityId(), store)); + + } + + private void findUniversityStore(final Long universityId, final Store store) { + if (isExistedUniversityStore(universityId, store)) { + throw new ConflictException(StoreErrorCode.STORE_ALREADY_REGISTERED); + } + } + + private boolean isExistedUniversityStore(final Long universityId, final Store store) { + return universityStoreFinder.existsByUniversityIdAndStore(universityId, store); + } } diff --git a/src/main/java/org/hankki/hankkiserver/api/store/service/UniversityStoreFinder.java b/src/main/java/org/hankki/hankkiserver/api/store/service/UniversityStoreFinder.java new file mode 100644 index 00000000..0e6c4328 --- /dev/null +++ b/src/main/java/org/hankki/hankkiserver/api/store/service/UniversityStoreFinder.java @@ -0,0 +1,17 @@ +package org.hankki.hankkiserver.api.store.service; + +import lombok.RequiredArgsConstructor; +import org.hankki.hankkiserver.domain.store.model.Store; +import org.hankki.hankkiserver.domain.universitystore.repository.UniversityStoreRepository; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class UniversityStoreFinder { + + private final UniversityStoreRepository universityStoreRepository; + + protected boolean existsByUniversityIdAndStore(final Long universityId, final Store store) { + return universityStoreRepository.existsByUniversityIdAndStore(universityId, store); + } +} diff --git a/src/main/java/org/hankki/hankkiserver/api/store/service/command/StoreValidationCommand.java b/src/main/java/org/hankki/hankkiserver/api/store/service/command/StoreValidationCommand.java new file mode 100644 index 00000000..6159d1c1 --- /dev/null +++ b/src/main/java/org/hankki/hankkiserver/api/store/service/command/StoreValidationCommand.java @@ -0,0 +1,13 @@ +package org.hankki.hankkiserver.api.store.service.command; + +import org.hankki.hankkiserver.api.store.controller.request.StoreDuplicateValidationRequest; + +public record StoreValidationCommand ( + long universityId, + double latitude, + double longitude +) { + public static StoreValidationCommand of(StoreDuplicateValidationRequest request) { + return new StoreValidationCommand(request.universityId(), request.latitude(), request.longitude()); + } +} diff --git a/src/main/java/org/hankki/hankkiserver/api/store/service/response/StoreDuplicateErrorResponse.java b/src/main/java/org/hankki/hankkiserver/api/store/service/response/StoreDuplicateErrorResponse.java new file mode 100644 index 00000000..79bd5d6e --- /dev/null +++ b/src/main/java/org/hankki/hankkiserver/api/store/service/response/StoreDuplicateErrorResponse.java @@ -0,0 +1,6 @@ +package org.hankki.hankkiserver.api.store.service.response; + +public record StoreDuplicateErrorResponse( + Long storeId +) { +} diff --git a/src/main/java/org/hankki/hankkiserver/api/user/controller/UserController.java b/src/main/java/org/hankki/hankkiserver/api/user/controller/UserController.java index c719af8e..e00ac83c 100644 --- a/src/main/java/org/hankki/hankkiserver/api/user/controller/UserController.java +++ b/src/main/java/org/hankki/hankkiserver/api/user/controller/UserController.java @@ -24,7 +24,7 @@ public class UserController { @PostMapping("/users/me/university") public HankkiResponse postUserUniversity(@UserId final Long userId, - @Valid @RequestBody final UserUniversityPostRequest request) { + @Valid @RequestBody final UserUniversityPostRequest request) { userCommandService.saveUserUniversity(new UserUniversityPostCommand(userId, request)); return HankkiResponse.success(CommonSuccessCode.CREATED); } @@ -36,11 +36,11 @@ public HankkiResponse findUserUniversity(@UserId fin @GetMapping("/users/me") public HankkiResponse getUserProfileAndNickname(@UserId final Long userId) { - return HankkiResponse.success(CommonSuccessCode.OK, userQueryService.getUserProfileAndNickname(userId)); + return HankkiResponse.success(CommonSuccessCode.OK, userQueryService.getUserProfileAndNickname(userId)); } @GetMapping("/users/me/favorites") public HankkiResponse findUserFavorites(@UserId final Long userId) { - return HankkiResponse.success(CommonSuccessCode.OK,userQueryService.findUserFavorites(userId)); + return HankkiResponse.success(CommonSuccessCode.OK, userQueryService.findUserFavorites(userId)); } } diff --git a/src/main/java/org/hankki/hankkiserver/api/user/service/UserQueryService.java b/src/main/java/org/hankki/hankkiserver/api/user/service/UserQueryService.java index e23807a1..41da7934 100644 --- a/src/main/java/org/hankki/hankkiserver/api/user/service/UserQueryService.java +++ b/src/main/java/org/hankki/hankkiserver/api/user/service/UserQueryService.java @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import org.hankki.hankkiserver.api.auth.service.UserInfoFinder; import org.hankki.hankkiserver.api.favorite.service.FavoriteFinder; +import org.hankki.hankkiserver.api.store.service.HeartFinder; import org.hankki.hankkiserver.api.user.service.response.UserFavoritesGetResponse; import org.hankki.hankkiserver.api.user.service.response.UserProfileAndNicknameResponse; import org.hankki.hankkiserver.api.user.service.response.UserUniversityFindResponse; @@ -18,6 +19,7 @@ public class UserQueryService { private final UserUniversityFinder userUniversityFinder; private final FavoriteFinder favoriteFinder; private final UserInfoFinder userInfoFinder; + private final HeartFinder heartFinder; @Transactional(readOnly = true) public UserUniversityFindResponse findUserUniversity(Long userId) { @@ -27,11 +29,11 @@ public UserUniversityFindResponse findUserUniversity(Long userId) { @Transactional(readOnly = true) public UserFavoritesGetResponse findUserFavorites(final Long userId) { - return UserFavoritesGetResponse.of(favoriteFinder.findAllByUserId(userId)); + return UserFavoritesGetResponse.of(favoriteFinder.findAllByUserId(userId)); } @Transactional(readOnly = true) public UserProfileAndNicknameResponse getUserProfileAndNickname(final Long userId) { - return UserProfileAndNicknameResponse.of(userInfoFinder.getUserInfo(userId)); + return UserProfileAndNicknameResponse.of(userInfoFinder.getUserInfo(userId)); } } diff --git a/src/main/java/org/hankki/hankkiserver/common/code/StoreErrorCode.java b/src/main/java/org/hankki/hankkiserver/common/code/StoreErrorCode.java index d88b16f9..16dc03de 100644 --- a/src/main/java/org/hankki/hankkiserver/common/code/StoreErrorCode.java +++ b/src/main/java/org/hankki/hankkiserver/common/code/StoreErrorCode.java @@ -8,7 +8,8 @@ @RequiredArgsConstructor public enum StoreErrorCode implements ErrorCode { - STORE_NOT_FOUND(HttpStatus.NOT_FOUND, "가게를 찾을 수 없습니다."); + STORE_NOT_FOUND(HttpStatus.NOT_FOUND, "가게를 찾을 수 없습니다."), + STORE_ALREADY_REGISTERED(HttpStatus.CONFLICT, "이미 등록된 가게입니다."); private final HttpStatus httpStatus; private final String message; diff --git a/src/main/java/org/hankki/hankkiserver/domain/heart/model/Heart.java b/src/main/java/org/hankki/hankkiserver/domain/heart/model/Heart.java index fef0fc65..879e91fa 100644 --- a/src/main/java/org/hankki/hankkiserver/domain/heart/model/Heart.java +++ b/src/main/java/org/hankki/hankkiserver/domain/heart/model/Heart.java @@ -38,5 +38,4 @@ public static final Heart createHeart(User user, Store store) { .store(store) .build(); } - } diff --git a/src/main/java/org/hankki/hankkiserver/domain/store/model/Store.java b/src/main/java/org/hankki/hankkiserver/domain/store/model/Store.java index f55a714e..ea8e4866 100644 --- a/src/main/java/org/hankki/hankkiserver/domain/store/model/Store.java +++ b/src/main/java/org/hankki/hankkiserver/domain/store/model/Store.java @@ -9,6 +9,7 @@ import org.hankki.hankkiserver.domain.common.BaseTimeEntity; import org.hankki.hankkiserver.domain.common.Point; import org.hankki.hankkiserver.domain.heart.model.Heart; +import org.hankki.hankkiserver.domain.universitystore.model.UniversityStore; import org.hibernate.annotations.BatchSize; @Entity @@ -48,6 +49,9 @@ public class Store extends BaseTimeEntity { @BatchSize(size = 100) private List images = new ArrayList<>(); + @OneToMany(mappedBy = "store") + private List universityStores = new ArrayList<>(); + public String getImage() { if (images.isEmpty()) { return "default.com"; diff --git a/src/main/java/org/hankki/hankkiserver/domain/store/model/StoreCategory.java b/src/main/java/org/hankki/hankkiserver/domain/store/model/StoreCategory.java index c1860158..e05bac81 100644 --- a/src/main/java/org/hankki/hankkiserver/domain/store/model/StoreCategory.java +++ b/src/main/java/org/hankki/hankkiserver/domain/store/model/StoreCategory.java @@ -1,9 +1,7 @@ package org.hankki.hankkiserver.domain.store.model; -import lombok.AllArgsConstructor; import lombok.Getter; import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; @Getter @RequiredArgsConstructor diff --git a/src/main/java/org/hankki/hankkiserver/domain/store/repository/StoreRepository.java b/src/main/java/org/hankki/hankkiserver/domain/store/repository/StoreRepository.java index 4fa67e8f..788c0765 100644 --- a/src/main/java/org/hankki/hankkiserver/domain/store/repository/StoreRepository.java +++ b/src/main/java/org/hankki/hankkiserver/domain/store/repository/StoreRepository.java @@ -12,4 +12,9 @@ public interface StoreRepository extends JpaRepository { @Query("select s from Store s join fetch s.hearts where s.id = :id and s.isDeleted = false") Optional findByIdWithHeartAndIsDeletedFalse(Long id); + + @Query("select s from Store s where s.point.latitude = :latitude and s.point.longitude = :longitude") + Optional findByPoint_LatitudeAndPoint_Longitude(double latitude, double longitude); + + Optional findByName(String name); } diff --git a/src/main/java/org/hankki/hankkiserver/domain/universitystore/model/UniversityStore.java b/src/main/java/org/hankki/hankkiserver/domain/universitystore/model/UniversityStore.java index 71625a11..be6147f2 100644 --- a/src/main/java/org/hankki/hankkiserver/domain/universitystore/model/UniversityStore.java +++ b/src/main/java/org/hankki/hankkiserver/domain/universitystore/model/UniversityStore.java @@ -24,5 +24,4 @@ public class UniversityStore { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "store_id") private Store store; - } diff --git a/src/main/java/org/hankki/hankkiserver/domain/universitystore/repository/UniversityStoreRepository.java b/src/main/java/org/hankki/hankkiserver/domain/universitystore/repository/UniversityStoreRepository.java index 339e5b14..f4653170 100644 --- a/src/main/java/org/hankki/hankkiserver/domain/universitystore/repository/UniversityStoreRepository.java +++ b/src/main/java/org/hankki/hankkiserver/domain/universitystore/repository/UniversityStoreRepository.java @@ -1,7 +1,10 @@ package org.hankki.hankkiserver.domain.universitystore.repository; +import org.hankki.hankkiserver.domain.store.model.Store; import org.hankki.hankkiserver.domain.universitystore.model.UniversityStore; import org.springframework.data.jpa.repository.JpaRepository; public interface UniversityStoreRepository extends JpaRepository { + + boolean existsByUniversityIdAndStore(Long universityId, Store store); } diff --git a/src/main/java/org/hankki/hankkiserver/domain/user/model/UserInfo.java b/src/main/java/org/hankki/hankkiserver/domain/user/model/UserInfo.java index 9cd87f34..cd0ca008 100644 --- a/src/main/java/org/hankki/hankkiserver/domain/user/model/UserInfo.java +++ b/src/main/java/org/hankki/hankkiserver/domain/user/model/UserInfo.java @@ -1,6 +1,5 @@ package org.hankki.hankkiserver.domain.user.model; - import jakarta.persistence.*; import lombok.*; diff --git a/src/main/java/org/hankki/hankkiserver/domain/user/repository/UserInfoRepository.java b/src/main/java/org/hankki/hankkiserver/domain/user/repository/UserInfoRepository.java index a238ea15..91aa6b33 100644 --- a/src/main/java/org/hankki/hankkiserver/domain/user/repository/UserInfoRepository.java +++ b/src/main/java/org/hankki/hankkiserver/domain/user/repository/UserInfoRepository.java @@ -1,6 +1,5 @@ package org.hankki.hankkiserver.domain.user.repository; - import org.hankki.hankkiserver.domain.user.model.UserInfo; import org.springframework.data.jpa.repository.JpaRepository;