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] - 여행 계획 수정 기능 구현 #341

Merged
merged 7 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import java.util.UUID;
import kr.touroot.global.auth.dto.MemberAuth;
import kr.touroot.global.exception.dto.ExceptionResponse;
import kr.touroot.travelplan.dto.request.PlanCreateRequest;
import kr.touroot.travelplan.dto.request.PlanRequest;
import kr.touroot.travelplan.dto.response.PlanCreateResponse;
import kr.touroot.travelplan.dto.response.PlanResponse;
import kr.touroot.travelplan.service.TravelPlanService;
Expand All @@ -22,6 +22,7 @@
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
Expand Down Expand Up @@ -53,7 +54,7 @@ public class TravelPlanController {
})
@PostMapping
public ResponseEntity<PlanCreateResponse> createTravelPlan(
@Valid @RequestBody PlanCreateRequest request,
@Valid @RequestBody PlanRequest request,
MemberAuth memberAuth
) {
PlanCreateResponse data = travelPlanService.createTravelPlan(request, memberAuth);
Expand Down Expand Up @@ -87,6 +88,32 @@ public ResponseEntity<PlanResponse> readTravelPlan(
return ResponseEntity.ok(data);
}

@Operation(summary = "여행 계획 수정")
@ApiResponses(value = {
@ApiResponse(
responseCode = "204",
description = "요청이 정상적으로 처리되었을 때"
),
@ApiResponse(
responseCode = "400",
description = "요청 Body에 올바르지 않은 값이 전달되었을 때",
content = @Content(schema = @Schema(implementation = ExceptionResponse.class))
),
@ApiResponse(
responseCode = "403",
description = "작성자가 아닌 사용자가 요청했을 때",
content = @Content(schema = @Schema(implementation = ExceptionResponse.class))
)
})
@PutMapping("/{id}")
public ResponseEntity<PlanCreateResponse> updateTravelPlan(
@PathVariable Long id,
@Valid MemberAuth memberAuth,
@Valid @RequestBody PlanRequest request
) {
return ResponseEntity.ok(travelPlanService.updateTravelPlan(id, memberAuth, request));
}

@Operation(summary = "여행 계획 삭제")
@ApiResponses(value = {
@ApiResponse(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ private void validateTitleLength(String title) {
}
}

public void update(String title, LocalDate startDate) {
this.title = title;
this.startDate = startDate;
}

Comment on lines +86 to +90
Copy link

Choose a reason for hiding this comment

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

우선은 이미 작성된 검증들이 호출되어야 하는 시점이라고 생각합니다..!
검증을 우아하게 하는 방법은.. 고민해보아야겠네요 🤔

Copy link
Author

Choose a reason for hiding this comment

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

아까 얘기했던 것처럼 리건형 코드랑 같이 별도의 이슈에서 처리하는 것으로 하겠습니다!

public boolean isStartDateBefore(LocalDate date) {
return startDate.isBefore(date);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
import kr.touroot.travelplan.domain.TravelPlan;
import kr.touroot.travelplan.domain.TravelPlanDay;

public record PlanDayCreateRequest(
public record PlanDayRequest(
@Schema(description = "여행 장소 정보")
@Valid
@Size(min = 1, message = "여행 장소는 한 개 이상이어야 합니다.")
@NotNull(message = "여행 장소 정보는 비어있을 수 없습니다.")
List<PlanPlaceCreateRequest> places
List<PlanPlaceRequest> places
) {

public TravelPlanDay toPlanDay(int order, TravelPlan plan) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
import lombok.Builder;

@Builder
public record PlanPlaceCreateRequest(
public record PlanPlaceRequest(
@Schema(description = "여행 장소 이름", example = "잠실한강공원")
@NotBlank(message = "장소명은 비어있을 수 없습니다.") String placeName,
@Valid
@NotNull(message = "위치는 비어있을 수 없습니다.")
PlanPositionCreateRequest position,
PlanPositionRequest position,
@Valid
@NotNull(message = "TODO 리스트는 필수 입니다.")
List<PlanPlaceTodoRequest> todos
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import kr.touroot.travelplan.domain.TravelPlaceTodo;
import kr.touroot.travelplan.domain.TravelPlanPlace;
Expand All @@ -10,10 +11,13 @@ public record PlanPlaceTodoRequest(
@Schema(description = "여행 장소에서 진행할 TODO", example = "함덕 해수욕장 산책")
@NotBlank(message = "TODO 내용은 비어 있을 수 없습니다")
@Size(min = 1, max = 20, message = "TODO 내용은 1자에서 20자 사이의 길이를 가져야 합니다")
String content
String content,
@Schema(description = "TODO의 체크 여부", example = "true")
@NotNull(message = "TODO의 체크 여부는 비어 있을 수 없습니다.")
Boolean isChecked
) {

public TravelPlaceTodo toUncheckedPlaceTodo(TravelPlanPlace travelPlanPlace, Integer order) {
return new TravelPlaceTodo(travelPlanPlace, content, order, false);
public TravelPlaceTodo toPlaceTodo(TravelPlanPlace travelPlanPlace, Integer order) {
return new TravelPlaceTodo(travelPlanPlace, content, order, isChecked);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

public record PlanPositionCreateRequest(
public record PlanPositionRequest(
@Schema(description = "여행 장소 위도", example = "37.5175896")
@NotNull(message = "위도는 비어있을 수 없습니다.")
String lat,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import lombok.Builder;

@Builder
public record PlanCreateRequest(
public record PlanRequest(
@Schema(description = "여행 계획 제목", example = "신나는 잠실 한강 여행")
@NotBlank(message = "여행 계획 제목은 비어있을 수 없습니다.")
String title,
Expand All @@ -24,7 +24,7 @@ public record PlanCreateRequest(
@Valid
@Size(min = 1, message = "여행 날짜는 하루 이상 있어야 합니다.")
@NotNull(message = "여행 날짜 정보는 비어있을 수 없습니다.")
List<PlanDayCreateRequest> days
List<PlanDayRequest> days
) {

public TravelPlan toTravelPlan(Member author, UUID shareKey) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
import kr.touroot.travelplan.domain.TravelPlan;
import kr.touroot.travelplan.domain.TravelPlanDay;
import kr.touroot.travelplan.domain.TravelPlanPlace;
import kr.touroot.travelplan.dto.request.PlanCreateRequest;
import kr.touroot.travelplan.dto.request.PlanDayCreateRequest;
import kr.touroot.travelplan.dto.request.PlanPlaceCreateRequest;
import kr.touroot.travelplan.dto.request.PlanDayRequest;
import kr.touroot.travelplan.dto.request.PlanPlaceRequest;
import kr.touroot.travelplan.dto.request.PlanPlaceTodoRequest;
import kr.touroot.travelplan.dto.request.PlanRequest;
import kr.touroot.travelplan.dto.response.PlanCreateResponse;
import kr.touroot.travelplan.dto.response.PlanDayResponse;
import kr.touroot.travelplan.dto.response.PlanPlaceResponse;
Expand Down Expand Up @@ -46,18 +46,18 @@ public class TravelPlanService {
private final PlaceTodoRepository placeTodoRepository;

@Transactional
public PlanCreateResponse createTravelPlan(PlanCreateRequest request, MemberAuth memberAuth) {
public PlanCreateResponse createTravelPlan(PlanRequest request, MemberAuth memberAuth) {
Member author = getMemberByMemberAuth(memberAuth);
TravelPlan travelPlan = request.toTravelPlan(author, UUID.randomUUID());
validateTravelPlan(travelPlan);
validateCreateTravelPlan(travelPlan);

TravelPlan savedTravelPlan = travelPlanRepository.save(travelPlan);
createPlanDay(request.days(), savedTravelPlan);

return new PlanCreateResponse(savedTravelPlan.getId());
}

private void validateTravelPlan(TravelPlan travelPlan) {
private void validateCreateTravelPlan(TravelPlan travelPlan) {
if (travelPlan.isStartDateBefore(LocalDate.now())) {
throw new BadRequestException("지난 날짜에 대한 계획은 작성할 수 없습니다.");
}
Expand All @@ -68,17 +68,17 @@ private Member getMemberByMemberAuth(MemberAuth memberAuth) {
.orElseThrow(() -> new BadRequestException("존재하지 않는 사용자입니다."));
}

private void createPlanDay(List<PlanDayCreateRequest> request, TravelPlan savedTravelPlan) {
private void createPlanDay(List<PlanDayRequest> request, TravelPlan savedTravelPlan) {
for (int order = 0; order < request.size(); order++) {
PlanDayCreateRequest dayRequest = request.get(order);
PlanDayRequest dayRequest = request.get(order);
TravelPlanDay travelPlanDay = travelPlanDayRepository.save(dayRequest.toPlanDay(order, savedTravelPlan));
createPlanPlace(dayRequest.places(), travelPlanDay);
}
}

private void createPlanPlace(List<PlanPlaceCreateRequest> request, TravelPlanDay travelPlanDay) {
private void createPlanPlace(List<PlanPlaceRequest> request, TravelPlanDay travelPlanDay) {
for (int order = 0; order < request.size(); order++) {
PlanPlaceCreateRequest planRequest = request.get(order);
PlanPlaceRequest planRequest = request.get(order);
Place place = getPlace(planRequest);
TravelPlanPlace planPlace = planRequest.toPlanPlace(order, travelPlanDay, place);
TravelPlanPlace travelPlanPlace = travelPlanPlaceRepository.save(planPlace);
Expand All @@ -89,12 +89,12 @@ private void createPlanPlace(List<PlanPlaceCreateRequest> request, TravelPlanDay
private void createPlaceTodo(List<PlanPlaceTodoRequest> request, TravelPlanPlace travelPlanPlace) {
for (int order = 0; order < request.size(); order++) {
PlanPlaceTodoRequest todoRequest = request.get(order);
TravelPlaceTodo travelPlaceTodo = todoRequest.toUncheckedPlaceTodo(travelPlanPlace, order);
TravelPlaceTodo travelPlaceTodo = todoRequest.toPlaceTodo(travelPlanPlace, order);
placeTodoRepository.save(travelPlaceTodo);
}
}

private Place getPlace(PlanPlaceCreateRequest planRequest) {
private Place getPlace(PlanPlaceRequest planRequest) {
return placeRepository.findByNameAndLatitudeAndLongitude(
planRequest.placeName(),
planRequest.position().lat(),
Expand Down Expand Up @@ -173,6 +173,35 @@ public int calculateTravelPeriod(TravelPlan travelPlan) {
.size();
}

@Transactional
public PlanCreateResponse updateTravelPlan(Long planId, MemberAuth memberAuth, PlanRequest request) {
TravelPlan travelPlan = getTravelPlanById(planId);
Member author = getMemberByMemberAuth(memberAuth);
validateUpdateByAuthor(travelPlan, author);

clearTravelPlanContents(travelPlan);
updateTravelPlanContents(request, travelPlan);
return new PlanCreateResponse(travelPlan.getId());
}

private void validateUpdateByAuthor(TravelPlan travelPlan, Member member) {
if (!travelPlan.isAuthor(member)) {
throw new ForbiddenException("여행 계획 수정은 작성자만 가능합니다.");
}
}

private void clearTravelPlanContents(TravelPlan travelPlan) {
placeTodoRepository.deleteByTravelPlanPlaceDayPlan(travelPlan);
travelPlanPlaceRepository.deleteByDayPlan(travelPlan);
travelPlanDayRepository.deleteByPlan(travelPlan);
}

private void updateTravelPlanContents(PlanRequest request, TravelPlan travelPlan) {
travelPlan.update(request.title(), request.startDate());
travelPlanRepository.save(travelPlan);
createPlanDay(request.days(), travelPlan);
}

@Transactional
public void deleteByTravelPlanId(Long planId, MemberAuth memberAuth) {
TravelPlan travelPlan = getTravelPlanById(planId);
Expand Down
Loading
Loading