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

[feat/CK-114] 로드맵 리뷰를 조회하는 기능을 구현한다 #74

Merged
merged 9 commits into from
Aug 10, 2023
11 changes: 11 additions & 0 deletions backend/kirikiri/src/docs/asciidoc/roadmap.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,14 @@ operation::roadmap-read-api-test/로드맵의_골룸_목록을_조건에_따라_
=== *8-2* 실패 - 존재하지 않는 로드맵인 경우

operation::roadmap-read-api-test/로드맵의_골룸_목록을_조건에_따라_조회할_때_로드맵이_존재하지_않으면_예외가_발생한다[snippets='http-request,query-parameters,http-response,response-fields']

[[로드맵리뷰조회-API]]
== *9. 로드맵의 리뷰 목록 조회 API*

=== *9-1* 성공

operation::roadmap-read-api-test/로드맵의_리뷰들을_조회한다[snippets='http-request,http-response,path-parameters,query-parameters,response-fields']

=== *9-1* 실패 - 존재하지 않는 로드맵인 경우

operation::roadmap-read-api-test/로드맵_리뷰_조회_시_유효하지_않은_로드맵_아이디일_경우_예외를_반환한다[snippets='http-request,http-response,path-parameters,query-parameters,response-fields']
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import co.kirikiri.common.resolver.MemberIdentifier;
import co.kirikiri.service.RoadmapCreateService;
import co.kirikiri.service.RoadmapReadService;
import co.kirikiri.service.dto.CustomReviewScrollRequest;
import co.kirikiri.service.dto.CustomScrollRequest;
import co.kirikiri.service.dto.roadmap.RoadmapGoalRoomsFilterTypeDto;
import co.kirikiri.service.dto.roadmap.request.RoadmapFilterTypeRequest;
Expand All @@ -15,6 +16,7 @@
import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponse;
import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponse;
import co.kirikiri.service.dto.roadmap.response.RoadmapResponse;
import co.kirikiri.service.dto.roadmap.response.RoadmapReviewResponse;
import jakarta.validation.Valid;
import java.net.URI;
import java.util.List;
Expand Down Expand Up @@ -108,4 +110,14 @@ public ResponseEntity<List<RoadmapGoalRoomResponse>> findGoalRoomsByFilterType(
roadmapId, roadmapGoalRoomsFilterTypeDto, scrollRequest);
return ResponseEntity.ok(responses);
}

