diff --git a/src/main/java/com/wayble/server/user/controller/UserPlaceController.java b/src/main/java/com/wayble/server/user/controller/UserPlaceController.java index 0fb80e43..c6c3bf83 100644 --- a/src/main/java/com/wayble/server/user/controller/UserPlaceController.java +++ b/src/main/java/com/wayble/server/user/controller/UserPlaceController.java @@ -1,7 +1,9 @@ package com.wayble.server.user.controller; +import com.wayble.server.common.config.security.jwt.JwtTokenProvider; import com.wayble.server.common.exception.ApplicationException; import com.wayble.server.common.response.CommonResponse; +import com.wayble.server.user.dto.UserPlaceListResponseDto; import com.wayble.server.user.dto.UserPlaceRequestDto; import com.wayble.server.user.exception.UserErrorCase; import com.wayble.server.user.service.UserPlaceService; @@ -12,12 +14,16 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequestMapping("/api/v1/users/{userId}/places") @RequiredArgsConstructor public class UserPlaceController { private final UserPlaceService userPlaceService; + private final JwtTokenProvider jwtProvider; + @PostMapping @Operation(summary = "유저 장소 저장", description = "유저가 웨이블존을 장소로 저장합니다.") @@ -29,16 +35,47 @@ public class UserPlaceController { public CommonResponse saveUserPlace( @PathVariable Long userId, @RequestBody @Valid UserPlaceRequestDto request, - - // TODO: 로그인 구현 후 Authorization 헤더 필수로 변경 필요 - @RequestHeader(value = "Authorization", required = false) String authorizationHeader + @RequestHeader(value = "Authorization") String authorizationHeader ) { - // Path variable과 request body의 userId 일치 여부 확인 - if (!userId.equals(request.userId())) { - throw new ApplicationException(UserErrorCase.INVALID_USER_ID); + String token = authorizationHeader.replace("Bearer ", ""); + if (!jwtProvider.validateToken(token)) { + throw new ApplicationException(UserErrorCase.FORBIDDEN); } + Long tokenUserId = jwtProvider.getUserId(token); + // Path variable과 request body의 userId 일치 여부 확인 + if (!userId.equals(request.userId()) || !userId.equals(tokenUserId)) { + throw new ApplicationException(UserErrorCase.FORBIDDEN); + } userPlaceService.saveUserPlace(request); return CommonResponse.success("장소가 저장되었습니다."); } + + @GetMapping + @Operation( + summary = "내가 저장한 장소 목록 조회", + description = "유저가 저장한 모든 장소 및 해당 웨이블존 정보를 조회합니다." + ) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "장소 목록 조회 성공"), + @ApiResponse(responseCode = "404", description = "해당 유저를 찾을 수 없음"), + @ApiResponse(responseCode = "403", description = "권한이 없습니다.") + }) + public CommonResponse> getUserPlaces( + @PathVariable Long userId, + @RequestHeader("Authorization") String authorizationHeader + ) { + String token = authorizationHeader.replace("Bearer ", ""); + if (!jwtProvider.validateToken(token)) { + throw new ApplicationException(UserErrorCase.FORBIDDEN); + } + Long tokenUserId = jwtProvider.getUserId(token); + + if (!userId.equals(tokenUserId)) { + throw new ApplicationException(UserErrorCase.FORBIDDEN); + } + + List places = userPlaceService.getUserPlaces(userId); + return CommonResponse.success(places); + } } diff --git a/src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java b/src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java new file mode 100644 index 00000000..73f155b9 --- /dev/null +++ b/src/main/java/com/wayble/server/user/dto/UserPlaceListResponseDto.java @@ -0,0 +1,22 @@ +package com.wayble.server.user.dto; + +import lombok.Builder; + + + +@Builder +public record UserPlaceListResponseDto( + Long place_id, + String title, + WaybleZoneDto wayble_zone +) { + @Builder + public record WaybleZoneDto( + Long wayble_zone_id, + String name, + String category, + double rating, + String address, + String image_url + ) {} +} \ No newline at end of file diff --git a/src/main/java/com/wayble/server/user/exception/UserErrorCase.java b/src/main/java/com/wayble/server/user/exception/UserErrorCase.java index 6398394b..531158e7 100644 --- a/src/main/java/com/wayble/server/user/exception/UserErrorCase.java +++ b/src/main/java/com/wayble/server/user/exception/UserErrorCase.java @@ -13,7 +13,8 @@ public enum UserErrorCase implements ErrorCase { PLACE_ALREADY_SAVED(400, 1003, "이미 저장한 장소입니다."), INVALID_USER_ID(400, 1004, "요청 경로의 유저 ID와 바디의 유저 ID가 일치하지 않습니다."), USER_ALREADY_EXISTS(400, 1005, "이미 존재하는 회원입니다."), - INVALID_CREDENTIALS(400, 1006, "아이디 혹은 비밀번호가 잘못되었습니다."); + INVALID_CREDENTIALS(400, 1006, "아이디 혹은 비밀번호가 잘못되었습니다."), + FORBIDDEN(403, 1007, "권한이 없습니다."); private final Integer httpStatusCode; private final Integer errorCode; diff --git a/src/main/java/com/wayble/server/user/repository/UserPlaceWaybleZoneMappingRepository.java b/src/main/java/com/wayble/server/user/repository/UserPlaceWaybleZoneMappingRepository.java index 763c2c8a..89ca8b85 100644 --- a/src/main/java/com/wayble/server/user/repository/UserPlaceWaybleZoneMappingRepository.java +++ b/src/main/java/com/wayble/server/user/repository/UserPlaceWaybleZoneMappingRepository.java @@ -3,6 +3,9 @@ import com.wayble.server.user.entity.UserPlaceWaybleZoneMapping; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + public interface UserPlaceWaybleZoneMappingRepository extends JpaRepository { boolean existsByUserPlace_User_IdAndWaybleZone_Id(Long userId, Long zoneId); + List findAllByUserPlace_User_Id(Long userId); } diff --git a/src/main/java/com/wayble/server/user/service/UserPlaceService.java b/src/main/java/com/wayble/server/user/service/UserPlaceService.java index 55539022..24885ee4 100644 --- a/src/main/java/com/wayble/server/user/service/UserPlaceService.java +++ b/src/main/java/com/wayble/server/user/service/UserPlaceService.java @@ -2,6 +2,7 @@ import com.wayble.server.common.exception.ApplicationException; +import com.wayble.server.user.dto.UserPlaceListResponseDto; import com.wayble.server.user.dto.UserPlaceRequestDto; import com.wayble.server.user.entity.User; import com.wayble.server.user.entity.UserPlace; @@ -16,6 +17,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.List; + @Service @RequiredArgsConstructor public class UserPlaceService { @@ -56,4 +59,36 @@ public void saveUserPlace(UserPlaceRequestDto request) { .build() ); } + + public List getUserPlaces(Long userId) { + // 유저 존재 여부 확인 + User user = userRepository.findById(userId) + .orElseThrow(() -> new ApplicationException(UserErrorCase.USER_NOT_FOUND)); + + List mappings = mappingRepository.findAllByUserPlace_User_Id(userId); + + return mappings.stream().map(mapping -> { + UserPlace userPlace = mapping.getUserPlace(); + WaybleZone waybleZone = mapping.getWaybleZone(); + + // 웨이블존 대표 이미지 가져오기 + String imageUrl = waybleZone.getWaybleZoneImageList().stream() + .findFirst().map(img -> img.getImageUrl()).orElse(null); + + return UserPlaceListResponseDto.builder() + .place_id(userPlace.getId()) + .title(userPlace.getTitle()) + .wayble_zone( + UserPlaceListResponseDto.WaybleZoneDto.builder() + .wayble_zone_id(waybleZone.getId()) + .name(waybleZone.getZoneName()) + .category(waybleZone.getZoneType().toString()) + .rating(waybleZone.getRating()) + .address(waybleZone.getAddress().toFullAddress()) + .image_url(imageUrl) + .build() + ) + .build(); + }).toList(); + } } \ No newline at end of file