From 57946ff263f7d6b2a84d8b522ce94b403e3cb4a5 Mon Sep 17 00:00:00 2001 From: jun23314 Date: Wed, 18 Sep 2024 00:48:39 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20UserScrapTour=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/tour/entity/UserScrapTour.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/com/projectX/projectX/domain/tour/entity/UserScrapTour.java diff --git a/src/main/java/com/projectX/projectX/domain/tour/entity/UserScrapTour.java b/src/main/java/com/projectX/projectX/domain/tour/entity/UserScrapTour.java new file mode 100644 index 0000000..e2c00a2 --- /dev/null +++ b/src/main/java/com/projectX/projectX/domain/tour/entity/UserScrapTour.java @@ -0,0 +1,38 @@ +package com.projectX.projectX.domain.tour.entity; + +import com.projectX.projectX.domain.member.entity.Member; +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 lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class UserScrapTour { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "tour_id") + private Tour tour; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "member_id") + private Member member; + + @Builder + public UserScrapTour(Tour tour, Member member) { + this.tour = tour; + this.member = member; + } +} From d59854351271dd6aaec7eb4858778eb7c9c0b94f Mon Sep 17 00:00:00 2001 From: jun23314 Date: Wed, 18 Sep 2024 00:56:57 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20method=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../projectX/domain/tour/entity/Tour.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/main/java/com/projectX/projectX/domain/tour/entity/Tour.java b/src/main/java/com/projectX/projectX/domain/tour/entity/Tour.java index 9c2c20d..940e681 100644 --- a/src/main/java/com/projectX/projectX/domain/tour/entity/Tour.java +++ b/src/main/java/com/projectX/projectX/domain/tour/entity/Tour.java @@ -1,8 +1,10 @@ package com.projectX.projectX.domain.tour.entity; +import com.projectX.projectX.domain.member.entity.Member; import com.projectX.projectX.global.common.BaseEntity; import com.projectX.projectX.global.common.ContentType; import com.projectX.projectX.global.common.JejuRegion; +import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; @@ -13,6 +15,7 @@ import jakarta.persistence.OneToMany; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -86,6 +89,10 @@ public class Tour extends BaseEntity { @Comment("카카오맵 URL") private String kakaoMapUrl; + @Comment("user 스크랩 정보") + @OneToMany(mappedBy = "tour", cascade = CascadeType.ALL, orphanRemoval = true) + private List scraps; + @Builder public Tour(Long id, String address, String spec_address, Long zipCode, Long contentId, ContentType contentType, JejuRegion jejuRegion, String imageUrl, float mapX, float mapY, @@ -119,4 +126,23 @@ public void updatePhone(String phone) { public void updateKakaoMapUrl(String kakaoMapUrl){ this.kakaoMapUrl = kakaoMapUrl; } + + public Boolean updateScrap(Tour tour, Member member) { + UserScrapTour forRemove = null; + for (UserScrapTour scrap : this.scraps) { + if (Objects.equals(scrap.getTour(), tour) && Objects.equals(scrap.getMember(), + member)) { + forRemove = scrap; + break; + } + } + + if (Objects.nonNull(forRemove)) { + this.scraps.remove(forRemove); + return false; + } + + this.scraps.add(new UserScrapTour(tour, member)); + return true; + } } \ No newline at end of file From 13668d1f6e460530e84aafde98d59ee46516c519 Mon Sep 17 00:00:00 2001 From: jun23314 Date: Wed, 18 Sep 2024 00:57:16 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/travel/service/TravelService.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/java/com/projectX/projectX/domain/travel/service/TravelService.java b/src/main/java/com/projectX/projectX/domain/travel/service/TravelService.java index a5ee304..d333ab5 100644 --- a/src/main/java/com/projectX/projectX/domain/travel/service/TravelService.java +++ b/src/main/java/com/projectX/projectX/domain/travel/service/TravelService.java @@ -1,5 +1,8 @@ package com.projectX.projectX.domain.travel.service; +import com.projectX.projectX.domain.member.entity.Member; +import com.projectX.projectX.domain.member.exception.InvalidMemberException; +import com.projectX.projectX.domain.member.repository.MemberRepository; import com.projectX.projectX.domain.tour.entity.Tour; import com.projectX.projectX.domain.tour.entity.TourImage; import com.projectX.projectX.domain.tour.repository.TourRepository; @@ -33,6 +36,7 @@ public class TravelService { private final TourRepository tourRepository; + private final MemberRepository memberRepository; private static final int RECOMMEND_WORK_SIZE = 3; @Transactional(readOnly = true) @@ -82,6 +86,14 @@ private Tour getTour(long tourId) { .orElseThrow(() -> new TravelNotFoundException(ErrorCode.TRAVEL_NOT_FOUND)); } + private Member getMember(String userEmail) { + Member member = memberRepository.findByUserEmail(userEmail).orElseThrow( + () -> new InvalidMemberException(ErrorCode.INVALID_MEMBER_EXCEPTION) + ); + + return member; + } + private List getTravelImageUrlList(List tourImageList) { if (tourImageList.isEmpty()) { return null; @@ -113,5 +125,13 @@ public List getTravelRecommd(JejuRegion jejuRegion) { return TravelMapper.toTravelGetRecommendResponse(tours); } + @Transactional + public String postTravelScrapInfo(Long travelId, String userEmail) { + Tour tour = getTour(travelId); + Member member = getMember(userEmail); + + Boolean result = tour.updateScrap(tour, member); + return result ? "travel 정보를 스크랩했습니다." : "travel 스크랩을 취소했습니다."; + } } From 55f5e29294bd69444b27d570e815d93a6db3f0a6 Mon Sep 17 00:00:00 2001 From: jun23314 Date: Wed, 18 Sep 2024 00:57:27 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20=EC=8A=A4=ED=81=AC=EB=9E=A9=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../travel/controller/TravelRestController.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/projectX/projectX/domain/travel/controller/TravelRestController.java b/src/main/java/com/projectX/projectX/domain/travel/controller/TravelRestController.java index fa03dfb..c5ed56e 100644 --- a/src/main/java/com/projectX/projectX/domain/travel/controller/TravelRestController.java +++ b/src/main/java/com/projectX/projectX/domain/travel/controller/TravelRestController.java @@ -5,6 +5,7 @@ import com.projectX.projectX.domain.travel.service.TravelService; import com.projectX.projectX.global.common.JejuRegion; import com.projectX.projectX.global.common.ResponseDTO; +import com.projectX.projectX.global.security.dto.CustomOAuth2User; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.constraints.NotBlank; @@ -12,8 +13,10 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; @@ -59,4 +62,15 @@ public ResponseDTO getRecommdTravelInfo( return ResponseDTO.res(travelService.getTravelRecommd(jejuRegion), "travel 추천 조회에 성공했습니다."); } + @PostMapping("/{travel_id}/scrap") + @ResponseStatus(HttpStatus.CREATED) + @Operation(summary = "travel 스크랩 API", description = "travel 게시물을 스크랩하는 API입니다.") + public ResponseDTO postTravelScrapInfo( + @PathVariable("travel_id") @NotNull Long travelId, + @AuthenticationPrincipal CustomOAuth2User user + ) { + String result = travelService.postTravelScrapInfo(travelId, user.getEmail()); + return ResponseDTO.res(result); + } + }