@GetMapping("/{roadmapId}/reviews")
public ResponseEntity<List<RoadmapReviewResponse>> findRoadmapReviews(
@PathVariable final Long roadmapId,
@ModelAttribute final CustomReviewScrollRequest reviewScrollRequest
) {
final List<RoadmapReviewResponse> responses = roadmapReadService.findRoadmapReviews(roadmapId,
reviewScrollRequest);
return ResponseEntity.ok(responses);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.time.LocalDateTime;
import java.util.regex.Pattern;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
Expand Down Expand Up @@ -73,4 +74,20 @@ public void updateRoadmap(final Roadmap roadmap) {
public boolean isNotSameRoadmap(final Roadmap roadmap) {
return this.roadmap == null || !this.roadmap.equals(roadmap);
}

public String getContent() {
return content;
}

public Double getRate() {
return rate;
}

public Member getMember() {
return member;
}

public LocalDateTime getCreatedAt() {
return createdAt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package co.kirikiri.persistence.dto;

import co.kirikiri.service.dto.CustomReviewScrollRequest;
import java.time.LocalDateTime;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class RoadmapReviewLastValueDto {

private final LocalDateTime lastCreatedAt;
private final Double lastReviewRate;

public static RoadmapReviewLastValueDto create(final CustomReviewScrollRequest request) {
if (request.lastCreatedAt() == null && request.lastReviewRate() == null) {
return null;
}
if (request.lastReviewRate() == null) {
return new RoadmapReviewLastValueDto(request.lastCreatedAt(), null);
}
return new RoadmapReviewLastValueDto(null, request.lastReviewRate());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package co.kirikiri.persistence.roadmap;

import co.kirikiri.domain.roadmap.Roadmap;
import co.kirikiri.domain.roadmap.RoadmapReview;
import co.kirikiri.persistence.dto.RoadmapReviewLastValueDto;
import java.util.List;

public interface RoadmapReviewQueryRepository {

List<RoadmapReview> findRoadmapReviewWithMemberByRoadmapOrderByLatest(final Roadmap roadmap,
final RoadmapReviewLastValueDto lastValue,
final int pageSize);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package co.kirikiri.persistence.roadmap;

import static co.kirikiri.domain.member.QMember.member;
import static co.kirikiri.domain.roadmap.QRoadmapReview.roadmapReview;

import co.kirikiri.domain.roadmap.Roadmap;
import co.kirikiri.domain.roadmap.RoadmapReview;
import co.kirikiri.persistence.QuerydslRepositorySupporter;
import co.kirikiri.persistence.dto.RoadmapReviewLastValueDto;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.dsl.BooleanExpression;
import java.time.LocalDateTime;
import java.util.List;

public class RoadmapReviewQueryRepositoryImpl extends QuerydslRepositorySupporter implements
RoadmapReviewQueryRepository {

public RoadmapReviewQueryRepositoryImpl() {
super(RoadmapReview.class);
}

@Override
public List<RoadmapReview> findRoadmapReviewWithMemberByRoadmapOrderByLatest(final Roadmap roadmap,
final RoadmapReviewLastValueDto lastValue,
final int pageSize) {
return selectFrom(roadmapReview)
.innerJoin(roadmapReview.member, member)
.fetchJoin()
.where(roadmapCond(roadmap), lessThanLastValue(lastValue))
.limit(pageSize)
.orderBy(orderByCreatedAtDesc())
.fetch();
}

private BooleanExpression roadmapCond(final Roadmap roadmap) {
return roadmapReview.roadmap.eq(roadmap);
}

private BooleanExpression lessThanLastValue(final RoadmapReviewLastValueDto lastValue) {
if (lastValue == null) {
return null;
}
return roadmapReview.createdAt.lt(lastValue.getLastCreatedAt());
}

private OrderSpecifier<LocalDateTime> orderByCreatedAtDesc() {
return roadmapReview.createdAt.desc();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface RoadmapReviewRepository extends JpaRepository<RoadmapReview, Long> {
public interface RoadmapReviewRepository extends JpaRepository<RoadmapReview, Long>, RoadmapReviewQueryRepository {

Optional<RoadmapReview> findByRoadmapAndMember(final Roadmap roadmap, final Member member);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@
import co.kirikiri.domain.roadmap.Roadmap;
import co.kirikiri.domain.roadmap.RoadmapCategory;
import co.kirikiri.domain.roadmap.RoadmapContent;
import co.kirikiri.domain.roadmap.RoadmapReview;
import co.kirikiri.exception.NotFoundException;
import co.kirikiri.persistence.dto.GoalRoomLastValueDto;
import co.kirikiri.persistence.dto.RoadmapFilterType;
import co.kirikiri.persistence.dto.RoadmapLastValueDto;
import co.kirikiri.persistence.dto.RoadmapReviewLastValueDto;
import co.kirikiri.persistence.dto.RoadmapSearchDto;
import co.kirikiri.persistence.goalroom.GoalRoomRepository;
import co.kirikiri.persistence.goalroom.dto.RoadmapGoalRoomsFilterType;
import co.kirikiri.persistence.member.MemberRepository;
import co.kirikiri.persistence.roadmap.RoadmapCategoryRepository;
import co.kirikiri.persistence.roadmap.RoadmapContentRepository;
import co.kirikiri.persistence.roadmap.RoadmapRepository;
import co.kirikiri.persistence.roadmap.RoadmapReviewRepository;
import co.kirikiri.service.dto.CustomReviewScrollRequest;
import co.kirikiri.service.dto.CustomScrollRequest;
import co.kirikiri.service.dto.roadmap.RoadmapGoalRoomsFilterTypeDto;
import co.kirikiri.service.dto.roadmap.request.RoadmapFilterTypeRequest;
Expand All @@ -26,6 +30,7 @@
import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponse;
import co.kirikiri.service.dto.roadmap.response.RoadmapGoalRoomResponse;
import co.kirikiri.service.dto.roadmap.response.RoadmapResponse;
import co.kirikiri.service.dto.roadmap.response.RoadmapReviewResponse;
import co.kirikiri.service.mapper.GoalRoomMapper;
import co.kirikiri.service.mapper.RoadmapMapper;
import java.util.List;
Expand All @@ -41,6 +46,7 @@ public class RoadmapReadService {
private final RoadmapRepository roadmapRepository;
private final RoadmapCategoryRepository roadmapCategoryRepository;
private final RoadmapContentRepository roadmapContentRepository;
private final RoadmapReviewRepository roadmapReviewRepository;
private final GoalRoomRepository goalRoomRepository;
private final MemberRepository memberRepository;

Expand Down Expand Up @@ -121,4 +127,14 @@ public List<RoadmapGoalRoomResponse> findRoadmapGoalRoomsByFilterType(final Long
roadmap, filterType, goalRoomLastValueDto, scrollRequest.size());
return GoalRoomMapper.convertToRoadmapGoalRoomResponses(goalRoomsWithPendingMembers);
}

public List<RoadmapReviewResponse> findRoadmapReviews(final Long roadmapId,
final CustomReviewScrollRequest reviewScrollRequest) {
final Roadmap roadmap = findRoadmapById(roadmapId);
final RoadmapReviewLastValueDto roadmapReviewLastValueDto = RoadmapReviewLastValueDto.create(
reviewScrollRequest);
final List<RoadmapReview> roadmapReviews = roadmapReviewRepository.findRoadmapReviewWithMemberByRoadmapOrderByLatest(
roadmap, roadmapReviewLastValueDto, reviewScrollRequest.size());
return RoadmapMapper.convertToRoadmapReviewResponses(roadmapReviews);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package co.kirikiri.service.dto;

import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import org.springframework.format.annotation.DateTimeFormat;

public record CustomReviewScrollRequest(
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSSSS")
LocalDateTime lastCreatedAt,
Comment on lines +8 to +9
Copy link
Collaborator

Choose a reason for hiding this comment

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

궁금한 게 있는데 요 포맷으로 들어오지 않았을 경우 어떤 예외 메시지가 발생하나요??

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

"message": "Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDateTime'; Failed to convert from type [java.lang.String] to type [java.time.LocalDateTime] for value [2023-08-10 20:41:51.083111]"
요런 메시지가 나오네요

Copy link
Collaborator

Choose a reason for hiding this comment

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

오호... 프론트분들이 요 형식에 맞게 요청을 하셔야겠네요...

Double lastReviewRate,
@NotNull(message = "사이즈를 입력해 주세요.")
Integer size
) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

public record MemberResponse(
long id,
String name
String name,
String imageUrl
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package co.kirikiri.service.dto.roadmap.response;

import co.kirikiri.service.dto.member.response.MemberResponse;
import java.time.LocalDateTime;

public record RoadmapReviewResponse(
Long id,
MemberResponse member,
LocalDateTime createdAt,
String content,
Double rate
) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ private static RoadmapGoalRoomResponse convertToRoadmapGoalRoomResponse(final Go

private static MemberResponse convertToMemberResponse(final GoalRoom goalRoom) {
final Member goalRoomLeader = goalRoom.findGoalRoomLeader();
return new MemberResponse(goalRoomLeader.getId(), goalRoomLeader.getNickname().getValue());
return new MemberResponse(goalRoomLeader.getId(), goalRoomLeader.getNickname().getValue(),
goalRoomLeader.getImage().getServerFilePath());
}

public static List<GoalRoomMemberResponse> convertToGoalRoomMemberResponses(
Expand All @@ -147,7 +148,7 @@ public static List<GoalRoomTodoResponse> convertGoalRoomTodoResponses(final Goal
}

private static GoalRoomTodoResponse convertGoalRoomTodoResponse(final List<Long> checkedTodoIds,
final GoalRoomToDo goalRoomToDo) {
final GoalRoomToDo goalRoomToDo) {
final GoalRoomToDoCheckResponse checkResponse = new GoalRoomToDoCheckResponse(
isCheckedTodo(goalRoomToDo.getId(), checkedTodoIds));
return new GoalRoomTodoResponse(goalRoomToDo.getId(),
Expand All @@ -165,7 +166,8 @@ public static MemberGoalRoomResponse convertToMemberGoalRoomResponse(final GoalR
final List<Long> checkedTodoIds) {
final GoalRoomRoadmapNodesResponse nodeResponses = convertToGoalRoomRoadmapNodesResponse(
goalRoom.getGoalRoomRoadmapNodes());
final List<GoalRoomTodoResponse> todoResponses = convertGoalRoomTodoResponsesLimit(goalRoom.getGoalRoomToDos(), checkedTodoIds);
final List<GoalRoomTodoResponse> todoResponses = convertGoalRoomTodoResponsesLimit(goalRoom.getGoalRoomToDos(),
checkedTodoIds);
final List<CheckFeedResponse> checkFeedResponses = convertToCheckFeedResponses(checkFeeds);

return new MemberGoalRoomResponse(goalRoom.getName().getValue(), goalRoom.getStatus().name(),
Expand Down Expand Up @@ -194,7 +196,7 @@ private static GoalRoomRoadmapNodesResponse convertToGoalRoomRoadmapNodesRespons
}

private static List<GoalRoomTodoResponse> convertGoalRoomTodoResponsesLimit(final GoalRoomToDos goalRoomToDos,
final List<Long> checkedTodoIds) {
final List<Long> checkedTodoIds) {
return goalRoomToDos.getValues()
.stream()
.map(goalRoomToDo -> convertGoalRoomTodoResponse(checkedTodoIds, goalRoomToDo))
Expand Down Expand Up @@ -227,6 +229,6 @@ private static MemberGoalRoomForListResponse convertToMemberGoalRoomForListRespo
goalRoom.getStatus().name(),
goalRoom.getCurrentMemberCount(), goalRoom.getLimitedMemberCount().getValue(),
goalRoom.getCreatedAt(), goalRoom.getStartDate(), goalRoom.getEndDate(),
new MemberResponse(leader.getId(), leader.getNickname().getValue()));
new MemberResponse(leader.getId(), leader.getNickname().getValue(), leader.getImage().getServerFilePath()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import co.kirikiri.domain.roadmap.RoadmapNode;
import co.kirikiri.domain.roadmap.RoadmapNodeImage;
import co.kirikiri.domain.roadmap.RoadmapNodes;
import co.kirikiri.domain.roadmap.RoadmapReview;
import co.kirikiri.domain.roadmap.RoadmapTags;
import co.kirikiri.persistence.dto.RoadmapFilterType;
import co.kirikiri.service.dto.member.response.MemberResponse;
Expand All @@ -25,6 +26,7 @@
import co.kirikiri.service.dto.roadmap.response.RoadmapForListResponse;
import co.kirikiri.service.dto.roadmap.response.RoadmapNodeResponse;
import co.kirikiri.service.dto.roadmap.response.RoadmapResponse;
import co.kirikiri.service.dto.roadmap.response.RoadmapReviewResponse;
import co.kirikiri.service.dto.roadmap.response.RoadmapTagResponse;
import java.util.List;
import lombok.AccessLevel;
Expand Down Expand Up @@ -67,7 +69,8 @@ public static RoadmapResponse convertToRoadmapResponse(final Roadmap roadmap, fi
new RoadmapCategoryResponse(category.getId(), category.getName()),
roadmap.getTitle(),
roadmap.getIntroduction(),
new MemberResponse(creator.getId(), creator.getNickname().getValue()),
new MemberResponse(creator.getId(), creator.getNickname().getValue(),
creator.getImage().getServerFilePath()),
roadmapContentResponse,
roadmap.getDifficulty().name(),
roadmap.getRequiredPeriod(),
Expand Down Expand Up @@ -117,7 +120,8 @@ private static RoadmapForListResponse convertRoadmapResponse(final Roadmap roadm
final RoadmapCategoryResponse categoryResponse = new RoadmapCategoryResponse(category.getId(),
category.getName());
final Member creator = roadmap.getCreator();
final MemberResponse creatorResponse = new MemberResponse(creator.getId(), creator.getNickname().getValue());
final MemberResponse creatorResponse = new MemberResponse(creator.getId(), creator.getNickname().getValue(),
creator.getImage().getServerFilePath());
final List<RoadmapTagResponse> roadmapTagResponses = convertRoadmapTagResponses(roadmap.getTags());

return new RoadmapForListResponse(
Expand Down Expand Up @@ -155,4 +159,19 @@ public static List<MemberRoadmapResponse> convertMemberRoadmapResponses(final Li
})
.toList();
}

public static List<RoadmapReviewResponse> convertToRoadmapReviewResponses(
final List<RoadmapReview> roadmapReviews) {
return roadmapReviews.stream()
.map(RoadmapMapper::convertToRoadmapReviewResponse)
.toList();
}

private static RoadmapReviewResponse convertToRoadmapReviewResponse(final RoadmapReview review) {
final Member member = review.getMember();
return new RoadmapReviewResponse(review.getId(),
new MemberResponse(member.getId(), member.getNickname().getValue(),
member.getImage().getServerFilePath()),
review.getCreatedAt(), review.getContent(), review.getRate());
}
}
2 changes: 1 addition & 1 deletion backend/kirikiri/src/main/resources/properties
Loading