Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] - 여행 계획 공유 기능 구현 #203

Merged
merged 9 commits into from
Aug 4, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import kr.touroot.authentication.infrastructure.JwtTokenProvider;
import kr.touroot.global.auth.dto.HttpRequestInfo;
import kr.touroot.global.exception.dto.ExceptionResponse;
Expand All @@ -17,9 +19,6 @@
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.List;

@RequiredArgsConstructor
@Slf4j
@Component
Expand All @@ -39,6 +38,7 @@ public class JwtAuthFilter extends OncePerRequestFilter {
new HttpRequestInfo(HttpMethod.GET, "/v3/api-docs/**"),
new HttpRequestInfo(HttpMethod.GET, "/api/v1/travelogues/**"),
new HttpRequestInfo(HttpMethod.GET, "/api/v1/login/**"),
new HttpRequestInfo(HttpMethod.GET, "/api/v1/travel-plans/shared/**"),
new HttpRequestInfo(HttpMethod.OPTIONS, "/**")
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.net.URI;
import java.util.UUID;
import kr.touroot.global.auth.dto.MemberAuth;
import kr.touroot.global.exception.dto.ExceptionResponse;
import kr.touroot.travelplan.dto.request.TravelPlanCreateRequest;
Expand All @@ -16,9 +18,12 @@
import kr.touroot.travelplan.service.TravelPlanService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.net.URI;
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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "여행 계획")
@RequiredArgsConstructor
Expand Down Expand Up @@ -80,4 +85,24 @@ public ResponseEntity<TravelPlanResponse> readTravelPlan(
TravelPlanResponse data = travelPlanService.readTravelPlan(id, memberAuth);
return ResponseEntity.ok(data);
}

