diff --git a/src/main/java/org/pingle/pingleserver/controller/PinController.java b/src/main/java/org/pingle/pingleserver/controller/PinController.java index df2a34f..c44cd96 100644 --- a/src/main/java/org/pingle/pingleserver/controller/PinController.java +++ b/src/main/java/org/pingle/pingleserver/controller/PinController.java @@ -8,6 +8,7 @@ import org.pingle.pingleserver.dto.common.ApiResponse; import org.pingle.pingleserver.dto.reponse.MeetingResponse; import org.pingle.pingleserver.dto.reponse.PinResponse; +import org.pingle.pingleserver.dto.response.RankingResponse; import org.pingle.pingleserver.dto.type.SuccessMessage; import org.pingle.pingleserver.service.PinService; import org.springframework.web.bind.annotation.*; @@ -34,4 +35,10 @@ public ApiResponse> getMeetings(@UserId Long userId, @Nullable @RequestParam MCategory category) { return ApiResponse.success(SuccessMessage.OK, pinService.getMeetings(pinId, userId, category)); } + + @GetMapping("/ranking") + public ApiResponse getRankings(@PathVariable Long teamId) { + return ApiResponse.success(SuccessMessage.OK, pinService.getRankings(teamId)); + + } } diff --git a/src/main/java/org/pingle/pingleserver/dto/response/RankingIndividualResponse.java b/src/main/java/org/pingle/pingleserver/dto/response/RankingIndividualResponse.java new file mode 100644 index 0000000..2743a2f --- /dev/null +++ b/src/main/java/org/pingle/pingleserver/dto/response/RankingIndividualResponse.java @@ -0,0 +1,6 @@ +package org.pingle.pingleserver.dto.response; + +import java.time.LocalDateTime; + +public record RankingIndividualResponse (String name, LocalDateTime latestVisitedDate, Long locationCount) { +} diff --git a/src/main/java/org/pingle/pingleserver/dto/response/RankingResponse.java b/src/main/java/org/pingle/pingleserver/dto/response/RankingResponse.java new file mode 100644 index 0000000..d0ec303 --- /dev/null +++ b/src/main/java/org/pingle/pingleserver/dto/response/RankingResponse.java @@ -0,0 +1,17 @@ +package org.pingle.pingleserver.dto.response; + +import java.util.List; + +public record RankingResponse (int meetingCount, List locations) { + public static RankingResponse of (List responses) { + return new RankingResponse(getSumOfMeetings(responses), responses); + } + + private static int getSumOfMeetings (List responses) { + int sum = 0; + for (RankingIndividualResponse response : responses) { + sum += response.locationCount(); + } + return sum; + } +} diff --git a/src/main/java/org/pingle/pingleserver/repository/PinRepository.java b/src/main/java/org/pingle/pingleserver/repository/PinRepository.java index 068e914..6f16148 100644 --- a/src/main/java/org/pingle/pingleserver/repository/PinRepository.java +++ b/src/main/java/org/pingle/pingleserver/repository/PinRepository.java @@ -4,6 +4,7 @@ import org.pingle.pingleserver.domain.Team; import org.pingle.pingleserver.domain.Point; import org.pingle.pingleserver.domain.enums.MCategory; +import org.pingle.pingleserver.dto.response.RankingIndividualResponse; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -17,6 +18,12 @@ public interface PinRepository extends JpaRepository { List findPinsWithCategoryAndTimeBefore(Long teamId, MCategory category); @Query("SELECT DISTINCT p FROM Pin p WHERE p.team.id = :teamId AND p.id IN (SELECT m.pin.id FROM Meeting m WHERE m.startAt > CURRENT_TIMESTAMP)") List findPinsAndTimeBefore(Long teamId); + @Query("select new org.pingle.pingleserver.dto.response.RankingIndividualResponse(p.name, max(m.endAt), count(p)) " + + "from Meeting m join m.pin p " + + "WHERE m.endAt < CURRENT_TIMESTAMP AND p.team.id = :teamId " + + "group by p " + + "order by count(p) desc, max(m.endAt) desc") + List findPinsWithMeetingsBeforeCurrentTimestampAndTeamId(Long teamId); // todo: use native query to solve n+1 problem // @Query(value = "SELECT p.*, COUNT(m.id) FROM pin p LEFT JOIN meeting m ON p.id = m.pin_id WHERE p.team_id = :teamId AND m.start_at > CURRENT_TIMESTAMP AND m.category = :category GROUP BY p.id", nativeQuery = true) diff --git a/src/main/java/org/pingle/pingleserver/service/PinService.java b/src/main/java/org/pingle/pingleserver/service/PinService.java index 8f4386a..4d17c83 100644 --- a/src/main/java/org/pingle/pingleserver/service/PinService.java +++ b/src/main/java/org/pingle/pingleserver/service/PinService.java @@ -12,6 +12,8 @@ import org.pingle.pingleserver.domain.Address; import org.pingle.pingleserver.domain.Point; import org.pingle.pingleserver.dto.request.MeetingRequest; +import org.pingle.pingleserver.dto.response.RankingIndividualResponse; +import org.pingle.pingleserver.dto.response.RankingResponse; import org.pingle.pingleserver.dto.type.ErrorMessage; import org.pingle.pingleserver.exception.CustomException; import org.pingle.pingleserver.repository.MeetingRepository; @@ -161,4 +163,10 @@ private boolean isParticipating(Long userId, Meeting meeting) { private boolean isOwner(Long userId, Long meetingId) { return userMeetingRepository.existsByUserIdAndMeetingIdAndMeetingRole(userId, meetingId, MRole.OWNER); } + + public RankingResponse getRankings(Long teamId) { + if(!teamRepository.existsById(teamId)) throw new CustomException(ErrorMessage.RESOURCE_NOT_FOUND); + List response = pinRepository.findPinsWithMeetingsBeforeCurrentTimestampAndTeamId(teamId); + return RankingResponse.of(response); + } }