diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/controller/DatePreferenceController.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/controller/DatePreferenceController.java new file mode 100644 index 0000000..69f0cdf --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/controller/DatePreferenceController.java @@ -0,0 +1,59 @@ +package org.withtime.be.withtimebe.domain.date.preference.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.namul.api.payload.response.DefaultResponse; +import org.springframework.web.bind.annotation.*; +import org.withtime.be.withtimebe.domain.date.preference.converter.DatePreferenceConverter; +import org.withtime.be.withtimebe.domain.date.preference.dto.DatePreferenceRequestDTO; +import org.withtime.be.withtimebe.domain.date.preference.dto.DatePreferenceResponseDTO; +import org.withtime.be.withtimebe.domain.date.preference.service.command.DatePreferenceTestCommandService; +import org.withtime.be.withtimebe.domain.date.preference.service.query.DatePreferenceDescriptionQueryService; +import org.withtime.be.withtimebe.domain.date.preference.service.query.DatePreferenceQuestionQueryService; +import org.withtime.be.withtimebe.domain.member.entity.Member; +import org.withtime.be.withtimebe.global.security.annotation.AuthenticatedMember; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/dates/preferences") +@Tag(name = "데이트 취향 테스트 API") +public class DatePreferenceController { + + private final DatePreferenceTestCommandService datePreferenceTestCommandService; + private final DatePreferenceDescriptionQueryService datePreferenceDescriptionQueryService; + private final DatePreferenceQuestionQueryService datePreferenceQuestionQueryService; + + @Operation(summary = "데이트 취향 조회 API", description = "데이트 취향 종류 조회") + @ApiResponse(responseCode = "COMMON200", description = "성공적으로 정보를 가져왔습니다.") + @GetMapping + public DefaultResponse findTypes() { + return DefaultResponse.ok(DatePreferenceConverter.toFindTypes(datePreferenceDescriptionQueryService.findTypes())); + } + + @Operation(summary = "데이트 취향 테스트 질문 조회 API", description = "데이트 취향 테스트에 사용되는 질문 조회하는 API") + @ApiResponse(responseCode = "COMMON200", description = "성공적으로 정보를 가져왔습니다.") + @GetMapping("/questions") + public DefaultResponse findQuestions() { + return DefaultResponse.ok(DatePreferenceConverter.toFindQuestions(datePreferenceQuestionQueryService.findQuestions())); + } + + @Operation(summary = "데이트 취향 테스트 API", description = "질문에 대한 답변으로 결과 생성하는 API 1, 2 둘 중 하나로 40개로 채워 배열 형태로 전송") + @ApiResponses({ + @ApiResponse(responseCode = "COMMON200", description = "테스트에 성공했습니다."), + @ApiResponse( + responseCode = "401", + description = """ + 다음과 같은 이유로 실패할 수 있습니다: + - DATE_PREFERENCE400_1: 질문에 대한 형식이 잘못되었습니다. + """ + ), + }) + @PostMapping("/tests") + public DefaultResponse test(@AuthenticatedMember Member member, @RequestBody DatePreferenceRequestDTO.Test request) { + return DefaultResponse.ok(datePreferenceTestCommandService.test(member, request)); + } + +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/converter/DatePreferenceConverter.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/converter/DatePreferenceConverter.java new file mode 100644 index 0000000..27e87e7 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/converter/DatePreferenceConverter.java @@ -0,0 +1,95 @@ +package org.withtime.be.withtimebe.domain.date.preference.converter; + +import org.withtime.be.withtimebe.domain.date.preference.dto.DatePreferenceResponseDTO; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceDescription; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferencePartDescription; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceQuestion; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceTestResult; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferenceType; + +import java.util.List; + +public class DatePreferenceConverter { + public static DatePreferenceResponseDTO.FindTypes toFindTypes(List datePreferenceDescriptions) { + return DatePreferenceResponseDTO.FindTypes.builder() + .types(datePreferenceDescriptions.stream().map(DatePreferenceConverter::toFindType).toList()) + .size(datePreferenceDescriptions.size()) + .build(); + } + + public static DatePreferenceResponseDTO.FindType toFindType(DatePreferenceDescription datePreferenceDescription) { + return DatePreferenceResponseDTO.FindType.builder() + .symbolicAnimal(datePreferenceDescription.getSymbolicAnimal()) + .preferenceType(datePreferenceDescription.getPreferenceType()) + .simpleDescription(datePreferenceDescription.getSimpleDescription()) + .build(); + } + + public static DatePreferenceResponseDTO.FindQuestions toFindQuestions(List datePreferenceQuestions) { + return DatePreferenceResponseDTO.FindQuestions.builder() + .questions(datePreferenceQuestions.stream().map(DatePreferenceConverter::toFindQuestion).toList()) + .size(datePreferenceQuestions.size()) + .build(); + } + + public static DatePreferenceResponseDTO.FindQuestion toFindQuestion(DatePreferenceQuestion datePreferenceQuestion) { + return DatePreferenceResponseDTO.FindQuestion.builder() + .question(datePreferenceQuestion.getQuestion()) + .firstAnswer(datePreferenceQuestion.getFirstAnswer()) + .secondAnswer(datePreferenceQuestion.getSecondAnswer()) + .build(); + } + + public static DatePreferenceResponseDTO.TestResult toTestResult(DatePreferenceTestResult datePreferenceTestResult, + DatePreferenceDescription datePreferenceDescription, + List datePreferencePartDescriptions) { + return DatePreferenceResponseDTO.TestResult.builder() + .preferenceType(datePreferenceTestResult.getPreferenceType()) + .aPercentage(datePreferenceTestResult.getAPercentage()) + .bPercentage(datePreferenceTestResult.getBPercentage()) + .cPercentage(datePreferenceTestResult.getCPercentage()) + .dPercentage(datePreferenceTestResult.getDPercentage()) + .typeDescription(datePreferenceDescription == null ? null : DatePreferenceConverter.toTypeDescription(datePreferenceDescription)) + .partTypeDescriptions(datePreferencePartDescriptions == null || datePreferencePartDescriptions.isEmpty() ? null : DatePreferenceConverter.toPartTypeDescriptions(datePreferencePartDescriptions)) + .build(); + } + + public static DatePreferenceTestResult toDatePreferenceTestResult(PreferenceType preferenceType, + Double aPercentage, + Double bPercentage, + Double cPercentage, + Double dPercentage) { + return DatePreferenceTestResult.builder() + .preferenceType(preferenceType) + .aPercentage(aPercentage) + .bPercentage(bPercentage) + .cPercentage(cPercentage) + .dPercentage(dPercentage) + .build(); + } + + public static DatePreferenceResponseDTO.TypeDescription toTypeDescription(DatePreferenceDescription datePreferenceDescription) { + return DatePreferenceResponseDTO.TypeDescription.builder() + .symbolicAnimal(datePreferenceDescription.getSymbolicAnimal()) + .preferenceType(datePreferenceDescription.getPreferenceType()) + .simpleDescription(datePreferenceDescription.getSimpleDescription()) + .analysis(datePreferenceDescription.getAnalysis()) + .build(); + } + + public static DatePreferenceResponseDTO.PartTypeDescriptions toPartTypeDescriptions(List descriptions) { + return DatePreferenceResponseDTO.PartTypeDescriptions.builder() + .types(descriptions.stream().map(DatePreferenceConverter::toPartTypeDescription).toList()) + .size(descriptions.size()) + .build(); + } + + public static DatePreferenceResponseDTO.PartTypeDescription toPartTypeDescription(DatePreferencePartDescription description) { + return DatePreferenceResponseDTO.PartTypeDescription.builder() + .typeInitial(description.getPreferencePartType()) + .type(description.getType()) + .typeEng(description.getTypeEng()) + .description(description.getDescription()) + .build(); + } +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/dto/DatePreferenceRequestDTO.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/dto/DatePreferenceRequestDTO.java new file mode 100644 index 0000000..fff5b58 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/dto/DatePreferenceRequestDTO.java @@ -0,0 +1,24 @@ +package org.withtime.be.withtimebe.domain.date.preference.dto; + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.util.List; + +public record DatePreferenceRequestDTO() { + public record Test( + @Schema( + description = "1 또는 2 중 하나의 값으로 이루어진 40개의 답변", + example = """ + [ + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 + ] + """ + ) + List answers + ) { + + } +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/dto/DatePreferenceResponseDTO.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/dto/DatePreferenceResponseDTO.java new file mode 100644 index 0000000..ab12ee4 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/dto/DatePreferenceResponseDTO.java @@ -0,0 +1,86 @@ +package org.withtime.be.withtimebe.domain.date.preference.dto; + +import lombok.Builder; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferencePartType; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferenceType; + +import java.util.List; + +public record DatePreferenceResponseDTO() { + + @Builder + public record FindTypes( + List types, + Integer size + ) { + + } + + @Builder + public record FindType( + String symbolicAnimal, + PreferenceType preferenceType, + String simpleDescription + ) { + + } + + @Builder + public record FindQuestions( + List questions, + Integer size + ) { + + } + + @Builder + public record FindQuestion( + String question, + String firstAnswer, + String secondAnswer + ) { + + } + + @Builder + public record TestResult( + PreferenceType preferenceType, + Double aPercentage, + Double bPercentage, + Double cPercentage, + Double dPercentage, + TypeDescription typeDescription, + PartTypeDescriptions partTypeDescriptions + ) { + + } + + @Builder + public record TypeDescription( + String symbolicAnimal, + PreferenceType preferenceType, + String simpleDescription, + String analysis + ) { + + } + + @Builder + public record PartTypeDescriptions( + List types, + Integer size + ) { + + } + + @Builder + public record PartTypeDescription( + PreferencePartType typeInitial, + String typeEng, + String type, + String description + ) { + + } + +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceDescription.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceDescription.java new file mode 100644 index 0000000..a695fba --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceDescription.java @@ -0,0 +1,32 @@ +package org.withtime.be.withtimebe.domain.date.preference.entity; + +import jakarta.persistence.*; +import lombok.*; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferenceType; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Table(name = "date_preference_description") +public class DatePreferenceDescription { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "date_preference_description_id") + private Long id; + + @Column(name = "symbolic_animal") + private String symbolicAnimal; + + @Enumerated(EnumType.STRING) + @Column(name = "preference_type", unique = true) + private PreferenceType preferenceType; + + @Column(name = "simple_description") + private String simpleDescription; + + @Column(name = "analysis", columnDefinition = "TEXT") + private String analysis; +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceDescriptionKeyword.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceDescriptionKeyword.java new file mode 100644 index 0000000..69e5c24 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceDescriptionKeyword.java @@ -0,0 +1,26 @@ +package org.withtime.be.withtimebe.domain.date.preference.entity; + +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Table(name = "date_preference_description_keyword") +public class DatePreferenceDescriptionKeyword { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "date_preference_description_keyword_id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "date_preference_description") + private DatePreferenceDescription datePreferenceDescription; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "date_preference_keyword") + private DatePreferenceKeyword datePreferenceKeyword; +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceKeyword.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceKeyword.java new file mode 100644 index 0000000..9908f9e --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceKeyword.java @@ -0,0 +1,22 @@ +package org.withtime.be.withtimebe.domain.date.preference.entity; + +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Table(name = "date_preference_keyword") +public class DatePreferenceKeyword { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "date_preference_keyword_id") + private Long id; + + @Column(name = "keyword") + private String keyword; + +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferencePartDescription.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferencePartDescription.java new file mode 100644 index 0000000..02d0590 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferencePartDescription.java @@ -0,0 +1,32 @@ +package org.withtime.be.withtimebe.domain.date.preference.entity; + +import jakarta.persistence.*; +import lombok.*; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferencePartType; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Table(name = "date_preference_part_description") +public class DatePreferencePartDescription { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "date_preference_part_description_id") + private Long id; + + @Enumerated(EnumType.STRING) + @Column(name = "preference_part_type", unique = true) + private PreferencePartType preferencePartType; + + @Column(name = "type_eng") + private String typeEng; + + @Column(name = "type") + private String type; + + @Column(name = "description") + private String description; +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceQuestion.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceQuestion.java new file mode 100644 index 0000000..0c7e0be --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceQuestion.java @@ -0,0 +1,27 @@ +package org.withtime.be.withtimebe.domain.date.preference.entity; + +import jakarta.persistence.*; +import lombok.*; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Table(name = "date_preference_question") +public class DatePreferenceQuestion { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "date_preference_question_id") + private Long id; + + @Column(name = "question") + private String question; + + @Column(name = "first_answer") + private String firstAnswer; + + @Column(name = "second_answer") + private String secondAnswer; +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceTestResult.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceTestResult.java new file mode 100644 index 0000000..40e243f --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/DatePreferenceTestResult.java @@ -0,0 +1,46 @@ +package org.withtime.be.withtimebe.domain.date.preference.entity; + +import jakarta.persistence.*; +import lombok.*; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferenceType; +import org.withtime.be.withtimebe.domain.member.entity.Member; +import org.withtime.be.withtimebe.global.common.BaseEntity; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Table(name = "date_preference_test_result") +public class DatePreferenceTestResult extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "date_preference_test_result_id") + private Long id; + + @Enumerated(EnumType.STRING) + @Column(name = "preferencePartType") + private PreferenceType preferenceType; + + @Column(name = "a_percentage") + private Double aPercentage; + + @Column(name = "b_percentage") + private Double bPercentage; + + @Column(name = "c_percentage") + private Double cPercentage; + + @Column(name = "d_percentage") + private Double dPercentage; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + public void mappingMember(Member member) { + this.member = member; + } + +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/enums/PreferencePartType.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/enums/PreferencePartType.java new file mode 100644 index 0000000..d752eaa --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/enums/PreferencePartType.java @@ -0,0 +1,8 @@ +package org.withtime.be.withtimebe.domain.date.preference.entity.enums; + +public enum PreferencePartType { + S,F, + A,C, + M,P, + O,E +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/enums/PreferenceType.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/enums/PreferenceType.java new file mode 100644 index 0000000..50c92dc --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/entity/enums/PreferenceType.java @@ -0,0 +1,20 @@ +package org.withtime.be.withtimebe.domain.date.preference.entity.enums; + +public enum PreferenceType { + SAME, + SAMO, + SAPE, + SAPO, + SCME, + SCMO, + SCPE, + SCPO, + FAME, + FAMO, + FAPE, + FAPO, + FCME, + FCMO, + FCPE, + FCPO +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceDescriptionKeywordRepository.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceDescriptionKeywordRepository.java new file mode 100644 index 0000000..54a4b82 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceDescriptionKeywordRepository.java @@ -0,0 +1,7 @@ +package org.withtime.be.withtimebe.domain.date.preference.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceDescriptionKeyword; + +public interface DatePreferenceDescriptionKeywordRepository extends JpaRepository { +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceDescriptionRepository.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceDescriptionRepository.java new file mode 100644 index 0000000..ec490d2 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceDescriptionRepository.java @@ -0,0 +1,11 @@ +package org.withtime.be.withtimebe.domain.date.preference.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceDescription; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferenceType; + +import java.util.Optional; + +public interface DatePreferenceDescriptionRepository extends JpaRepository { + Optional findByPreferenceType(PreferenceType preferenceType); +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceKeywordRepository.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceKeywordRepository.java new file mode 100644 index 0000000..aebb932 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceKeywordRepository.java @@ -0,0 +1,7 @@ +package org.withtime.be.withtimebe.domain.date.preference.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceKeyword; + +public interface DatePreferenceKeywordRepository extends JpaRepository { +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferencePartDescriptionRepository.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferencePartDescriptionRepository.java new file mode 100644 index 0000000..7c567d3 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferencePartDescriptionRepository.java @@ -0,0 +1,11 @@ +package org.withtime.be.withtimebe.domain.date.preference.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferencePartDescription; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferencePartType; + +import java.util.Optional; + +public interface DatePreferencePartDescriptionRepository extends JpaRepository { + Optional findByPreferencePartType(PreferencePartType preferencePartType); +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceQuestionRepository.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceQuestionRepository.java new file mode 100644 index 0000000..b77ea19 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceQuestionRepository.java @@ -0,0 +1,10 @@ +package org.withtime.be.withtimebe.domain.date.preference.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceQuestion; + +import java.util.List; + +public interface DatePreferenceQuestionRepository extends JpaRepository { + List findAllByOrderByIdAsc(); +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceTestResultRepository.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceTestResultRepository.java new file mode 100644 index 0000000..d614183 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/DatePreferenceTestResultRepository.java @@ -0,0 +1,7 @@ +package org.withtime.be.withtimebe.domain.date.preference.repository; + +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceTestResult; + +public interface DatePreferenceTestResultRepository { + DatePreferenceTestResult save(DatePreferenceTestResult datePreferenceTestResult); +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/JpaDatePreferenceTestResultRepository.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/JpaDatePreferenceTestResultRepository.java new file mode 100644 index 0000000..842e374 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/repository/JpaDatePreferenceTestResultRepository.java @@ -0,0 +1,7 @@ +package org.withtime.be.withtimebe.domain.date.preference.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceTestResult; + +public interface JpaDatePreferenceTestResultRepository extends DatePreferenceTestResultRepository, JpaRepository { +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/command/DatePreferenceTestCommandService.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/command/DatePreferenceTestCommandService.java new file mode 100644 index 0000000..9b9bb42 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/command/DatePreferenceTestCommandService.java @@ -0,0 +1,9 @@ +package org.withtime.be.withtimebe.domain.date.preference.service.command; + +import org.withtime.be.withtimebe.domain.date.preference.dto.DatePreferenceRequestDTO; +import org.withtime.be.withtimebe.domain.date.preference.dto.DatePreferenceResponseDTO; +import org.withtime.be.withtimebe.domain.member.entity.Member; + +public interface DatePreferenceTestCommandService { + DatePreferenceResponseDTO.TestResult test(Member member, DatePreferenceRequestDTO.Test request); +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/command/DatePreferenceTestCommandServiceImpl.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/command/DatePreferenceTestCommandServiceImpl.java new file mode 100644 index 0000000..15609e0 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/command/DatePreferenceTestCommandServiceImpl.java @@ -0,0 +1,70 @@ +package org.withtime.be.withtimebe.domain.date.preference.service.command; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.withtime.be.withtimebe.domain.date.preference.converter.DatePreferenceConverter; +import org.withtime.be.withtimebe.domain.date.preference.dto.DatePreferenceRequestDTO; +import org.withtime.be.withtimebe.domain.date.preference.dto.DatePreferenceResponseDTO; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferencePartDescription; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceTestResult; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferencePartType; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferenceType; +import org.withtime.be.withtimebe.domain.date.preference.repository.DatePreferenceDescriptionRepository; +import org.withtime.be.withtimebe.domain.date.preference.repository.DatePreferencePartDescriptionRepository; +import org.withtime.be.withtimebe.domain.date.preference.repository.DatePreferenceQuestionRepository; +import org.withtime.be.withtimebe.domain.date.preference.repository.DatePreferenceTestResultRepository; +import org.withtime.be.withtimebe.domain.date.preference.util.DatePreferenceTestScoreCalculator; +import org.withtime.be.withtimebe.domain.member.entity.Member; +import org.withtime.be.withtimebe.global.error.code.DatePreferenceErrorCode; +import org.withtime.be.withtimebe.global.error.exception.DatePreferenceException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class DatePreferenceTestCommandServiceImpl implements DatePreferenceTestCommandService { + + private final DatePreferenceDescriptionRepository datePreferenceDescriptionRepository; + private final DatePreferencePartDescriptionRepository datePreferencePartDescriptionRepository; + private final DatePreferenceTestResultRepository datePreferenceTestResultRepository; + private final DatePreferenceQuestionRepository datePreferenceQuestionRepository; + private final DatePreferenceTestScoreCalculator datePreferenceTestScoreCalculator; + + @Override + public DatePreferenceResponseDTO.TestResult test(Member member, DatePreferenceRequestDTO.Test request) { + // valid 판단 + if (!validateRequest(request)) { + throw new DatePreferenceException(DatePreferenceErrorCode.INVALID_ANSWERS); + } + + // 점수 계산 + DatePreferenceTestResult result = datePreferenceTestScoreCalculator.calculateTestScore(request); + result.mappingMember(member); + + // 엔티티 저장 (로그) + datePreferenceTestResultRepository.save(result); + + // 응답 생성 + return buildResponse(result); + } + + private boolean validateRequest(DatePreferenceRequestDTO.Test request) { + return datePreferenceQuestionRepository.count() == request.answers().size() && request.answers().stream().allMatch(value -> value >= 1 && value <= 2); + } + + private DatePreferenceResponseDTO.TestResult buildResponse(DatePreferenceTestResult testResult) { + List partDescriptionList = new ArrayList<>(); + PreferenceType preferenceType = testResult.getPreferenceType(); + for (int i = 0; i < 4; i++) { + PreferencePartType preferencePartType = PreferencePartType.valueOf(preferenceType.name().substring(i, i + 1)); + datePreferencePartDescriptionRepository.findByPreferencePartType(preferencePartType).ifPresent(partDescriptionList::add); + } + return DatePreferenceConverter.toTestResult( + testResult, + datePreferenceDescriptionRepository.findByPreferenceType(preferenceType).orElse(null), + partDescriptionList + ); + } +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceDescriptionQueryService.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceDescriptionQueryService.java new file mode 100644 index 0000000..c953712 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceDescriptionQueryService.java @@ -0,0 +1,11 @@ +package org.withtime.be.withtimebe.domain.date.preference.service.query; + +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceDescription; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceQuestion; + +import java.util.List; + +public interface DatePreferenceDescriptionQueryService { + + List findTypes(); +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceDescriptionQueryServiceImpl.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceDescriptionQueryServiceImpl.java new file mode 100644 index 0000000..b88923f --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceDescriptionQueryServiceImpl.java @@ -0,0 +1,21 @@ +package org.withtime.be.withtimebe.domain.date.preference.service.query; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceDescription; +import org.withtime.be.withtimebe.domain.date.preference.repository.DatePreferenceDescriptionRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class DatePreferenceDescriptionQueryServiceImpl implements DatePreferenceDescriptionQueryService { + + private final DatePreferenceDescriptionRepository datePreferenceDescriptionRepository; + + @Override + public List findTypes() { + return datePreferenceDescriptionRepository.findAll(); + } + +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceQuestionQueryService.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceQuestionQueryService.java new file mode 100644 index 0000000..6d972b4 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceQuestionQueryService.java @@ -0,0 +1,9 @@ +package org.withtime.be.withtimebe.domain.date.preference.service.query; + +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceQuestion; + +import java.util.List; + +public interface DatePreferenceQuestionQueryService { + List findQuestions(); +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceQuestionQueryServiceImpl.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceQuestionQueryServiceImpl.java new file mode 100644 index 0000000..dae072d --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/service/query/DatePreferenceQuestionQueryServiceImpl.java @@ -0,0 +1,20 @@ +package org.withtime.be.withtimebe.domain.date.preference.service.query; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceQuestion; +import org.withtime.be.withtimebe.domain.date.preference.repository.DatePreferenceQuestionRepository; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class DatePreferenceQuestionQueryServiceImpl implements DatePreferenceQuestionQueryService { + + private final DatePreferenceQuestionRepository datePreferenceQuestionRepository; + + @Override + public List findQuestions() { + return datePreferenceQuestionRepository.findAllByOrderByIdAsc(); + } +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/util/DatePreferenceTestScoreCalculator.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/util/DatePreferenceTestScoreCalculator.java new file mode 100644 index 0000000..c3ab67f --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/util/DatePreferenceTestScoreCalculator.java @@ -0,0 +1,8 @@ +package org.withtime.be.withtimebe.domain.date.preference.util; + +import org.withtime.be.withtimebe.domain.date.preference.dto.DatePreferenceRequestDTO; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceTestResult; + +public interface DatePreferenceTestScoreCalculator { + DatePreferenceTestResult calculateTestScore(DatePreferenceRequestDTO.Test request); +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/date/preference/util/WeightBaseTestScoreCalculator.java b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/util/WeightBaseTestScoreCalculator.java new file mode 100644 index 0000000..2e6b496 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/date/preference/util/WeightBaseTestScoreCalculator.java @@ -0,0 +1,67 @@ +package org.withtime.be.withtimebe.domain.date.preference.util; + +import org.springframework.stereotype.Component; +import org.withtime.be.withtimebe.domain.date.preference.converter.DatePreferenceConverter; +import org.withtime.be.withtimebe.domain.date.preference.dto.DatePreferenceRequestDTO; +import org.withtime.be.withtimebe.domain.date.preference.entity.DatePreferenceTestResult; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferencePartType; +import org.withtime.be.withtimebe.domain.date.preference.entity.enums.PreferenceType; + +import java.util.List; + +@Component +public class WeightBaseTestScoreCalculator implements DatePreferenceTestScoreCalculator { + + private static final PreferencePartType[][] types = { + {PreferencePartType.S, PreferencePartType.F}, + {PreferencePartType.A, PreferencePartType.C}, + {PreferencePartType.M, PreferencePartType.P}, + {PreferencePartType.E, PreferencePartType.O} + }; + + private static final double[] weights = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + + @Override + public DatePreferenceTestResult calculateTestScore(DatePreferenceRequestDTO.Test request) { + List answers = request.answers(); // 정답 배열 + int number = types.length; // PartType 개수 + int size = answers.size() / number; // PartType 개수 별 정답 개수 + Double[] percentages = new Double[number]; + StringBuilder type = new StringBuilder(); + + // 계산 + for (int i = 0; i < number ; i++) { + type.append(calculatePartType(answers, percentages, i * size, size)); + } + + return DatePreferenceConverter.toDatePreferenceTestResult( + PreferenceType.valueOf(type.toString()), + percentages[0], + percentages[1], + percentages[2], + percentages[3] + ); + } + + private String calculatePartType(List list, Double[] percentages, int start, int size) { + double score = calculateScore(list, start, size); + int index = start / size; + percentages[index] = Math.floor((score - 1) * 1000) / 10; + return score < 1.5 ? types[index][0].name() : types[index][1].name(); + } + + // return value between 1, 2 + private double calculateScore(List list, int start, int size) { + int end = start + size; + double sum = 0.0; + for (int i = start; i < end; i++) { + sum += list.get(i) * weights[i]; + } + return sum / size; + } +} diff --git a/src/main/java/org/withtime/be/withtimebe/global/error/code/DatePreferenceErrorCode.java b/src/main/java/org/withtime/be/withtimebe/global/error/code/DatePreferenceErrorCode.java new file mode 100644 index 0000000..a3209a7 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/global/error/code/DatePreferenceErrorCode.java @@ -0,0 +1,25 @@ +package org.withtime.be.withtimebe.global.error.code; + +import lombok.AllArgsConstructor; +import org.namul.api.payload.code.BaseErrorCode; +import org.namul.api.payload.code.dto.supports.DefaultResponseErrorReasonDTO; +import org.springframework.http.HttpStatus; + +@AllArgsConstructor +public enum DatePreferenceErrorCode implements BaseErrorCode { + + INVALID_ANSWERS(HttpStatus.BAD_REQUEST, "DATE_PREFERENCE400_1", "질문에 대한 응답의 형식이 잘못되었습니다.") + ; + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public DefaultResponseErrorReasonDTO getReason() { + return DefaultResponseErrorReasonDTO.builder() + .httpStatus(this.httpStatus) + .code(this.code) + .message(this.message) + .build(); + } +} diff --git a/src/main/java/org/withtime/be/withtimebe/global/error/exception/DatePreferenceException.java b/src/main/java/org/withtime/be/withtimebe/global/error/exception/DatePreferenceException.java new file mode 100644 index 0000000..f72ff6f --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/global/error/exception/DatePreferenceException.java @@ -0,0 +1,11 @@ +package org.withtime.be.withtimebe.global.error.exception; + +import org.namul.api.payload.code.BaseErrorCode; +import org.namul.api.payload.error.exception.ServerApplicationException; + +public class DatePreferenceException extends ServerApplicationException { + + public DatePreferenceException(BaseErrorCode code) { + super(code); + } +}