@Operation(summary = "공유된 여행 계획 상세 조회")
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "여행 계획 상세 조회가 정상적으로 성공했을 때"
),
@ApiResponse(
responseCode = "400",
description = "존재하지 않은 여행 계획을 조회할 때",
content = @Content(schema = @Schema(implementation = ExceptionResponse.class))
),
})
@GetMapping("shared/{shareKey}")
public ResponseEntity<TravelPlanResponse> readSharedTravelPlan(
@Parameter(description = "여행 계획 공유 키") @PathVariable UUID shareKey
) {
TravelPlanResponse data = travelPlanService.readTravelPlan(shareKey);
return ResponseEntity.ok(data);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.time.LocalDate;
import java.util.UUID;
import kr.touroot.global.entity.BaseEntity;
import kr.touroot.global.exception.BadRequestException;
import kr.touroot.member.domain.Member;
Expand All @@ -23,6 +24,7 @@ public class TravelPlan extends BaseEntity {

private static final int TITLE_MIN_LENGTH = 1;
private static final int TITLE_MAX_LENGTH = 20;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Expand All @@ -33,20 +35,24 @@ public class TravelPlan extends BaseEntity {
@Column(nullable = false)
private LocalDate startDate;

@Column(nullable = false)
private UUID shareKey;

@JoinColumn(name = "author_id", nullable = false)
@ManyToOne(fetch = FetchType.LAZY)
private Member author;

public TravelPlan(Long id, String title, LocalDate startDate, Member author) {
public TravelPlan(Long id, String title, LocalDate startDate, UUID shareKey, Member author) {
validate(title, startDate, author);
this.id = id;
this.title = title;
this.startDate = startDate;
this.shareKey = shareKey;
this.author = author;
}

public TravelPlan(String title, LocalDate startDate, Member author) {
this(null, title, startDate, author);
public TravelPlan(String title, LocalDate startDate, UUID shareKey, Member author) {
this(null, title, startDate, shareKey, author);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import jakarta.validation.constraints.Size;
import java.time.LocalDate;
import java.util.List;

import java.util.UUID;
import kr.touroot.member.domain.Member;
import kr.touroot.travelplan.domain.TravelPlan;
import lombok.Builder;
Expand All @@ -27,7 +27,7 @@ public record TravelPlanCreateRequest(
List<PlanDayCreateRequest> days
) {

public TravelPlan toTravelPlan(Member author) {
return new TravelPlan(title, startDate, author);
public TravelPlan toTravelPlan(Member author, UUID shareKey) {
return new TravelPlan(title, startDate, shareKey, author);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import io.swagger.v3.oas.annotations.media.Schema;

public record TravelPlanCreateResponse(
@Schema(description = "생성된 여행 계획 id")
@Schema(description = "생성된 여행 계획 id", example = "1")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추가 감사합니다 👍 👍

Long id
) {
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package kr.touroot.travelplan.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import kr.touroot.place.domain.Place;
import kr.touroot.travelplan.domain.TravelPlanPlace;
import lombok.Builder;

@Builder
public record TravelPlanPlaceResponse(
@Schema(description = "여행 장소 이름") String placeName,
@Schema(description = "여행 장소 이름", example = "잠실한강공원") String placeName,
@Schema(description = "여행 장소 위치") TravelPlanPositionResponse position,
@Schema(description = "여행 장소 설명") String description
@Schema(description = "여행 장소 설명", example = "신나는 여행 장소") String description
) {

public static TravelPlanPlaceResponse from(TravelPlanPlace planPlace) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

@Builder
public record TravelPlanPositionResponse(
@Schema(description = "여행 장소 위도") String lat,
@Schema(description = "여행 계획 경도") String lng
@Schema(description = "여행 장소 위도", example = "37.5175896") String lat,
@Schema(description = "여행 계획 경도", example = "127.0867236") String lng
) {

public static TravelPlanPositionResponse from(Place place) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
import kr.touroot.travelplan.domain.TravelPlan;
import lombok.Builder;

@Builder
public record TravelPlanResponse(
@Schema(description = "여행 계획 id") Long id,
@Schema(description = "여행 계획 제목") String title,
@Schema(description = "여행 시작일") LocalDate startDate,
@Schema(description = "여행 계획 날짜별 정보") List<TravelPlanDayResponse> days
@Schema(description = "여행 계획 id", example = "1") Long id,
@Schema(description = "여행 계획 제목", example = "신나는 잠실 한강 여행") String title,
@Schema(description = "여행 시작일", example = "2024-11-16") LocalDate startDate,
@Schema(description = "여행 계획 날짜별 정보") List<TravelPlanDayResponse> days,
@Schema(description = "여행 계획 공유 share Key") UUID shareKey
) {

public static TravelPlanResponse of(TravelPlan travelPlan, List<TravelPlanDayResponse> days) {
Expand All @@ -20,6 +22,7 @@ public static TravelPlanResponse of(TravelPlan travelPlan, List<TravelPlanDayRes
.title(travelPlan.getTitle())
.startDate(travelPlan.getStartDate())
.days(days)
.shareKey(travelPlan.getShareKey())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package kr.touroot.travelplan.repository;

import java.util.Optional;
import java.util.UUID;
import kr.touroot.member.domain.Member;
import kr.touroot.travelplan.domain.TravelPlan;
import org.springframework.data.domain.Page;
Expand All @@ -9,4 +11,6 @@
public interface TravelPlanRepository extends JpaRepository<TravelPlan, Long> {

Page<TravelPlan> findAllByAuthor(Member member, Pageable pageable);

Optional<TravelPlan> findByShareKey(UUID shareKey);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package kr.touroot.travelplan.service;

import java.util.Comparator;
import java.util.List;
import java.util.UUID;
import kr.touroot.global.auth.dto.MemberAuth;
import kr.touroot.global.exception.BadRequestException;
import kr.touroot.global.exception.ForbiddenException;
Expand All @@ -26,9 +29,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.List;

@RequiredArgsConstructor
@Service
public class TravelPlanService {
Expand All @@ -42,7 +42,7 @@ public class TravelPlanService {
@Transactional
public TravelPlanCreateResponse createTravelPlan(TravelPlanCreateRequest request, MemberAuth memberAuth) {
Member author = getMemberByMemberAuth(memberAuth);
TravelPlan travelPlan = request.toTravelPlan(author);
TravelPlan travelPlan = request.toTravelPlan(author, UUID.randomUUID());
validStartDate(travelPlan);

TravelPlan savedTravelPlan = travelPlanRepository.save(travelPlan);
Expand Down Expand Up @@ -95,6 +95,13 @@ public TravelPlanResponse readTravelPlan(Long planId, MemberAuth memberAuth) {
return TravelPlanResponse.of(travelPlan, getTravelPlanDayResponses(travelPlan));
}

@Transactional(readOnly = true)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다형성 활용 굿~ 👍

public TravelPlanResponse readTravelPlan(UUID shareKey) {
TravelPlan travelPlan = getTravelPlanByShareKey(shareKey);

return TravelPlanResponse.of(travelPlan, getTravelPlanDayResponses(travelPlan));
}

private void validateAuthor(TravelPlan travelPlan, Member member) {
if (!travelPlan.isAuthor(member)) {
throw new ForbiddenException("여행 계획은 작성자만 조회할 수 있습니다.");
Expand All @@ -106,6 +113,11 @@ private TravelPlan getTravelPlanById(Long planId) {
.orElseThrow(() -> new BadRequestException("존재하지 않는 여행 계획입니다."));
}

private TravelPlan getTravelPlanByShareKey(UUID shareKey) {
return travelPlanRepository.findByShareKey(shareKey)
.orElseThrow(() -> new BadRequestException("존재하지 않는 여행 계획입니다."));
}

private List<TravelPlanDayResponse> getTravelPlanDayResponses(TravelPlan travelPlan) {
List<TravelPlanDay> planDays = travelPlanDayRepository.findByPlan(travelPlan);

Expand Down
Loading
Loading