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/1360 로드맵 답변 목록 검색 기능 추가 #1433

Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ public enum BadRequestCode {
FILE_UPLOAD_FAIL_EXCEPTION(9003, "파일 업로드에 실패했습니다."),

DUPLICATE_SESSION_EXCEPTION(10001, "중복되는 세션입니다."),
SESSION_NOT_FOUND_EXCEPTION(10002, "세션을 찾을 수 없습니다."),
TOO_LONG_LEVEL_NAME_EXCEPTION(10003, String.format("세션 이름이 %d자 초과입니다.", Session.MAX_LENGTH)),

SEARCH_ARGUMENT_PARSE_EXCEPTION(11001, "parsing 할 수 없는 argument입니다."),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
package wooteco.prolog.roadmap.application;

import static wooteco.prolog.common.exception.BadRequestCode.CURRICULUM_NOT_FOUND_EXCEPTION;
import static wooteco.prolog.common.exception.BadRequestCode.ESSAY_ANSWER_NOT_FOUND_EXCEPTION;
import static wooteco.prolog.common.exception.BadRequestCode.ROADMAP_QUIZ_NOT_FOUND_EXCEPTION;
import static wooteco.prolog.common.exception.BadRequestCode.ROADMAP_SESSION_NOT_FOUND_EXCEPTION;

import java.util.List;
import java.util.stream.Collectors;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import wooteco.prolog.common.exception.BadRequestException;
import wooteco.prolog.member.application.MemberService;
import wooteco.prolog.member.domain.Member;
import wooteco.prolog.roadmap.application.dto.EssayAnswerRequest;
import wooteco.prolog.roadmap.application.dto.EssayAnswerSearchRequest;
import wooteco.prolog.roadmap.application.dto.EssayAnswerUpdateRequest;
import wooteco.prolog.roadmap.domain.Curriculum;
import wooteco.prolog.roadmap.domain.EssayAnswer;
import wooteco.prolog.roadmap.domain.Quiz;
import wooteco.prolog.roadmap.domain.repository.CurriculumRepository;
import wooteco.prolog.roadmap.domain.repository.EssayAnswerRepository;
import wooteco.prolog.roadmap.domain.repository.EssayAnswerSpecification;
import wooteco.prolog.roadmap.domain.repository.QuizRepository;

import java.util.List;
import wooteco.prolog.session.domain.Session;
import wooteco.prolog.session.domain.repository.SessionRepository;
import wooteco.prolog.studylog.application.dto.EssayAnswersResponse;

@Transactional
@Service
Expand All @@ -26,14 +37,20 @@ public class EssayAnswerService {
private final EssayAnswerRepository essayAnswerRepository;
private final QuizRepository quizRepository;
private final MemberService memberService;

@Autowired
public EssayAnswerService(EssayAnswerRepository essayAnswerRepository,
QuizRepository quizRepository,
MemberService memberService) {
private final CurriculumRepository curriculumRepository;
private final SessionRepository sessionRepository;

public EssayAnswerService(
EssayAnswerRepository essayAnswerRepository,
QuizRepository quizRepository,
MemberService memberService,
CurriculumRepository curriculumRepository,
SessionRepository sessionRepository) {
this.essayAnswerRepository = essayAnswerRepository;
this.quizRepository = quizRepository;
this.memberService = memberService;
this.curriculumRepository = curriculumRepository;
this.sessionRepository = sessionRepository;
}

@Transactional
Expand Down Expand Up @@ -85,4 +102,35 @@ public List<EssayAnswer> findByQuizId(Long quizId) {

return essayAnswers;
}

public EssayAnswersResponse searchEssayAnswers(
final EssayAnswerSearchRequest request,
final Pageable pageable
) {

final Long curriculumId = request.getCurriculumId();

final Curriculum curriculum = curriculumRepository.findById(curriculumId)
.orElseThrow(() -> new BadRequestException(CURRICULUM_NOT_FOUND_EXCEPTION));

final List<Long> sessionIds = sessionRepository.findAllByCurriculumId(curriculum.getId())
.stream()
.map(Session::getId)
.collect(Collectors.toList());

if (sessionIds.isEmpty()) {
throw new BadRequestException(ROADMAP_SESSION_NOT_FOUND_EXCEPTION);
}

final Specification<EssayAnswer> essayAnswerSpecification = EssayAnswerSpecification.equalsSessionIdsIn(
sessionIds)
.and(EssayAnswerSpecification.equalsKeywordId(request.getKeywordId()))
.and(EssayAnswerSpecification.inQuizIds(request.getQuizIds()))
.and(EssayAnswerSpecification.inMemberIds(request.getMemberIds()))
.and(EssayAnswerSpecification.orderByIdDesc());

final Page<EssayAnswer> essayAnswers = essayAnswerRepository.findAll(essayAnswerSpecification,
pageable);
return EssayAnswersResponse.of(essayAnswers);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import java.time.LocalDateTime;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import wooteco.prolog.member.application.dto.MemberResponse;
import wooteco.prolog.roadmap.domain.EssayAnswer;

@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class EssayAnswerResponse {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package wooteco.prolog.roadmap.application.dto;

import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Setter
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class EssayAnswerSearchRequest {

private Long curriculumId;
private Long keywordId;
private List<Long> quizIds;
private List<Long> memberIds;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import wooteco.prolog.roadmap.domain.EssayAnswer;

public interface EssayAnswerRepository extends JpaRepository<EssayAnswer, Long> {
public interface EssayAnswerRepository extends JpaRepository<EssayAnswer, Long>,
JpaSpecificationExecutor<EssayAnswer> {

Optional<EssayAnswer> findByIdAndMemberId(Long id, Long memberId);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package wooteco.prolog.roadmap.domain.repository;

import java.util.List;
import javax.persistence.criteria.JoinType;
import org.springframework.data.jpa.domain.Specification;
import wooteco.prolog.roadmap.domain.EssayAnswer;

public class EssayAnswerSpecification {

private EssayAnswerSpecification() {
}

public static Specification<EssayAnswer> equalsSessionIdsIn(final List<Long> sessionIds) {
return (root, query, builder) -> {
if (sessionIds == null || sessionIds.isEmpty()) {
return builder.and();
}

return root.join("quiz", JoinType.INNER)
.join("keyword", JoinType.INNER)
.get("sessionId").in(sessionIds);
};
}

public static Specification<EssayAnswer> equalsKeywordId(Long keywordId) {
return (root, query, builder) -> {
if (keywordId == null || keywordId == 0L) {
return builder.and();
}

return root.get("quiz").get("keyword").get("id").in(keywordId);
};
}

public static Specification<EssayAnswer> inQuizIds(List<Long> quizIds) {
return (root, query, builder) -> {
if (quizIds == null || quizIds.isEmpty()) {
return builder.and();
}

return root.get("quiz").get("id").in(quizIds);
};
}

public static Specification<EssayAnswer> inMemberIds(List<Long> memberIds) {
return (root, query, builder) -> {
if (memberIds == null || memberIds.isEmpty()) {
return builder.and();
}

return root.join("member", JoinType.LEFT).get("id").in(memberIds);
};
}

public static Specification<EssayAnswer> orderByIdDesc() {
return (root, query, builder) -> {
query.orderBy(builder.desc(root.get("id")));
return null;
};
}

public static Specification<EssayAnswer> distinct(final boolean distinct) {
return (root, query, builder) -> {
query.distinct(distinct);
return null;
};
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
package wooteco.prolog.roadmap.ui;

import static java.util.stream.Collectors.toList;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
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;
import wooteco.prolog.login.domain.AuthMemberPrincipal;
import wooteco.prolog.login.ui.LoginMember;
import wooteco.prolog.roadmap.application.EssayAnswerService;
import wooteco.prolog.roadmap.application.QuizService;
import wooteco.prolog.roadmap.application.dto.EssayAnswerRequest;
import wooteco.prolog.roadmap.application.dto.EssayAnswerResponse;
import wooteco.prolog.roadmap.application.dto.EssayAnswerSearchRequest;
import wooteco.prolog.roadmap.application.dto.EssayAnswerUpdateRequest;
import wooteco.prolog.roadmap.application.dto.QuizResponse;
import wooteco.prolog.roadmap.domain.EssayAnswer;

import java.util.List;

import static java.util.stream.Collectors.toList;
import wooteco.prolog.studylog.application.dto.EssayAnswersResponse;

@RestController
@RequestMapping
Expand All @@ -38,6 +48,13 @@ public ResponseEntity<Long> create(@RequestBody EssayAnswerRequest request,
return ResponseEntity.ok(essayAnswerService.createEssayAnswer(request, member.getId()));
}

@GetMapping("/essay-answers")
public ResponseEntity<EssayAnswersResponse> search(
EssayAnswerSearchRequest request,
@PageableDefault Pageable pageable) {
return ResponseEntity.ok(essayAnswerService.searchEssayAnswers(request, pageable));
}

@GetMapping("/essay-answers/{essayAnswerId}")
public ResponseEntity<EssayAnswerResponse> findById(@PathVariable Long essayAnswerId) {
EssayAnswer essayAnswer = essayAnswerService.getById(essayAnswerId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import static java.util.stream.Collectors.toList;
import static wooteco.prolog.common.exception.BadRequestCode.DUPLICATE_SESSION_EXCEPTION;
import static wooteco.prolog.common.exception.BadRequestCode.SESSION_NOT_FOUND_EXCEPTION;
import static wooteco.prolog.common.exception.BadRequestCode.ROADMAP_SESSION_NOT_FOUND_EXCEPTION;

import java.util.Collection;
import java.util.List;
Expand Down Expand Up @@ -43,7 +43,7 @@ private void validateName(String name) {

public Session findById(Long id) {
return sessionRepository.findById(id)
.orElseThrow(() -> new BadRequestException(SESSION_NOT_FOUND_EXCEPTION));
.orElseThrow(() -> new BadRequestException(ROADMAP_SESSION_NOT_FOUND_EXCEPTION));
}

public Optional<Session> findSessionById(Long id) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package wooteco.prolog.studylog.application.dto;


import static java.util.stream.Collectors.toList;

import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import wooteco.prolog.roadmap.application.dto.EssayAnswerResponse;
import wooteco.prolog.roadmap.domain.EssayAnswer;

@NoArgsConstructor
@AllArgsConstructor
@Getter
public class EssayAnswersResponse {

private static final int ONE_INDEXED_PARAMETER = 1;

private List<EssayAnswerResponse> data;
private Long totalSize;
private int totalPage;
private int currPage;

public static EssayAnswersResponse of(Page<EssayAnswer> page) {
Page<EssayAnswerResponse> responsePage = new PageImpl<>(
toResponses(page.getContent()),
page.getPageable(),
page.getTotalElements()
);

return new EssayAnswersResponse(responsePage.getContent(),
responsePage.getTotalElements(),
responsePage.getTotalPages(),
responsePage.getNumber() + ONE_INDEXED_PARAMETER);
}

private static List<EssayAnswerResponse> toResponses(List<EssayAnswer> essayAnswers) {
return essayAnswers.stream()
.map(EssayAnswerResponse::of)
.collect(toList());
}
}
Loading