Skip to content
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
17 changes: 16 additions & 1 deletion src/docs/asciidoc/grooming-test-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,19 @@ include::{snippetsDir}/loadGroomingTests/1/http-response.adoc[]
==== Response Body Fields
include::{snippetsDir}/loadGroomingTests/1/response-fields.adoc[]

---
---

=== **2. 그루밍 테스트 제출**

그루밍 테스트 제출(완료) api 입니다.

==== Request
include::{snippetsDir}/submitGroomingTests/1/http-request.adoc[]

==== 성공 Response
include::{snippetsDir}/submitGroomingTests/1/http-response.adoc[]

==== Response Body Fields
include::{snippetsDir}/submitGroomingTests/1/response-fields.adoc[]

---
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.ftm.server.adapter.in.web.grooming.controller;

import com.ftm.server.adapter.in.web.grooming.dto.request.GroomingTestSubmissionRequest;
import com.ftm.server.adapter.in.web.grooming.dto.response.GroomingTestResultResponse;
import com.ftm.server.adapter.in.web.grooming.mapper.GroomingTestCommandMapper;
import com.ftm.server.application.port.in.grooming.SubmitGroomingTestUseCase;
import com.ftm.server.application.vo.grooming.GroomingTestResultVo;
import com.ftm.server.common.response.ApiResponse;
import com.ftm.server.common.response.enums.SuccessResponseCode;
import com.ftm.server.infrastructure.security.UserPrincipal;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class SubmitGroomingTestController {

private final SubmitGroomingTestUseCase submitGroomingTestUseCase;

@PostMapping("/api/grooming/tests/submission")
public ResponseEntity<ApiResponse<GroomingTestResultResponse>> completeGroomingTests(
@RequestBody GroomingTestSubmissionRequest request,
@AuthenticationPrincipal UserPrincipal userPrincipal) {
GroomingTestResultVo results =
submitGroomingTestUseCase.execute(
GroomingTestCommandMapper.toSubmitGroomingTestCommand(
userPrincipal, request));

return ResponseEntity.status(HttpStatus.OK)
.body(
ApiResponse.success(
SuccessResponseCode.OK, GroomingTestResultResponse.from(results)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.ftm.server.adapter.in.web.grooming.dto.request;

import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public class GroomingTestSubmissionRequest {

private List<SubmittedQuestion> submissions;

@Getter
@AllArgsConstructor
public static class SubmittedQuestion {

private Long questionId;
private String groomingCategory;
private List<SelectedAnswer> answers;

@Getter
@AllArgsConstructor
public static class SelectedAnswer {
private Long answerId;
private Integer score;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.ftm.server.adapter.in.web.grooming.dto.response;

import com.ftm.server.application.vo.grooming.GroomingLevelVo;
import com.ftm.server.application.vo.grooming.GroomingTestResultGradesVo;
import com.ftm.server.application.vo.grooming.GroomingTestResultScoresVo;
import com.ftm.server.application.vo.grooming.GroomingTestResultVo;
import lombok.Getter;

@Getter
public class GroomingTestResultResponse {

private final GroomingTestResultScoresVo scores;
private final GroomingTestResultGradesVo grades;
private final GroomingLevelVo level;

private GroomingTestResultResponse(GroomingTestResultVo result) {
this.scores = result.getScores();
this.grades = result.getGrades();
this.level = result.getLevel();
}

public static GroomingTestResultResponse from(GroomingTestResultVo result) {
return new GroomingTestResultResponse(result);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.ftm.server.adapter.in.web.grooming.mapper;

import com.ftm.server.adapter.in.web.grooming.dto.request.GroomingTestSubmissionRequest;
import com.ftm.server.application.command.grooming.SubmitGroomingTestCommand;
import com.ftm.server.infrastructure.security.UserPrincipal;
import java.util.List;

public class GroomingTestCommandMapper {

public static SubmitGroomingTestCommand toSubmitGroomingTestCommand(
UserPrincipal userPrincipal, GroomingTestSubmissionRequest request) {
Long userId = (userPrincipal != null) ? userPrincipal.getId() : null;
List<SubmitGroomingTestCommand.SubmittedQuestion> submissions =
request.getSubmissions().stream()
.map(
item ->
SubmitGroomingTestCommand.SubmittedQuestion.of(
item.getQuestionId(),
item.getGroomingCategory(),
item.getAnswers().stream()
.map(
answer ->
SubmitGroomingTestCommand
.SubmittedQuestion
.SelectedAnswer.of(
answer
.getAnswerId(),
answer.getScore()))
.toList()))
.toList();

return SubmitGroomingTestCommand.from(userId, submissions);
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package com.ftm.server.adapter.out.persistence.adapter.grooming;

import com.ftm.server.adapter.out.persistence.mapper.GroomingTestAnswerMapper;
import com.ftm.server.adapter.out.persistence.mapper.GroomingTestQuestionMapper;
import com.ftm.server.adapter.out.persistence.model.GroomingTestAnswerJpaEntity;
import com.ftm.server.adapter.out.persistence.model.GroomingTestQuestionJpaEntity;
import com.ftm.server.adapter.out.persistence.repository.GroomingTestAnswerRepository;
import com.ftm.server.adapter.out.persistence.repository.GroomingTestQuestionRepository;
import com.ftm.server.application.port.out.persistence.grooming.LoadGroomingTestAnswerPort;
import com.ftm.server.application.port.out.persistence.grooming.LoadGroomingTestQuestionPort;
import com.ftm.server.adapter.out.persistence.mapper.*;
import com.ftm.server.adapter.out.persistence.model.*;
import com.ftm.server.adapter.out.persistence.repository.*;
import com.ftm.server.application.port.out.persistence.grooming.*;
import com.ftm.server.application.query.FIndGroomingLevelByScoreQuery;
import com.ftm.server.application.query.FindByIdQuery;
import com.ftm.server.common.annotation.Adapter;
import com.ftm.server.domain.entity.GroomingTestAnswer;
import com.ftm.server.domain.entity.GroomingTestQuestion;
import com.ftm.server.common.exception.CustomException;
import com.ftm.server.common.response.enums.ErrorResponseCode;
import com.ftm.server.domain.entity.*;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -20,15 +20,26 @@
@RequiredArgsConstructor
@Slf4j
public class GroomingDomainPersistenceAdapter
implements LoadGroomingTestQuestionPort, LoadGroomingTestAnswerPort {
implements LoadGroomingTestQuestionPort,
LoadGroomingTestAnswerPort,
LoadUserForGroomingPort,
SaveGroomingTestResultPort,
LoadGroomingLevelPort,
UpdateUserForGroomingPort {

// Repository
private final GroomingTestQuestionRepository groomingTestQuestionRepository;
private final GroomingTestAnswerRepository groomingTestAnswerRepository;
private final GroomingLevelRepository groomingLevelRepository;
private final GroomingTestResultRepository groomingTestResultRepository;
private final UserRepository userRepository;

// Mapper
private final GroomingTestQuestionMapper groomingTestQuestionMapper;
private final GroomingTestAnswerMapper groomingTestAnswerMapper;
private final GroomingLevelMapper groomingLevelMapper;
private final GroomingTestResultMapper groomingTestResultMapper;
private final UserMapper userMapper;

@Override
public List<GroomingTestQuestion> loadGroomingTestQuestions() {
Expand All @@ -45,4 +56,61 @@ public List<GroomingTestAnswer> loadGroomingTestAnswers() {
.map(groomingTestAnswerMapper::toDomain)
.collect(Collectors.toList());
}

@Override
public Optional<User> loadUser(FindByIdQuery query) {
return userRepository.findById(query.getId()).map(userMapper::toDomainEntity);
}

@Override
public void saveGroomingTestResults(List<GroomingTestResult> results) {
List<GroomingTestResultJpaEntity> entities =
results.stream()
.map(
result -> {
UserJpaEntity user =
userRepository.getReferenceById(result.getUserId());
GroomingTestQuestionJpaEntity question =
groomingTestQuestionRepository.getReferenceById(
result.getGroomingTestQuestionId());
GroomingTestAnswerJpaEntity answer =
groomingTestAnswerRepository.getReferenceById(
result.getGroomingTestAnswerId());

return groomingTestResultMapper.toJpaEntity(
user, question, answer, result);
})
.toList();

groomingTestResultRepository.saveAll(entities);
}

@Override
public Optional<GroomingLevel> loadGroomingLevelByScore(FIndGroomingLevelByScoreQuery query) {
return groomingLevelRepository
.findByScoreInRange(query.getScore())
.map(groomingLevelMapper::toDomainEntity);
}

@Override
public void updateUserGroomingStatus(User user) {
UserJpaEntity userJpaEntity =
userRepository
.findById(user.getId())
.orElseThrow(() -> CustomException.USER_NOT_FOUND);

// 유저 점수 업데이트
userJpaEntity.updateGroomingScore(user);

GroomingLevelJpaEntity groomingLevelJpaEntity =
groomingLevelRepository
.findById(user.getGroomingLevelId())
.orElseThrow(
() ->
new CustomException(
ErrorResponseCode.GROOMING_LEVEL_NOT_FOUND));

// 유저 그루밍 레벨 업데이트
userJpaEntity.updateGroomingLevel(groomingLevelJpaEntity);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,20 @@ public GroomingTestResult toDomainEntity(GroomingTestResultJpaEntity jpaEntity)
jpaEntity.getUser().getId(),
jpaEntity.getGroomingTestQuestion().getId(),
jpaEntity.getGroomingTestAnswer().getId(),
jpaEntity.getTestedAt(),
jpaEntity.getCreatedAt(),
jpaEntity.getUpdatedAt());
}

public GroomingTestResultJpaEntity toJpaEntity(
UserJpaEntity userJpaEntity,
GroomingTestQuestionJpaEntity groomingTestQuestionJpaEntity,
GroomingTestAnswerJpaEntity groomingTestAnswerJpaEntity) {
GroomingTestAnswerJpaEntity groomingTestAnswerJpaEntity,
GroomingTestResult domainEntity) {
return GroomingTestResultJpaEntity.from(
userJpaEntity, groomingTestQuestionJpaEntity, groomingTestAnswerJpaEntity);
userJpaEntity,
groomingTestQuestionJpaEntity,
groomingTestAnswerJpaEntity,
domainEntity);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.ftm.server.adapter.out.persistence.model;

import com.ftm.server.domain.entity.GroomingTestResult;
import jakarta.persistence.*;
import java.time.LocalDateTime;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
Expand Down Expand Up @@ -28,24 +30,30 @@ public class GroomingTestResultJpaEntity extends BaseTimeJpaEntity {
@JoinColumn(name = "grooming_test_answer_id")
private GroomingTestAnswerJpaEntity groomingTestAnswer;

private LocalDateTime testedAt;

@Builder(access = AccessLevel.PRIVATE)
private GroomingTestResultJpaEntity(
UserJpaEntity user,
GroomingTestQuestionJpaEntity groomingTestQuestion,
GroomingTestAnswerJpaEntity groomingTestAnswer) {
GroomingTestAnswerJpaEntity groomingTestAnswer,
LocalDateTime testedAt) {
this.user = user;
this.groomingTestQuestion = groomingTestQuestion;
this.groomingTestAnswer = groomingTestAnswer;
this.testedAt = testedAt;
}

public static GroomingTestResultJpaEntity from(
UserJpaEntity userJpaEntity,
GroomingTestQuestionJpaEntity groomingTestQuestionJpaEntity,
GroomingTestAnswerJpaEntity groomingTestAnswerJpaEntity) {
GroomingTestAnswerJpaEntity groomingTestAnswerJpaEntity,
GroomingTestResult groomingTestResult) {
return GroomingTestResultJpaEntity.builder()
.user(userJpaEntity)
.groomingTestQuestion(groomingTestQuestionJpaEntity)
.groomingTestAnswer(groomingTestAnswerJpaEntity)
.testedAt(groomingTestResult.getTestedAt())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,12 @@ public static UserJpaEntity from(User user, GroomingLevelJpaEntity groomingLevel
.deletedAt(user.getDeletedAt())
.build();
}

public void updateGroomingScore(User user) {
this.groomingScore = user.getGroomingScore();
}

public void updateGroomingLevel(GroomingLevelJpaEntity groomingLevelJpaEntity) {
this.groomingLevel = groomingLevelJpaEntity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.ftm.server.adapter.out.persistence.repository;

import com.ftm.server.adapter.out.persistence.model.GroomingLevelJpaEntity;
import java.util.Optional;

public interface GroomingLevelCustomRepository {

Optional<GroomingLevelJpaEntity> findByScoreInRange(int score);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.ftm.server.adapter.out.persistence.repository;

import static com.ftm.server.adapter.out.persistence.model.QGroomingLevelJpaEntity.groomingLevelJpaEntity;

import com.ftm.server.adapter.out.persistence.model.GroomingLevelJpaEntity;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

@Repository
@RequiredArgsConstructor
public class GroomingLevelCustomRepositoryImpl implements GroomingLevelCustomRepository {

private final JPAQueryFactory queryFactory;

@Override
public Optional<GroomingLevelJpaEntity> findByScoreInRange(int score) {
return Optional.ofNullable(
queryFactory
.selectFrom(groomingLevelJpaEntity)
.where(
groomingLevelJpaEntity.minScore.loe(score),
groomingLevelJpaEntity.maxScore.goe(score))
.fetchOne());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
import com.ftm.server.adapter.out.persistence.model.GroomingLevelJpaEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface GroomingLevelRepository extends JpaRepository<GroomingLevelJpaEntity, Long> {}
public interface GroomingLevelRepository
extends JpaRepository<GroomingLevelJpaEntity, Long>, GroomingLevelCustomRepository {}
Loading