diff --git a/doorip-api/src/main/java/org/doorip/common/Constants.java b/doorip-api/src/main/java/org/doorip/common/Constants.java index 3123a06..59e6e74 100644 --- a/doorip-api/src/main/java/org/doorip/common/Constants.java +++ b/doorip-api/src/main/java/org/doorip/common/Constants.java @@ -17,4 +17,5 @@ public abstract class Constants { public static final int MAX_STYLE_RATE = 100; public static final int PROPENSITY_WEIGHT = 25; public static final int MAX_PARTICIPANT_COUNT = 6; + public static final int MIN_PARTICIPANT_COUNT = 1; } diff --git a/doorip-api/src/main/java/org/doorip/trip/api/TripApiController.java b/doorip-api/src/main/java/org/doorip/trip/api/TripApiController.java index d748301..3be0d49 100644 --- a/doorip-api/src/main/java/org/doorip/trip/api/TripApiController.java +++ b/doorip-api/src/main/java/org/doorip/trip/api/TripApiController.java @@ -2,8 +2,8 @@ import lombok.RequiredArgsConstructor; import org.doorip.auth.UserId; -import org.doorip.common.BaseResponse; import org.doorip.common.ApiResponseUtil; +import org.doorip.common.BaseResponse; import org.doorip.message.SuccessMessage; import org.doorip.trip.dto.request.TripCreateRequest; import org.doorip.trip.dto.request.TripEntryRequest; @@ -79,10 +79,17 @@ public ResponseEntity> getParticipants(@UserId final Long userId return ApiResponseUtil.success(SuccessMessage.OK, response); } + @PatchMapping("/{tripId}") + public ResponseEntity> leaveTrip(@UserId final Long userId, + @PathVariable final Long tripId) { + tripDetailService.leaveTrip(userId, tripId); + return ApiResponseUtil.success(SuccessMessage.OK); + } + @PatchMapping("/{tripId}") public ResponseEntity> updateTrip(@PathVariable final Long tripId, - @UserId final Long userId, - @RequestBody final TripUpdateRequest request) { + @UserId final Long userId, + @RequestBody final TripUpdateRequest request) { tripService.updateTrip(userId, tripId, request); return ApiResponseUtil.success(SuccessMessage.OK); } diff --git a/doorip-api/src/main/java/org/doorip/trip/service/TodoService.java b/doorip-api/src/main/java/org/doorip/trip/service/TodoService.java index 0a320ae..ce6d4fa 100644 --- a/doorip-api/src/main/java/org/doorip/trip/service/TodoService.java +++ b/doorip-api/src/main/java/org/doorip/trip/service/TodoService.java @@ -118,18 +118,18 @@ private Participant getParticipant(Long participantId) { private List getOurTodosAccordingToProgress(Long tripId, String progress) { if (progress.equals(Constants.INCOMPLETE)) { - return todoRepository.findOurTodoByTripId(tripId, Secret.OUR, Progress.INCOMPLETE); + return todoRepository.findOurTodoByTripIdAndSecretAndProgress(tripId, Secret.OUR, Progress.INCOMPLETE); } else if (progress.equals(Constants.COMPLETE)) { - return todoRepository.findOurTodoByTripId(tripId, Secret.OUR, Progress.COMPLETE); + return todoRepository.findOurTodoByTripIdAndSecretAndProgress(tripId, Secret.OUR, Progress.COMPLETE); } throw new InvalidValueException(ErrorMessage.INVALID_REQUEST_PARAMETER_VALUE); } private List getMyTodosAccordingToProgress(Long userId, Long tripId, String progress) { if (progress.equals(Constants.INCOMPLETE)) { - return todoRepository.findMyTodoByTripId(tripId, userId, Progress.INCOMPLETE); + return todoRepository.findMyTodoByTripIdAndUserIdAndProgress(tripId, userId, Progress.INCOMPLETE); } else if (progress.equals(Constants.COMPLETE)) { - return todoRepository.findMyTodoByTripId(tripId, userId, Progress.COMPLETE); + return todoRepository.findMyTodoByTripIdAndUserIdAndProgress(tripId, userId, Progress.COMPLETE); } throw new InvalidValueException(ErrorMessage.INVALID_REQUEST_PARAMETER_VALUE); } diff --git a/doorip-api/src/main/java/org/doorip/trip/service/TripDetailService.java b/doorip-api/src/main/java/org/doorip/trip/service/TripDetailService.java index 141f86f..bd0ea67 100644 --- a/doorip-api/src/main/java/org/doorip/trip/service/TripDetailService.java +++ b/doorip-api/src/main/java/org/doorip/trip/service/TripDetailService.java @@ -1,19 +1,19 @@ package org.doorip.trip.service; import lombok.RequiredArgsConstructor; +import org.doorip.common.Constants; import org.doorip.exception.EntityNotFoundException; import org.doorip.message.ErrorMessage; -import org.doorip.trip.domain.Participant; -import org.doorip.trip.domain.Progress; -import org.doorip.trip.domain.Secret; -import org.doorip.trip.domain.Trip; +import org.doorip.trip.domain.*; import org.doorip.trip.dto.response.MyTodoResponse; import org.doorip.trip.dto.response.OurTodoResponse; import org.doorip.trip.dto.response.TripParticipantGetResponse; import org.doorip.trip.dto.response.TripStyleResponse; +import org.doorip.trip.repository.ParticipantRepository; import org.doorip.trip.repository.TodoRepository; import org.doorip.trip.repository.TripRepository; import org.doorip.user.domain.User; +import org.doorip.user.repository.UserRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -28,8 +28,10 @@ @Transactional(readOnly = true) @Service public class TripDetailService { + private final UserRepository userRepository; private final TripRepository tripRepository; private final TodoRepository todoRepository; + private final ParticipantRepository participantRepository; public MyTodoResponse getMyTodoDetail(Long userId, Long tripId) { Trip findTrip = getTrip(tripId); @@ -58,6 +60,18 @@ public TripParticipantGetResponse getParticipants(Long userId, Long tripId) { return TripParticipantGetResponse.of(participants, response); } + @Transactional + public void leaveTrip(Long userId, Long tripId) { + User findUser = getUser(userId); + Trip findTrip = getTrip(tripId); + int size = calculateParticipantsCount(findTrip); + Participant findParticipant = getParticipant(findUser, findTrip); + List todos = todoRepository.findMyTodoByTripIdAndUserIdAndSecret(tripId, userId, Secret.MY); + todoRepository.deleteAll(todos); + participantRepository.delete(findParticipant); + deleteTripIfLastParticipant(size, findTrip); + } + private Map createDefaultPropensity() { return new HashMap<>(Map.of(STYLE_A, MIN_STYLE_RATE, STYLE_B, MIN_STYLE_RATE, STYLE_C, MIN_STYLE_RATE, STYLE_D, MIN_STYLE_RATE, STYLE_E, MIN_STYLE_RATE)) { @@ -105,6 +119,26 @@ private List calculateAndGetPropensityAverageRates(List new EntityNotFoundException(ErrorMessage.USER_NOT_FOUND)); + } + + private int calculateParticipantsCount(Trip findTrip) { + return findTrip.getParticipants().size(); + } + + private Participant getParticipant(User findUser, Trip findTrip) { + return participantRepository.findByUserAndTrip(findUser, findTrip) + .orElseThrow(() -> new EntityNotFoundException(ErrorMessage.PARTICIPANT_NOT_FOUND)); + } + + private void deleteTripIfLastParticipant(int size, Trip trip) { + if (size == Constants.MIN_PARTICIPANT_COUNT) { + tripRepository.delete(trip); + } + } + private Trip getTrip(Long tripId) { return tripRepository.findById(tripId) .orElseThrow(() -> new EntityNotFoundException(ErrorMessage.TRIP_NOT_FOUND)); diff --git a/doorip-domain/src/main/java/org/doorip/trip/repository/ParticipantRepository.java b/doorip-domain/src/main/java/org/doorip/trip/repository/ParticipantRepository.java index 98df310..b6b857a 100644 --- a/doorip-domain/src/main/java/org/doorip/trip/repository/ParticipantRepository.java +++ b/doorip-domain/src/main/java/org/doorip/trip/repository/ParticipantRepository.java @@ -5,6 +5,10 @@ import org.doorip.user.domain.User; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface ParticipantRepository extends JpaRepository { boolean existsByUserAndTrip(User user, Trip trip); + + Optional findByUserAndTrip(User user, Trip trip); } diff --git a/doorip-domain/src/main/java/org/doorip/trip/repository/TodoRepository.java b/doorip-domain/src/main/java/org/doorip/trip/repository/TodoRepository.java index 8d55f8d..dc16927 100644 --- a/doorip-domain/src/main/java/org/doorip/trip/repository/TodoRepository.java +++ b/doorip-domain/src/main/java/org/doorip/trip/repository/TodoRepository.java @@ -19,7 +19,20 @@ public interface TodoRepository extends JpaRepository { "and d.progress = :progress " + "and d.secret = :secret " + "order by d.endDate") - List findOurTodoByTripId(@Param("tripId") Long tripId, @Param("secret") Secret secret, @Param("progress") Progress progress); + List findOurTodoByTripIdAndSecretAndProgress(@Param("tripId") Long tripId, @Param("secret") Secret secret, @Param("progress") Progress progress); + + @Query("select d " + + "from Todo d " + + "join Trip i " + + "on d.trip = i " + + "join Participant p " + + "on p.trip = i " + + "join User u " + + "on p.user = u " + + "where i.id = :tripId " + + "and u.id = :userId " + + "and d.secret = :secret") + List findMyTodoByTripIdAndUserIdAndSecret(@Param("tripId") Long tripId, @Param("userId") Long userId, @Param("secret") Secret secret); @Query("select d " + "from Todo d " + @@ -35,7 +48,7 @@ public interface TodoRepository extends JpaRepository { "and u.id = :userId " + "and d.progress = :progress " + "order by d.endDate") - List findMyTodoByTripId(@Param("tripId") Long tripId, @Param("userId") Long userId, @Param("progress") Progress progress); + List findMyTodoByTripIdAndUserIdAndProgress(@Param("tripId") Long tripId, @Param("userId") Long userId, @Param("progress") Progress progress); int countTodoByTripIdAndSecretAndProgress(Long tripId, Secret secret, Progress progress);