From 7c44b2c20bb7e8faf88f7c27006972f9473819e7 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sun, 16 Feb 2025 14:22:37 +0900 Subject: [PATCH 01/22] =?UTF-8?q?[#95]=20refactor:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - OneToOne 관계의 CharacterValueReport 삭제 - CharacterRecord와 관계 재설정 --- .../character/model/CharacterRecord.java | 12 +- .../character/model/CharacterValueReport.java | 38 ---- .../domain/character/model/ValueReport.java | 38 +++- .../repository/CharacterRecordRepository.java | 7 +- .../CharacterValueReportRepository.java | 16 -- .../repository/ValueReportRepository.java | 6 + .../CharacterRecordRepositoryTest.java | 145 ++++++++++++++- .../CharacterValueReportRepositoryTest.java | 168 ------------------ 8 files changed, 185 insertions(+), 245 deletions(-) delete mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterValueReport.java delete mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterValueReportRepository.java create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/ValueReportRepository.java delete mode 100644 jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterValueReportRepositoryTest.java diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java index f683b0aa..7b3667ed 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java @@ -5,8 +5,9 @@ import jakarta.persistence.FetchType; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToOne; +import jakarta.persistence.OneToMany; import java.time.LocalDate; +import java.util.List; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -38,8 +39,8 @@ public class CharacterRecord extends BaseTimeEntity { @JoinColumn(name = "bundle_id") private SurveyBundle surveyBundle; - @OneToOne(mappedBy = "characterRecord", cascade = CascadeType.ALL, orphanRemoval = true) - private CharacterValueReport characterValueReport; + @OneToMany(mappedBy = "characterRecord", cascade = CascadeType.ALL, orphanRemoval = true) + private List valueReports; @Builder private CharacterRecord( @@ -57,7 +58,8 @@ private CharacterRecord( this.surveyBundle = surveyBundle; } - public void updateCharacterValueReport(final CharacterValueReport characterValueReport) { - this.characterValueReport = characterValueReport; + public void updateValueReports(final List valueReports) { + valueReports.forEach(it -> it.updateCharacterRecord(this)); + this.valueReports = valueReports; } } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterValueReport.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterValueReport.java deleted file mode 100644 index 66883602..00000000 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterValueReport.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.nexters.jaknaesocore.domain.character.model; - -import jakarta.persistence.CollectionTable; -import jakarta.persistence.ElementCollection; -import jakarta.persistence.Entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.OneToOne; -import java.util.List; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.nexters.jaknaesocore.common.model.BaseTimeEntity; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@Entity -public class CharacterValueReport extends BaseTimeEntity { - - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "character_record_id") - private CharacterRecord characterRecord; - - // TODO: 추후 대체 - // @OneToMany(mappedBy = "characterValueReport", cascade = CascadeType.ALL, orphanRemoval = true) - @ElementCollection - @CollectionTable( - name = "value_reports", - joinColumns = @JoinColumn(name = "character_value_report_id")) - private List valueReports; - - public CharacterValueReport( - final CharacterRecord characterRecord, final List valueReports) { - this.characterRecord = characterRecord; - this.valueReports = valueReports; - characterRecord.updateCharacterValueReport(this); - } -} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueReport.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueReport.java index d02fd4ef..79e48001 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueReport.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueReport.java @@ -1,27 +1,34 @@ package org.nexters.jaknaesocore.domain.character.model; -import jakarta.persistence.Embeddable; +import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import java.math.BigDecimal; +import java.util.Objects; import lombok.AccessLevel; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; +import org.nexters.jaknaesocore.common.model.BaseTimeEntity; import org.nexters.jaknaesocore.common.model.ScaledBigDecimal; import org.nexters.jaknaesocore.domain.survey.model.Keyword; -@EqualsAndHashCode @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -@Embeddable -public class ValueReport { +@Entity +public class ValueReport extends BaseTimeEntity { @Enumerated(EnumType.STRING) private Keyword keyword; private BigDecimal percentage; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "character_record_id") + private CharacterRecord characterRecord; + private ValueReport(final Keyword keyword, final BigDecimal percentage) { this.keyword = keyword; this.percentage = percentage; @@ -31,6 +38,27 @@ public static ValueReport of(final Keyword keyword, final ScaledBigDecimal perce return new ValueReport(keyword, percentage.getValue()); } + public void updateCharacterRecord(final CharacterRecord characterRecord) { + this.characterRecord = characterRecord; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ValueReport that = (ValueReport) o; + return keyword == that.keyword && Objects.equals(percentage, that.percentage); + } + + @Override + public int hashCode() { + return Objects.hash(keyword, percentage); + } + @Override public String toString() { return "ValueReport{" + "keyword=" + keyword + ",percentage=" + percentage + "}"; diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepository.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepository.java index bcc54a9d..46b97159 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepository.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepository.java @@ -27,8 +27,7 @@ List findByMemberIdAndDeletedAtIsNullWithMemberAndSurveyBundle( final Long memberId); @Query( - "SELECT c FROM CharacterRecord c JOIN FETCH c.member cm " - + "WHERE c.id = :id AND cm.id = :memberId AND c.deletedAt IS NULL") - Optional existsByIdAndMemberIdAndDeletedAtIsNullWithMember( - final Long id, final Long memberId); + "SELECT c FROM CharacterRecord c JOIN FETCH c.valueReports cr " + + "WHERE c.id = :id AND c.deletedAt IS NULL") + Optional findByIdAndDeletedAtIsNullWithValueReports(final Long id); } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterValueReportRepository.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterValueReportRepository.java deleted file mode 100644 index d977055c..00000000 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterValueReportRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.nexters.jaknaesocore.domain.character.repository; - -import java.util.Optional; -import org.nexters.jaknaesocore.domain.character.model.CharacterValueReport; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; - -public interface CharacterValueReportRepository extends JpaRepository { - - @Query( - "SELECT c FROM CharacterValueReport c " - + "JOIN FETCH c.characterRecord cc JOIN FETCH c.valueReports " - + "WHERE cc.id = :characterId AND c.deletedAt IS NULL") - Optional findByCharacterIdAndDeletedAtIsNullWithCharacterAndValueReports( - final Long characterId); -} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/ValueReportRepository.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/ValueReportRepository.java new file mode 100644 index 00000000..c168cd7a --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/ValueReportRepository.java @@ -0,0 +1,6 @@ +package org.nexters.jaknaesocore.domain.character.repository; + +import org.nexters.jaknaesocore.domain.character.model.ValueReport; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ValueReportRepository extends JpaRepository {} diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java index cd134028..30a61e27 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java @@ -2,17 +2,34 @@ import static org.assertj.core.api.BDDAssertions.then; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.nexters.jaknaesocore.domain.survey.model.Keyword.BENEVOLENCE; +import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SELF_DIRECTION; +import static org.nexters.jaknaesocore.domain.survey.model.Keyword.STABILITY; +import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SUCCESS; +import java.math.BigDecimal; import java.time.LocalDate; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.nexters.jaknaesocore.common.support.IntegrationTest; import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; import org.nexters.jaknaesocore.domain.character.model.ValueCharacter; +import org.nexters.jaknaesocore.domain.character.model.ValueReport; +import org.nexters.jaknaesocore.domain.character.model.ValueReports; import org.nexters.jaknaesocore.domain.member.model.Member; import org.nexters.jaknaesocore.domain.member.repository.MemberRepository; +import org.nexters.jaknaesocore.domain.survey.model.BalanceSurvey; import org.nexters.jaknaesocore.domain.survey.model.Keyword; +import org.nexters.jaknaesocore.domain.survey.model.KeywordMetrics; +import org.nexters.jaknaesocore.domain.survey.model.KeywordMetricsMap; +import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; +import org.nexters.jaknaesocore.domain.survey.model.KeywordWeightMap; import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; +import org.nexters.jaknaesocore.domain.survey.model.SurveyOption; +import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; import org.nexters.jaknaesocore.domain.survey.repository.SurveyBundleRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveyOptionRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveyRepository; @@ -27,24 +44,34 @@ class CharacterRecordRepositoryTest extends IntegrationTest { @Autowired private CharacterRecordRepository sut; + @Autowired private ValueReportRepository valueReportRepository; @Autowired private ValueCharacterRepository valueCharacterRepository; - @Autowired private CharacterValueReportRepository characterValueReportRepository; @Autowired private MemberRepository memberRepository; @Autowired private SurveyBundleRepository surveyBundleRepository; @Autowired private SurveyRepository surveyRepository; @Autowired private SurveyOptionRepository surveyOptionRepository; @Autowired private SurveySubmissionRepository surveySubmissionRepository; + @AfterEach + void tearDown() { + valueReportRepository.deleteAllInBatch(); + sut.deleteAllInBatch(); + valueCharacterRepository.deleteAllInBatch(); + surveySubmissionRepository.deleteAllInBatch(); + surveyOptionRepository.deleteAllInBatch(); + surveyRepository.deleteAllInBatch(); + surveyBundleRepository.deleteAllInBatch(); + memberRepository.deleteAllInBatch(); + } + @Test void 회원의_현재_캐릭터를_조회한다() { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); final ValueCharacter valueCharacter1 = - valueCharacterRepository.save( - new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", Keyword.SUCCESS)); + valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); final ValueCharacter valueCharacter2 = - valueCharacterRepository.save( - new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", Keyword.SUCCESS)); + valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); final CharacterRecord characterRecord1 = CharacterRecord.builder() .characterNo("첫번째") @@ -78,8 +105,7 @@ class CharacterRecordRepositoryTest extends IntegrationTest { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); final ValueCharacter valueCharacter = - valueCharacterRepository.save( - new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", Keyword.SUCCESS)); + valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); final CharacterRecord characterRecord = sut.save( CharacterRecord.builder() @@ -104,8 +130,7 @@ class CharacterRecordRepositoryTest extends IntegrationTest { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); final ValueCharacter valueCharacter = - valueCharacterRepository.save( - new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", Keyword.SUCCESS)); + valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); sut.save( CharacterRecord.builder() .characterNo("첫번째") @@ -123,4 +148,106 @@ class CharacterRecordRepositoryTest extends IntegrationTest { () -> then(actual).hasSize(1), () -> then(actual.get(0).getSurveyBundle()).isEqualTo(bundle)); } + + @Transactional + @Test + void 회원의_캐릭터_분석_결과를_조회한다() { + final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); + final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); + final BalanceSurvey survey1 = + new BalanceSurvey( + "꿈에 그리던 드림 기업에 입사했다. 연봉도 좋지만, 무엇보다 회사의 근무 방식이 나와 잘 맞는 것 같다. 우리 회사의 근무 방식은...", bundle); + final SurveyOption option1 = + SurveyOption.builder() + .survey(survey1) + .content("자율 출퇴근제로 원하는 시간에 근무하며 창의적인 성과 내기") + .scores( + List.of( + KeywordScore.builder().keyword(SELF_DIRECTION).score(BigDecimal.ONE).build())) + .build(); + + final BalanceSurvey survey2 = new BalanceSurvey("독립에 대한 고민이 깊어지는 요즘... 드디어 결정을 내렸다.", bundle); + final SurveyOption option2 = + SurveyOption.builder() + .survey(survey2) + .content("내 취향대로 꾸민 집에서 자유롭게 생활하기") + .scores( + List.of( + KeywordScore.builder().keyword(SELF_DIRECTION).score(BigDecimal.ONE).build())) + .build(); + + final BalanceSurvey survey3 = + new BalanceSurvey("바쁜 일상에 지쳐버린 나. 여가 시간을 더 의미 있게 보내고 싶어졌다.", bundle); + final SurveyOption option3 = + SurveyOption.builder() + .survey(survey3) + .content("매년 새로운 취미에 도전하며 색다른 즐거움 찾기") + .scores( + List.of(KeywordScore.builder().keyword(STABILITY).score(BigDecimal.ONE).build())) + .build(); + + final BalanceSurvey survey4 = new BalanceSurvey("회사에서 새로운 평가 시스템을 도입한다. 당신의 선택은?", bundle); + final SurveyOption option4 = + SurveyOption.builder() + .survey(survey4) + .content("업무 성과에 따라 차등 보너스를 지급한다") + .scores(List.of(KeywordScore.builder().keyword(SUCCESS).score(BigDecimal.ONE).build())) + .build(); + + final BalanceSurvey survey5 = + new BalanceSurvey("연애를 시작한지도 어연 3개월, 그 사람과 나의 연애는 꽤 잘 맞는다. 우리의 관계는...", bundle); + final SurveyOption option5 = + SurveyOption.builder() + .survey(survey5) + .content("서로의 일상 속에서 따뜻하게 지지하는 관계") + .scores( + List.of(KeywordScore.builder().keyword(BENEVOLENCE).score(BigDecimal.ONE).build())) + .build(); + + final List submissions = + List.of( + SurveySubmission.builder().survey(survey1).selectedOption(option1).build(), + SurveySubmission.builder().survey(survey2).selectedOption(option2).build(), + SurveySubmission.builder().survey(survey3).selectedOption(option3).build(), + SurveySubmission.builder().survey(survey4).selectedOption(option4).build(), + SurveySubmission.builder().survey(survey5).selectedOption(option5).build()); + + final Map weights = new HashMap<>(); + weights.put(SELF_DIRECTION, BigDecimal.valueOf(5)); + weights.put(STABILITY, BigDecimal.valueOf(25)); + weights.put(SUCCESS, BigDecimal.valueOf(25)); + weights.put(BENEVOLENCE, BigDecimal.valueOf(5)); + + final List scores = + List.of( + KeywordScore.builder().keyword(SELF_DIRECTION).score(BigDecimal.valueOf(1)).build(), + KeywordScore.builder().keyword(STABILITY).score(BigDecimal.valueOf(1)).build(), + KeywordScore.builder().keyword(SUCCESS).score(BigDecimal.valueOf(1)).build(), + KeywordScore.builder().keyword(BENEVOLENCE).score(BigDecimal.valueOf(1)).build()); + + final Map metricsMap = KeywordMetricsMap.generate(scores); + final Map weightMap = KeywordWeightMap.generate(metricsMap); + + final ValueCharacter valueCharacter = + valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); + final CharacterRecord characterRecord = + sut.save( + CharacterRecord.builder() + .characterNo("첫번째") + .valueCharacter(valueCharacter) + .startDate(LocalDate.now().minusDays(15)) + .endDate(LocalDate.now()) + .member(member) + .surveyBundle(bundle) + .build()); + + List valueReports = + valueReportRepository.saveAll(ValueReports.report(weightMap, metricsMap, submissions)); + characterRecord.updateValueReports(valueReports); + + final CharacterRecord actual = + sut.findByIdAndDeletedAtIsNullWithValueReports(characterRecord.getId()).get(); + + then(actual).extracting("valueReports").usingRecursiveComparison().isEqualTo(valueReports); + } } diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterValueReportRepositoryTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterValueReportRepositoryTest.java deleted file mode 100644 index 5c7a7413..00000000 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterValueReportRepositoryTest.java +++ /dev/null @@ -1,168 +0,0 @@ -package org.nexters.jaknaesocore.domain.character.repository; - -import static org.assertj.core.api.BDDAssertions.then; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.BENEVOLENCE; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SELF_DIRECTION; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.STABILITY; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SUCCESS; - -import java.math.BigDecimal; -import java.time.LocalDate; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; -import org.nexters.jaknaesocore.common.support.IntegrationTest; -import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; -import org.nexters.jaknaesocore.domain.character.model.CharacterValueReport; -import org.nexters.jaknaesocore.domain.character.model.ValueCharacter; -import org.nexters.jaknaesocore.domain.character.model.ValueReports; -import org.nexters.jaknaesocore.domain.member.model.Member; -import org.nexters.jaknaesocore.domain.member.repository.MemberRepository; -import org.nexters.jaknaesocore.domain.survey.model.BalanceSurvey; -import org.nexters.jaknaesocore.domain.survey.model.Keyword; -import org.nexters.jaknaesocore.domain.survey.model.KeywordMetrics; -import org.nexters.jaknaesocore.domain.survey.model.KeywordMetricsMap; -import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; -import org.nexters.jaknaesocore.domain.survey.model.KeywordWeightMap; -import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; -import org.nexters.jaknaesocore.domain.survey.model.SurveyOption; -import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; -import org.nexters.jaknaesocore.domain.survey.repository.SurveyBundleRepository; -import org.nexters.jaknaesocore.domain.survey.repository.SurveyOptionRepository; -import org.nexters.jaknaesocore.domain.survey.repository.SurveyRepository; -import org.nexters.jaknaesocore.domain.survey.repository.SurveySubmissionRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; - -class CharacterValueReportRepositoryTest extends IntegrationTest { - - @Autowired private CharacterValueReportRepository sut; - - @Autowired private ValueCharacterRepository valueCharacterRepository; - @Autowired private CharacterRecordRepository characterRecordRepository; - @Autowired private MemberRepository memberRepository; - @Autowired private SurveyBundleRepository surveyBundleRepository; - @Autowired private SurveyRepository surveyRepository; - @Autowired private SurveyOptionRepository surveyOptionRepository; - @Autowired private SurveySubmissionRepository surveySubmissionRepository; - - @AfterEach - void tearDown() { - sut.deleteAllInBatch(); - characterRecordRepository.deleteAllInBatch(); - valueCharacterRepository.deleteAllInBatch(); - surveySubmissionRepository.deleteAllInBatch(); - surveyOptionRepository.deleteAllInBatch(); - surveyRepository.deleteAllInBatch(); - surveyBundleRepository.deleteAllInBatch(); - memberRepository.deleteAllInBatch(); - } - - @Transactional - @Test - void 회원의_캐릭터_분석_결과를_조회한다() { - final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); - final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); - final BalanceSurvey survey1 = - new BalanceSurvey( - "꿈에 그리던 드림 기업에 입사했다. 연봉도 좋지만, 무엇보다 회사의 근무 방식이 나와 잘 맞는 것 같다. 우리 회사의 근무 방식은...", bundle); - final SurveyOption option1 = - SurveyOption.builder() - .survey(survey1) - .content("자율 출퇴근제로 원하는 시간에 근무하며 창의적인 성과 내기") - .scores( - List.of( - KeywordScore.builder().keyword(SELF_DIRECTION).score(BigDecimal.ONE).build())) - .build(); - - final BalanceSurvey survey2 = new BalanceSurvey("독립에 대한 고민이 깊어지는 요즘... 드디어 결정을 내렸다.", bundle); - final SurveyOption option2 = - SurveyOption.builder() - .survey(survey2) - .content("내 취향대로 꾸민 집에서 자유롭게 생활하기") - .scores( - List.of( - KeywordScore.builder().keyword(SELF_DIRECTION).score(BigDecimal.ONE).build())) - .build(); - - final BalanceSurvey survey3 = - new BalanceSurvey("바쁜 일상에 지쳐버린 나. 여가 시간을 더 의미 있게 보내고 싶어졌다.", bundle); - final SurveyOption option3 = - SurveyOption.builder() - .survey(survey3) - .content("매년 새로운 취미에 도전하며 색다른 즐거움 찾기") - .scores( - List.of(KeywordScore.builder().keyword(STABILITY).score(BigDecimal.ONE).build())) - .build(); - - final BalanceSurvey survey4 = new BalanceSurvey("회사에서 새로운 평가 시스템을 도입한다. 당신의 선택은?", bundle); - final SurveyOption option4 = - SurveyOption.builder() - .survey(survey4) - .content("업무 성과에 따라 차등 보너스를 지급한다") - .scores(List.of(KeywordScore.builder().keyword(SUCCESS).score(BigDecimal.ONE).build())) - .build(); - - final BalanceSurvey survey5 = - new BalanceSurvey("연애를 시작한지도 어연 3개월, 그 사람과 나의 연애는 꽤 잘 맞는다. 우리의 관계는...", bundle); - final SurveyOption option5 = - SurveyOption.builder() - .survey(survey5) - .content("서로의 일상 속에서 따뜻하게 지지하는 관계") - .scores( - List.of(KeywordScore.builder().keyword(BENEVOLENCE).score(BigDecimal.ONE).build())) - .build(); - - final List submissions = - List.of( - SurveySubmission.builder().survey(survey1).selectedOption(option1).build(), - SurveySubmission.builder().survey(survey2).selectedOption(option2).build(), - SurveySubmission.builder().survey(survey3).selectedOption(option3).build(), - SurveySubmission.builder().survey(survey4).selectedOption(option4).build(), - SurveySubmission.builder().survey(survey5).selectedOption(option5).build()); - - final Map weights = new HashMap<>(); - weights.put(SELF_DIRECTION, BigDecimal.valueOf(5)); - weights.put(STABILITY, BigDecimal.valueOf(25)); - weights.put(SUCCESS, BigDecimal.valueOf(25)); - weights.put(BENEVOLENCE, BigDecimal.valueOf(5)); - - final List scores = - List.of( - KeywordScore.builder().keyword(SELF_DIRECTION).score(BigDecimal.valueOf(1)).build(), - KeywordScore.builder().keyword(STABILITY).score(BigDecimal.valueOf(1)).build(), - KeywordScore.builder().keyword(SUCCESS).score(BigDecimal.valueOf(1)).build(), - KeywordScore.builder().keyword(BENEVOLENCE).score(BigDecimal.valueOf(1)).build()); - - final Map metricsMap = KeywordMetricsMap.generate(scores); - final Map weightMap = KeywordWeightMap.generate(metricsMap); - - final ValueCharacter valueCharacter = - valueCharacterRepository.save( - new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", Keyword.SUCCESS)); - final CharacterRecord characterRecord = - characterRecordRepository.save( - CharacterRecord.builder() - .characterNo("첫번째") - .valueCharacter(valueCharacter) - .startDate(LocalDate.now().minusDays(15)) - .endDate(LocalDate.now()) - .member(member) - .surveyBundle(bundle) - .build()); - final CharacterValueReport report = - new CharacterValueReport( - characterRecord, ValueReports.of(weightMap, metricsMap, submissions).getReports()); - - final CharacterValueReport actual = - sut.findByCharacterIdAndDeletedAtIsNullWithCharacterAndValueReports(characterRecord.getId()) - .get(); - - then(actual) - .extracting("valueReports") - .usingRecursiveComparison() - .isEqualTo(ValueReports.of(weightMap, metricsMap, submissions).getReports()); - } -} From a375a7744162f3d512beb63bfab01c917d1c8e56 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sun, 16 Feb 2025 18:55:32 +0900 Subject: [PATCH 02/22] =?UTF-8?q?[#95]=20refactor:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EA=B0=9D=EC=B2=B4=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EC=9D=BC=EA=B8=89=20=EC=BB=AC=EB=A0=89=EC=85=98=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/character/model/Characters.java | 96 +++++++++++++++++++ .../domain/character/model/ValueReports.java | 18 +--- .../survey/model/KeywordMetricsMap.java | 17 ---- .../domain/survey/model/KeywordScores.java | 18 ++++ .../domain/survey/model/KeywordWeightMap.java | 24 ----- .../character/model/ValueReportsTest.java | 46 +++++++-- .../survey/model/KeywordMetricsMapTest.java | 35 ------- .../survey/model/KeywordWeightMapTest.java | 37 ------- 8 files changed, 156 insertions(+), 135 deletions(-) create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/Characters.java delete mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordMetricsMap.java create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordScores.java delete mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordWeightMap.java delete mode 100644 jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/model/KeywordMetricsMapTest.java delete mode 100644 jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/model/KeywordWeightMapTest.java diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/Characters.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/Characters.java new file mode 100644 index 00000000..cadde3e1 --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/Characters.java @@ -0,0 +1,96 @@ +package org.nexters.jaknaesocore.domain.character.model; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.RequiredArgsConstructor; +import org.nexters.jaknaesocore.common.model.ScaledBigDecimal; +import org.nexters.jaknaesocore.domain.member.model.Member; +import org.nexters.jaknaesocore.domain.survey.model.Keyword; +import org.nexters.jaknaesocore.domain.survey.model.KeywordMetrics; +import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; +import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; +import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; + +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class Characters { + + private final Long characterNo; + private final Member member; + private final SurveyBundle bundle; + private final List scores; + private final List submissions; + private final Map valueCharacters; + + @Builder + public static Characters of( + final Long characterNo, + final Member member, + final SurveyBundle bundle, + final List scores, + final List submissions, + final Map valueCharacters) { + return new Characters(characterNo, member, bundle, scores, submissions, valueCharacters); + } + + public CharacterRecord provideCharacterRecord() { + final List valueReports = provideValueReport(); + final ValueCharacter valueCharacter = findTopValueCharacter(valueReports); + return CharacterRecord.builder() + .characterNo("TODO 수정") + .valueCharacter(valueCharacter) + .valueReports(valueReports) + .member(member) + .surveyBundle(bundle) + .valueReports(valueReports) + .startDate(bundle.getCreatedAt().toLocalDate()) + .endDate(LocalDate.now()) + .build(); + } + + private List provideValueReport() { + final Map metricsMap = calculateKeywordMetrics(scores); + final Map weightMap = calculateKeywordWeights(metricsMap); + + return ValueReports.report(weightMap, metricsMap, submissions); + } + + private Map calculateKeywordMetrics(final List scores) { + return scores.stream() + .collect(Collectors.groupingBy(KeywordScore::getKeyword, Collectors.toList())) + .entrySet() + .stream() + .collect( + Collectors.toMap(Map.Entry::getKey, entry -> KeywordMetrics.create(entry.getValue()))); + } + + private Map calculateKeywordWeights( + final Map metricsMap) { + int keywordCnt = metricsMap.size(); + ScaledBigDecimal sumPerKeyword = + ScaledBigDecimal.of(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(keywordCnt)); + + Map weightMap = new HashMap<>(); + metricsMap.forEach( + (k, v) -> { + var sum = v.getPositive().subtract(v.getNegative()); + weightMap.put(k, sumPerKeyword.divide(sum).getValue()); + }); + return weightMap; + } + + private ValueCharacter findTopValueCharacter(final List valueReports) { + final ValueReport topReport = + valueReports.stream() + .max(Comparator.comparing(ValueReport::getPercentage)) + .orElseThrow(() -> new IllegalStateException("ValueReport가 비어 있습니다.")); + + return valueCharacters.get(topReport.getKeyword()); + } +} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueReports.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueReports.java index 6401ec25..5d0ed24a 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueReports.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueReports.java @@ -5,7 +5,6 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import lombok.Getter; import org.nexters.jaknaesocore.common.model.ScaledBigDecimal; import org.nexters.jaknaesocore.domain.survey.model.Keyword; import org.nexters.jaknaesocore.domain.survey.model.KeywordMetrics; @@ -13,29 +12,20 @@ import org.nexters.jaknaesocore.domain.survey.model.KeywordScoreNormalizer; import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; -@Getter public class ValueReports { private static final ScaledBigDecimal PERCENTAGE100 = ScaledBigDecimal.of(BigDecimal.valueOf(100)); - private List reports; - - private ValueReports(final List reports) { - this.reports = reports; - } - - public static ValueReports of( + public static List report( final Map weights, final Map metrics, final List submissions) { Map percentage = getKeywordPercentage(weights, metrics, submissions); - List reports = - percentage.entrySet().stream() - .map(it -> ValueReport.of(it.getKey(), ScaledBigDecimal.of(it.getValue()))) - .collect(Collectors.toList()); - return new ValueReports(reports); + return percentage.entrySet().stream() + .map(it -> ValueReport.of(it.getKey(), ScaledBigDecimal.of(it.getValue()))) + .collect(Collectors.toList()); } private static Map getKeywordPercentage( diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordMetricsMap.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordMetricsMap.java deleted file mode 100644 index 1589305f..00000000 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordMetricsMap.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.nexters.jaknaesocore.domain.survey.model; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -public class KeywordMetricsMap { - - public static Map generate(final List scores) { - return scores.stream() - .collect(Collectors.groupingBy(KeywordScore::getKeyword, Collectors.toList())) - .entrySet() - .stream() - .collect( - Collectors.toMap(Map.Entry::getKey, entry -> KeywordMetrics.create(entry.getValue()))); - } -} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordScores.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordScores.java new file mode 100644 index 00000000..d70674eb --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordScores.java @@ -0,0 +1,18 @@ +package org.nexters.jaknaesocore.domain.survey.model; + +import java.util.List; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class KeywordScores { + + private final List surveys; + + public List getKeywordScores() { + return surveys.stream() + .flatMap(survey -> survey.getOptions().stream()) + .flatMap(option -> option.getScores().stream()) + .collect(Collectors.toList()); + } +} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordWeightMap.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordWeightMap.java deleted file mode 100644 index 60899a35..00000000 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordWeightMap.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.nexters.jaknaesocore.domain.survey.model; - -import java.math.BigDecimal; -import java.util.HashMap; -import java.util.Map; -import org.nexters.jaknaesocore.common.model.ScaledBigDecimal; - -public class KeywordWeightMap { - - public static Map generate(final Map metricsMap) { - Map weightMap = new HashMap<>(); - - int keywordCnt = metricsMap.size(); - ScaledBigDecimal sumPerKeyword = - ScaledBigDecimal.of(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(keywordCnt)); - - metricsMap.forEach( - (k, v) -> { - var sum = v.getPositive().subtract(v.getNegative()); - weightMap.put(k, sumPerKeyword.divide(sum).getValue()); - }); - return weightMap; - } -} diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/ValueReportsTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/ValueReportsTest.java index 2a6c7b1a..f9f70465 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/ValueReportsTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/ValueReportsTest.java @@ -8,21 +8,53 @@ import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SUCCESS; import java.math.BigDecimal; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import org.nexters.jaknaesocore.common.model.ScaledBigDecimal; +import org.nexters.jaknaesocore.common.support.IntegrationTest; +import org.nexters.jaknaesocore.domain.character.repository.CharacterRecordRepository; +import org.nexters.jaknaesocore.domain.character.repository.ValueReportRepository; import org.nexters.jaknaesocore.domain.survey.model.BalanceSurvey; import org.nexters.jaknaesocore.domain.survey.model.Keyword; import org.nexters.jaknaesocore.domain.survey.model.KeywordMetrics; -import org.nexters.jaknaesocore.domain.survey.model.KeywordMetricsMap; import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; -import org.nexters.jaknaesocore.domain.survey.model.KeywordWeightMap; import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; import org.nexters.jaknaesocore.domain.survey.model.SurveyOption; import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; +import org.springframework.beans.factory.annotation.Autowired; -class ValueReportsTest { +class ValueReportsTest extends IntegrationTest { + + @Autowired private CharacterRecordRepository characterRecordRepository; + @Autowired private ValueReportRepository valueReportRepository; + + private Map generateMetricsMap(List scores) { + return scores.stream() + .collect(Collectors.groupingBy(KeywordScore::getKeyword, Collectors.toList())) + .entrySet() + .stream() + .collect( + Collectors.toMap(Map.Entry::getKey, entry -> KeywordMetrics.create(entry.getValue()))); + } + + private Map generateWeightsMap( + final Map metricsMap) { + Map weightMap = new HashMap<>(); + + int keywordCnt = metricsMap.size(); + ScaledBigDecimal sumPerKeyword = + ScaledBigDecimal.of(BigDecimal.valueOf(100)).divide(BigDecimal.valueOf(keywordCnt)); + + metricsMap.forEach( + (k, v) -> { + var sum = v.getPositive().subtract(v.getNegative()); + weightMap.put(k, sumPerKeyword.divide(sum).getValue()); + }); + return weightMap; + } @Test void 키워드_가중치와_설문_응답_목록으로_가치관_리포트를_반환한다() { @@ -33,8 +65,8 @@ class ValueReportsTest { KeywordScore.builder().keyword(SUCCESS).score(BigDecimal.valueOf(1)).build(), KeywordScore.builder().keyword(BENEVOLENCE).score(BigDecimal.valueOf(1)).build()); - final Map metricsMap = KeywordMetricsMap.generate(scores); - final Map weightMap = KeywordWeightMap.generate(metricsMap); + final Map metricsMap = generateMetricsMap(scores); + final Map weightMap = generateWeightsMap(metricsMap); final SurveyBundle bundle = new SurveyBundle(); final BalanceSurvey survey1 = @@ -95,9 +127,7 @@ class ValueReportsTest { SurveySubmission.builder().survey(survey4).selectedOption(option4).build(), SurveySubmission.builder().survey(survey5).selectedOption(option5).build()); - final ValueReports reports = ValueReports.of(weightMap, metricsMap, submissions); - - final List actual = reports.getReports(); + final List actual = ValueReports.report(weightMap, metricsMap, submissions); assertAll( () -> diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/model/KeywordMetricsMapTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/model/KeywordMetricsMapTest.java deleted file mode 100644 index 684156ac..00000000 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/model/KeywordMetricsMapTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.nexters.jaknaesocore.domain.survey.model; - -import static org.assertj.core.api.BDDAssertions.then; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.ADVENTURE; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SECURITY; - -import java.math.BigDecimal; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.Test; - -class KeywordMetricsMapTest { - - @Test - void 키워드_점수_리스트를_바탕으로_키워드_지표_맵을_생성한다() { - final List scores = - List.of( - KeywordScore.builder().keyword(ADVENTURE).score(BigDecimal.valueOf(1)).build(), - KeywordScore.builder().keyword(ADVENTURE).score(BigDecimal.valueOf(-1)).build(), - KeywordScore.builder().keyword(SECURITY).score(BigDecimal.valueOf(1)).build()); - - final Map actual = KeywordMetricsMap.generate(scores); - - assertAll( - () -> - then(actual.get(ADVENTURE)) - .extracting("cnt", "positive", "negative") - .containsExactly(2, BigDecimal.valueOf(1), BigDecimal.valueOf(-1)), - () -> - then(actual.get(SECURITY)) - .extracting("cnt", "positive", "negative") - .containsExactly(1, BigDecimal.valueOf(1), BigDecimal.valueOf(0))); - } -} diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/model/KeywordWeightMapTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/model/KeywordWeightMapTest.java deleted file mode 100644 index ea508223..00000000 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/model/KeywordWeightMapTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.nexters.jaknaesocore.domain.survey.model; - -import static org.assertj.core.api.BDDAssertions.then; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.ADVENTURE; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SECURITY; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SUCCESS; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.UNIVERSALISM; - -import java.math.BigDecimal; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.Test; - -class KeywordWeightMapTest { - - @Test - void 키워드_지표를_바탕으로_키워드_응답별_가중치를_계산한다() { - final List scores = - List.of( - KeywordScore.builder().keyword(ADVENTURE).score(BigDecimal.valueOf(1)).build(), - KeywordScore.builder().keyword(ADVENTURE).score(BigDecimal.valueOf(-1)).build(), - KeywordScore.builder().keyword(SECURITY).score(BigDecimal.valueOf(1)).build(), - KeywordScore.builder().keyword(SUCCESS).score(BigDecimal.valueOf(1)).build(), - KeywordScore.builder().keyword(UNIVERSALISM).score(BigDecimal.valueOf(-1)).build()); - final Map metricsMap = KeywordMetricsMap.generate(scores); - - final Map actual = KeywordWeightMap.generate(metricsMap); - - assertAll( - () -> then(actual).hasSize(4), - () -> then(actual.get(ADVENTURE)).isEqualByComparingTo(BigDecimal.valueOf(12.50)), - () -> then(actual.get(SECURITY)).isEqualByComparingTo(BigDecimal.valueOf(25.00)), - () -> then(actual.get(SUCCESS)).isEqualByComparingTo(BigDecimal.valueOf(25.00)), - () -> then(actual.get(UNIVERSALISM)).isEqualByComparingTo(BigDecimal.valueOf(25.00))); - } -} From 9b731d90b38b98c03eb0319066ac7c33ef169e75 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sun, 16 Feb 2025 18:56:56 +0900 Subject: [PATCH 03/22] =?UTF-8?q?[#95]=20refactor:=20final=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/nexters/jaknaesocore/common/model/BaseEntity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/common/model/BaseEntity.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/common/model/BaseEntity.java index 74546fe1..b4caf129 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/common/model/BaseEntity.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/common/model/BaseEntity.java @@ -16,7 +16,7 @@ public abstract class BaseEntity { private Long id; @Override - public final boolean equals(Object o) { + public boolean equals(Object o) { if (this == o) { return true; } From 658f309f03960a84631362241514c1e58dc9b928 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sun, 16 Feb 2025 18:58:05 +0900 Subject: [PATCH 04/22] =?UTF-8?q?[#95]=20refactor:=20ValueReports=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CharacterRecord와 일대다 관계 맺도록 변경 --- .../character/model/CharacterRecord.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java index 7b3667ed..26aefd14 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java @@ -39,27 +39,40 @@ public class CharacterRecord extends BaseTimeEntity { @JoinColumn(name = "bundle_id") private SurveyBundle surveyBundle; - @OneToMany(mappedBy = "characterRecord", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "characterRecord", cascade = CascadeType.PERSIST, orphanRemoval = true) private List valueReports; - @Builder private CharacterRecord( final String characterNo, final ValueCharacter valueCharacter, final LocalDate startDate, final LocalDate endDate, final Member member, - final SurveyBundle surveyBundle) { + final SurveyBundle surveyBundle, + final List valueReports) { this.characterNo = characterNo; this.valueCharacter = valueCharacter; this.startDate = startDate; this.endDate = endDate; this.member = member; this.surveyBundle = surveyBundle; + + if (valueReports != null) { + this.valueReports = valueReports; + this.valueReports.forEach(it -> it.updateCharacterRecord(this)); + } } - public void updateValueReports(final List valueReports) { - valueReports.forEach(it -> it.updateCharacterRecord(this)); - this.valueReports = valueReports; + @Builder + public static CharacterRecord of( + final String characterNo, + final ValueCharacter valueCharacter, + final LocalDate startDate, + final LocalDate endDate, + final Member member, + final SurveyBundle surveyBundle, + final List valueReports) { + return new CharacterRecord( + characterNo, valueCharacter, startDate, endDate, member, surveyBundle, valueReports); } } From 85bf864b56ab2ddcda8a4c936264d2a8e1db6f83 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sun, 16 Feb 2025 19:05:49 +0900 Subject: [PATCH 05/22] =?UTF-8?q?[#95]=20feat:=20=EC=BA=90=EB=A6=AD?= =?UTF-8?q?=ED=84=B0=20=EC=83=9D=EC=84=B1=20=EB=A1=9C=EC=A7=81=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Survey 도메인에서 이벤트로 실행 --- .../character/service/CharacterService.java | 58 ++++-- .../service/CharacterServiceTest.java | 177 ++++++++++++------ 2 files changed, 171 insertions(+), 64 deletions(-) diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java index 5e93e1c0..fa2f945d 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java @@ -1,11 +1,17 @@ package org.nexters.jaknaesocore.domain.character.service; +import jakarta.annotation.PostConstruct; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.nexters.jaknaesocore.common.support.error.CustomException; -import org.nexters.jaknaesocore.domain.character.model.CharacterValueReport; +import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; +import org.nexters.jaknaesocore.domain.character.model.Characters; +import org.nexters.jaknaesocore.domain.character.model.ValueCharacter; import org.nexters.jaknaesocore.domain.character.repository.CharacterRecordRepository; -import org.nexters.jaknaesocore.domain.character.repository.CharacterValueReportRepository; +import org.nexters.jaknaesocore.domain.character.repository.ValueCharacterRepository; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterCommand; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterResponse; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterValueReportCommand; @@ -13,16 +19,31 @@ import org.nexters.jaknaesocore.domain.character.service.dto.CharactersResponse; import org.nexters.jaknaesocore.domain.character.service.dto.CharactersResponse.SimpleCharacterResponse; import org.nexters.jaknaesocore.domain.member.repository.MemberRepository; +import org.nexters.jaknaesocore.domain.survey.model.Keyword; +import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; +import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; +@Slf4j @RequiredArgsConstructor @Service public class CharacterService { private final MemberRepository memberRepository; private final CharacterRecordRepository characterRecordRepository; - private final CharacterValueReportRepository characterValueReportRepository; + private final ValueCharacterRepository valueCharacterRepository; + + private Map valueCharacters; + + @PostConstruct + void setUp() { + valueCharacters = + valueCharacterRepository.findAll().stream() + .collect( + Collectors.toMap(ValueCharacter::getKeyword, valueCharacter -> valueCharacter)); + } @Transactional(readOnly = true) public CharacterResponse getCharacter(final CharacterCommand command) { @@ -82,14 +103,29 @@ public CharactersResponse getCharacters(final Long memberId) { @Transactional(readOnly = true) public CharacterValueReportResponse getCharacterReport( final CharacterValueReportCommand command) { - characterRecordRepository - .findByIdAndMemberIdAndDeletedAtIsNullWithMember(command.characterId(), command.memberId()) - .orElseThrow(() -> CustomException.CHARACTER_NOT_FOUND); + final CharacterRecord characterRecord = + characterRecordRepository + .findByIdAndDeletedAtIsNullWithValueReports(command.characterId()) + .orElseThrow(() -> CustomException.CHARACTER_NOT_FOUND); + return CharacterValueReportResponse.of(characterRecord.getValueReports()); + } + + @EventListener + @Transactional(propagation = Propagation.MANDATORY) + public void createCharacter(final CreateCharacterEvent event) { + final Characters characters = + Characters.builder() + .member(event.member()) + .bundle(event.bundle()) + .scores(event.scores()) + .submissions(event.submissions()) + .valueCharacters(valueCharacters) + .build(); + characterRecordRepository.save(characters.provideCharacterRecord()); - final CharacterValueReport report = - characterValueReportRepository - .findByCharacterIdAndDeletedAtIsNullWithCharacterAndValueReports(command.characterId()) - .orElseThrow(() -> CustomException.CHARACTER_VALUE_REPORT_NOT_FOUND); - return CharacterValueReportResponse.of(report.getValueReports()); + log.info( + "Handled CreateCharacterEvent for memberId {} and bundleId {}", + event.member().getId(), + event.bundle().getId()); } } diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java index d38a718a..0e86f480 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java @@ -3,25 +3,27 @@ import static org.assertj.core.api.BDDAssertions.then; import static org.assertj.core.api.BDDAssertions.thenThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.nexters.jaknaesocore.domain.survey.model.Keyword.BENEVOLENCE; import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SELF_DIRECTION; +import static org.nexters.jaknaesocore.domain.survey.model.Keyword.STABILITY; +import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SUCCESS; import java.math.BigDecimal; import java.time.LocalDate; import java.util.List; -import java.util.Map; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.nexters.jaknaesocore.common.model.ScaledBigDecimal; import org.nexters.jaknaesocore.common.support.IntegrationTest; import org.nexters.jaknaesocore.common.support.error.CustomException; import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; -import org.nexters.jaknaesocore.domain.character.model.CharacterValueReport; import org.nexters.jaknaesocore.domain.character.model.ValueCharacter; -import org.nexters.jaknaesocore.domain.character.model.ValueReports; +import org.nexters.jaknaesocore.domain.character.model.ValueReport; import org.nexters.jaknaesocore.domain.character.repository.CharacterRecordRepository; -import org.nexters.jaknaesocore.domain.character.repository.CharacterValueReportRepository; import org.nexters.jaknaesocore.domain.character.repository.ValueCharacterRepository; +import org.nexters.jaknaesocore.domain.character.repository.ValueReportRepository; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterCommand; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterResponse; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterValueReportCommand; @@ -30,12 +32,8 @@ import org.nexters.jaknaesocore.domain.member.model.Member; import org.nexters.jaknaesocore.domain.member.repository.MemberRepository; import org.nexters.jaknaesocore.domain.survey.model.BalanceSurvey; -import org.nexters.jaknaesocore.domain.survey.model.Keyword; -import org.nexters.jaknaesocore.domain.survey.model.KeywordMetrics; -import org.nexters.jaknaesocore.domain.survey.model.KeywordMetricsMap; import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; -import org.nexters.jaknaesocore.domain.survey.model.KeywordWeightMap; -import org.nexters.jaknaesocore.domain.survey.model.Survey; +import org.nexters.jaknaesocore.domain.survey.model.KeywordScores; import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; import org.nexters.jaknaesocore.domain.survey.model.SurveyOption; import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; @@ -43,9 +41,11 @@ import org.nexters.jaknaesocore.domain.survey.repository.SurveyOptionRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveyRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveySubmissionRepository; +import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; +import org.springframework.transaction.annotation.Transactional; @DirtiesContext(classMode = ClassMode.BEFORE_CLASS) class CharacterServiceTest extends IntegrationTest { @@ -53,9 +53,9 @@ class CharacterServiceTest extends IntegrationTest { @Autowired private CharacterService sut; @Autowired private MemberRepository memberRepository; + @Autowired private ValueReportRepository valueReportRepository; @Autowired private ValueCharacterRepository valueCharacterRepository; @Autowired private CharacterRecordRepository characterRecordRepository; - @Autowired private CharacterValueReportRepository characterValueReportRepository; @Autowired private SurveyBundleRepository surveyBundleRepository; @Autowired private SurveyRepository surveyRepository; @Autowired private SurveyOptionRepository surveyOptionRepository; @@ -63,7 +63,7 @@ class CharacterServiceTest extends IntegrationTest { @AfterEach void tearDown() { - characterValueReportRepository.deleteAllInBatch(); + valueReportRepository.deleteAllInBatch(); characterRecordRepository.deleteAllInBatch(); valueCharacterRepository.deleteAllInBatch(); surveySubmissionRepository.deleteAllInBatch(); @@ -108,8 +108,7 @@ void shouldReturnCharacter() { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); final ValueCharacter valueCharacter = - valueCharacterRepository.save( - new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", Keyword.SUCCESS)); + valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); final CharacterRecord characterRecord = characterRecordRepository.save( CharacterRecord.builder() @@ -157,8 +156,7 @@ void shouldReturnCharacter() { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); final ValueCharacter valueCharacter = - valueCharacterRepository.save( - new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", Keyword.SUCCESS)); + valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); characterRecordRepository.save( CharacterRecord.builder() .characterNo("첫번째") @@ -204,8 +202,7 @@ void shouldReturnCharacters() { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); final ValueCharacter valueCharacter = - valueCharacterRepository.save( - new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", Keyword.SUCCESS)); + valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); characterRecordRepository.save( CharacterRecord.builder() .characterNo("첫번째") @@ -248,62 +245,136 @@ void shouldThrowException() { @DisplayName("캐릭터 기록을 찾으면") class whenCharacterRecordFound { + @Transactional @Test @DisplayName("회원의 캐릭터 가치관 분석 정보를 반환한다.") void shouldReturnReport() { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); - final Survey survey = - surveyRepository.save( - new BalanceSurvey( - "꿈에 그리던 드림 기업에 입사했다. 연봉도 좋지만, 무엇보다 회사의 근무 방식이 나와 잘 맞는 것 같다. 우리 회사의 근무 방식은...", - bundle)); - final List scores = - List.of(KeywordScore.builder().keyword(SELF_DIRECTION).score(BigDecimal.ONE).build()); - final SurveyOption option = - surveyOptionRepository.save( - SurveyOption.builder() - .survey(survey) - .content("자율 출퇴근제로 원하는 시간에 근무하며 창의적인 성과 내기") - .scores(scores) - .build()); - final SurveySubmission submission = - surveySubmissionRepository.save( - SurveySubmission.builder() - .member(member) - .survey(survey) - .selectedOption(option) - .build()); - - final Map metricsMap = KeywordMetricsMap.generate(scores); - final Map weightMap = KeywordWeightMap.generate(metricsMap); - - final ValueCharacter valueCharacter = - valueCharacterRepository.save( - new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", Keyword.SUCCESS)); + final ValueReport valueReport = + valueReportRepository.save( + ValueReport.of(SELF_DIRECTION, ScaledBigDecimal.of(BigDecimal.valueOf(100)))); final CharacterRecord characterRecord = characterRecordRepository.save( CharacterRecord.builder() .characterNo("첫번째") - .valueCharacter(valueCharacter) + .valueReports(List.of(valueReport)) .startDate(LocalDate.now().minusDays(15)) .endDate(LocalDate.now()) .member(member) .surveyBundle(bundle) .build()); - characterValueReportRepository.save( - new CharacterValueReport( - characterRecord, - ValueReports.of(weightMap, metricsMap, List.of(submission)).getReports())); final CharacterValueReportResponse actual = sut.getCharacterReport( createCharacterReportCommand(member.getId(), characterRecord.getId())); - then(actual.valueReports()) - .usingRecursiveComparison() - .isEqualTo(ValueReports.of(weightMap, metricsMap, List.of(submission)).getReports()); + then(actual.valueReports()).usingRecursiveComparison().isEqualTo(List.of(valueReport)); } } } + + @Nested + @DisplayName("createCharacter 메소드는") + class createCharacter { + + @Transactional + @Test + @DisplayName("회원의 캐릭터를 생성한다.") + void shouldCreateCharacter() { + final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); + final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); + + final BalanceSurvey survey1 = + surveyRepository.save( + new BalanceSurvey( + "꿈에 그리던 드림 기업에 입사했다. 연봉도 좋지만, 무엇보다 회사의 근무 방식이 나와 잘 맞는 것 같다. 우리 회사의 근무 방식은...", + bundle)); + final BalanceSurvey survey2 = + surveyRepository.save(new BalanceSurvey("독립에 대한 고민이 깊어지는 요즘... 드디어 결정을 내렸다.", bundle)); + final BalanceSurvey survey3 = + surveyRepository.save( + new BalanceSurvey("바쁜 일상에 지쳐버린 나. 여가 시간을 더 의미 있게 보내고 싶어졌다.", bundle)); + final BalanceSurvey survey4 = + surveyRepository.save(new BalanceSurvey("회사에서 새로운 평가 시스템을 도입한다. 당신의 선택은?", bundle)); + final BalanceSurvey survey5 = + surveyRepository.save( + new BalanceSurvey("연애를 시작한지도 어연 3개월, 그 사람과 나의 연애는 꽤 잘 맞는다. 우리의 관계는...", bundle)); + + final SurveyOption option1 = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(survey1) + .content("자율 출퇴근제로 원하는 시간에 근무하며 창의적인 성과 내기") + .scores( + List.of( + KeywordScore.builder() + .keyword(SELF_DIRECTION) + .score(BigDecimal.ONE) + .build())) + .build()); + final SurveyOption option2 = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(survey2) + .content("내 취향대로 꾸민 집에서 자유롭게 생활하기") + .scores( + List.of( + KeywordScore.builder() + .keyword(SELF_DIRECTION) + .score(BigDecimal.ONE) + .build())) + .build()); + final SurveyOption option3 = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(survey3) + .content("매년 새로운 취미에 도전하며 색다른 즐거움 찾기") + .scores( + List.of( + KeywordScore.builder().keyword(STABILITY).score(BigDecimal.ONE).build())) + .build()); + final SurveyOption option4 = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(survey4) + .content("업무 성과에 따라 차등 보너스를 지급한다") + .scores( + List.of( + KeywordScore.builder().keyword(SUCCESS).score(BigDecimal.ONE).build())) + .build()); + final SurveyOption option5 = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(survey5) + .content("서로의 일상 속에서 따뜻하게 지지하는 관계") + .scores( + List.of( + KeywordScore.builder() + .keyword(BENEVOLENCE) + .score(BigDecimal.ONE) + .build())) + .build()); + + final List submissions = + surveySubmissionRepository.saveAll( + List.of( + SurveySubmission.builder().survey(survey1).selectedOption(option1).build(), + SurveySubmission.builder().survey(survey2).selectedOption(option2).build(), + SurveySubmission.builder().survey(survey3).selectedOption(option3).build(), + SurveySubmission.builder().survey(survey4).selectedOption(option4).build(), + SurveySubmission.builder().survey(survey5).selectedOption(option5).build())); + + final KeywordScores scores = + new KeywordScores(List.of(survey1, survey2, survey3, survey4, survey5)); + final CreateCharacterEvent event = + new CreateCharacterEvent(member, bundle, scores.getKeywordScores(), submissions); + + sut.createCharacter(event); + + assertAll( + () -> then(characterRecordRepository.findAll()).hasSize(1), + () -> then(valueReportRepository.findAll()).hasSize(4)); + } + } } From 17bd48224417e338b84f1eb187396bb9865e10e0 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sun, 16 Feb 2025 19:06:52 +0900 Subject: [PATCH 06/22] =?UTF-8?q?[#95]=20refactor:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EA=B0=9D=EC=B2=B4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CharacterRecordRepositoryTest.java | 171 +++--------------- 1 file changed, 27 insertions(+), 144 deletions(-) diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java index 30a61e27..f0ff65e7 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java @@ -2,38 +2,23 @@ import static org.assertj.core.api.BDDAssertions.then; import static org.junit.jupiter.api.Assertions.assertAll; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.BENEVOLENCE; import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SELF_DIRECTION; -import static org.nexters.jaknaesocore.domain.survey.model.Keyword.STABILITY; import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SUCCESS; import java.math.BigDecimal; import java.time.LocalDate; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.nexters.jaknaesocore.common.model.ScaledBigDecimal; import org.nexters.jaknaesocore.common.support.IntegrationTest; import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; import org.nexters.jaknaesocore.domain.character.model.ValueCharacter; import org.nexters.jaknaesocore.domain.character.model.ValueReport; -import org.nexters.jaknaesocore.domain.character.model.ValueReports; import org.nexters.jaknaesocore.domain.member.model.Member; import org.nexters.jaknaesocore.domain.member.repository.MemberRepository; -import org.nexters.jaknaesocore.domain.survey.model.BalanceSurvey; -import org.nexters.jaknaesocore.domain.survey.model.Keyword; -import org.nexters.jaknaesocore.domain.survey.model.KeywordMetrics; -import org.nexters.jaknaesocore.domain.survey.model.KeywordMetricsMap; -import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; -import org.nexters.jaknaesocore.domain.survey.model.KeywordWeightMap; import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; -import org.nexters.jaknaesocore.domain.survey.model.SurveyOption; -import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; import org.nexters.jaknaesocore.domain.survey.repository.SurveyBundleRepository; -import org.nexters.jaknaesocore.domain.survey.repository.SurveyOptionRepository; -import org.nexters.jaknaesocore.domain.survey.repository.SurveyRepository; -import org.nexters.jaknaesocore.domain.survey.repository.SurveySubmissionRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; @@ -48,18 +33,12 @@ class CharacterRecordRepositoryTest extends IntegrationTest { @Autowired private ValueCharacterRepository valueCharacterRepository; @Autowired private MemberRepository memberRepository; @Autowired private SurveyBundleRepository surveyBundleRepository; - @Autowired private SurveyRepository surveyRepository; - @Autowired private SurveyOptionRepository surveyOptionRepository; - @Autowired private SurveySubmissionRepository surveySubmissionRepository; @AfterEach void tearDown() { valueReportRepository.deleteAllInBatch(); sut.deleteAllInBatch(); valueCharacterRepository.deleteAllInBatch(); - surveySubmissionRepository.deleteAllInBatch(); - surveyOptionRepository.deleteAllInBatch(); - surveyRepository.deleteAllInBatch(); surveyBundleRepository.deleteAllInBatch(); memberRepository.deleteAllInBatch(); } @@ -68,36 +47,26 @@ void tearDown() { void 회원의_현재_캐릭터를_조회한다() { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); - final ValueCharacter valueCharacter1 = - valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); - final ValueCharacter valueCharacter2 = - valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); - final CharacterRecord characterRecord1 = - CharacterRecord.builder() - .characterNo("첫번째") - .valueCharacter(valueCharacter1) - .startDate(LocalDate.now().minusDays(31)) - .endDate(LocalDate.now().minusDays(16)) - .member(member) - .surveyBundle(bundle) - .build(); - final CharacterRecord characterRecord2 = - CharacterRecord.builder() - .characterNo("두번째") - .valueCharacter(valueCharacter2) - .startDate(LocalDate.now().minusDays(15)) - .endDate(LocalDate.now()) - .member(member) - .surveyBundle(bundle) - .build(); - sut.saveAll(List.of(characterRecord1, characterRecord2)); + + sut.saveAll( + List.of( + CharacterRecord.builder() + .characterNo("첫번째") + .endDate(LocalDate.now().minusDays(15)) + .member(member) + .surveyBundle(bundle) + .build(), + CharacterRecord.builder() + .characterNo("두번째") + .endDate(LocalDate.now()) + .member(member) + .surveyBundle(bundle) + .build())); final CharacterRecord actual = sut.findTopByMemberIdAndDeletedAtIsNullWithMember(member.getId()).get(); - then(actual) - .extracting("characterNo", "valueCharacter") - .containsExactly("두번째", valueCharacter2); + then(actual.getCharacterNo()).isEqualTo("두번째"); } @Test @@ -111,8 +80,6 @@ void tearDown() { CharacterRecord.builder() .characterNo("첫번째") .valueCharacter(valueCharacter) - .startDate(LocalDate.now().minusDays(31)) - .endDate(LocalDate.now().minusDays(16)) .member(member) .surveyBundle(bundle) .build()); @@ -129,17 +96,8 @@ void tearDown() { void 회원의_캐릭터를_설문_번들과_함께_조회한다() { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); - final ValueCharacter valueCharacter = - valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); - sut.save( - CharacterRecord.builder() - .characterNo("첫번째") - .valueCharacter(valueCharacter) - .startDate(LocalDate.now().minusDays(15)) - .endDate(LocalDate.now()) - .member(member) - .surveyBundle(bundle) - .build()); + + sut.save(CharacterRecord.builder().member(member).surveyBundle(bundle).build()); final List actual = sut.findByMemberIdAndDeletedAtIsNullWithMemberAndSurveyBundle(member.getId()); @@ -154,100 +112,25 @@ void tearDown() { void 회원의_캐릭터_분석_결과를_조회한다() { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); - final BalanceSurvey survey1 = - new BalanceSurvey( - "꿈에 그리던 드림 기업에 입사했다. 연봉도 좋지만, 무엇보다 회사의 근무 방식이 나와 잘 맞는 것 같다. 우리 회사의 근무 방식은...", bundle); - final SurveyOption option1 = - SurveyOption.builder() - .survey(survey1) - .content("자율 출퇴근제로 원하는 시간에 근무하며 창의적인 성과 내기") - .scores( - List.of( - KeywordScore.builder().keyword(SELF_DIRECTION).score(BigDecimal.ONE).build())) - .build(); - - final BalanceSurvey survey2 = new BalanceSurvey("독립에 대한 고민이 깊어지는 요즘... 드디어 결정을 내렸다.", bundle); - final SurveyOption option2 = - SurveyOption.builder() - .survey(survey2) - .content("내 취향대로 꾸민 집에서 자유롭게 생활하기") - .scores( - List.of( - KeywordScore.builder().keyword(SELF_DIRECTION).score(BigDecimal.ONE).build())) - .build(); - - final BalanceSurvey survey3 = - new BalanceSurvey("바쁜 일상에 지쳐버린 나. 여가 시간을 더 의미 있게 보내고 싶어졌다.", bundle); - final SurveyOption option3 = - SurveyOption.builder() - .survey(survey3) - .content("매년 새로운 취미에 도전하며 색다른 즐거움 찾기") - .scores( - List.of(KeywordScore.builder().keyword(STABILITY).score(BigDecimal.ONE).build())) - .build(); - - final BalanceSurvey survey4 = new BalanceSurvey("회사에서 새로운 평가 시스템을 도입한다. 당신의 선택은?", bundle); - final SurveyOption option4 = - SurveyOption.builder() - .survey(survey4) - .content("업무 성과에 따라 차등 보너스를 지급한다") - .scores(List.of(KeywordScore.builder().keyword(SUCCESS).score(BigDecimal.ONE).build())) - .build(); - - final BalanceSurvey survey5 = - new BalanceSurvey("연애를 시작한지도 어연 3개월, 그 사람과 나의 연애는 꽤 잘 맞는다. 우리의 관계는...", bundle); - final SurveyOption option5 = - SurveyOption.builder() - .survey(survey5) - .content("서로의 일상 속에서 따뜻하게 지지하는 관계") - .scores( - List.of(KeywordScore.builder().keyword(BENEVOLENCE).score(BigDecimal.ONE).build())) - .build(); - - final List submissions = - List.of( - SurveySubmission.builder().survey(survey1).selectedOption(option1).build(), - SurveySubmission.builder().survey(survey2).selectedOption(option2).build(), - SurveySubmission.builder().survey(survey3).selectedOption(option3).build(), - SurveySubmission.builder().survey(survey4).selectedOption(option4).build(), - SurveySubmission.builder().survey(survey5).selectedOption(option5).build()); - - final Map weights = new HashMap<>(); - weights.put(SELF_DIRECTION, BigDecimal.valueOf(5)); - weights.put(STABILITY, BigDecimal.valueOf(25)); - weights.put(SUCCESS, BigDecimal.valueOf(25)); - weights.put(BENEVOLENCE, BigDecimal.valueOf(5)); - - final List scores = - List.of( - KeywordScore.builder().keyword(SELF_DIRECTION).score(BigDecimal.valueOf(1)).build(), - KeywordScore.builder().keyword(STABILITY).score(BigDecimal.valueOf(1)).build(), - KeywordScore.builder().keyword(SUCCESS).score(BigDecimal.valueOf(1)).build(), - KeywordScore.builder().keyword(BENEVOLENCE).score(BigDecimal.valueOf(1)).build()); - - final Map metricsMap = KeywordMetricsMap.generate(scores); - final Map weightMap = KeywordWeightMap.generate(metricsMap); + final ValueReport valueReport = + valueReportRepository.save( + ValueReport.of(SELF_DIRECTION, ScaledBigDecimal.of(BigDecimal.valueOf(100)))); - final ValueCharacter valueCharacter = - valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); final CharacterRecord characterRecord = sut.save( CharacterRecord.builder() .characterNo("첫번째") - .valueCharacter(valueCharacter) - .startDate(LocalDate.now().minusDays(15)) - .endDate(LocalDate.now()) + .valueReports(List.of(valueReport)) .member(member) .surveyBundle(bundle) .build()); - List valueReports = - valueReportRepository.saveAll(ValueReports.report(weightMap, metricsMap, submissions)); - characterRecord.updateValueReports(valueReports); - final CharacterRecord actual = sut.findByIdAndDeletedAtIsNullWithValueReports(characterRecord.getId()).get(); - then(actual).extracting("valueReports").usingRecursiveComparison().isEqualTo(valueReports); + then(actual) + .extracting("valueReports") + .usingRecursiveComparison() + .isEqualTo(List.of(valueReport)); } } From 830c4cf0148b3e57c57a4ce5a994e30c5c203151 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sun, 16 Feb 2025 19:07:42 +0900 Subject: [PATCH 07/22] =?UTF-8?q?[#95]=20feat:=20=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EB=B8=94=20fetch=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/SurveySubmissionRepository.java | 8 +++++--- .../repository/SurveySubmissionRepositoryTest.java | 12 +++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/SurveySubmissionRepository.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/SurveySubmissionRepository.java index 9daa6077..bc03c971 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/SurveySubmissionRepository.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/SurveySubmissionRepository.java @@ -22,12 +22,14 @@ List findByMember_IdAndSurvey_SurveyBundle_Id( "SELECT s FROM SurveySubmission s " + "JOIN FETCH s.member sm JOIN FETCH s.survey ss JOIN FETCH ss.surveyBundle sb " + "WHERE sm.id = :memberId AND sb.id = :bundleId AND s.deletedAt IS NULL") - List findWithSurveyByMemberIdAndBundleIdAndDeletedAtIsNull( + List findByMemberIdAndBundleIdAndDeletedAtIsNullWithSurveyAndSurveyBundle( final Long memberId, final Long bundleId); @Query( "SELECT s FROM SurveySubmission s " - + "JOIN FETCH s.member sm JOIN FETCH s.survey ss JOIN FETCH ss.surveyBundle sb " + + "JOIN FETCH s.member sm JOIN FETCH s.survey ss " + + "JOIN FETCH ss.surveyBundle sb JOIN FETCH ss.options " + "WHERE sm.id = :memberId AND s.deletedAt IS NULL") - List findWithSurveyBundlesByMemberIdAndDeletedAtIsNull(final Long memberId); + List findByMemberIdAndDeletedAtIsNullWithSurveyAndSurveyBundleAndSurveyOption( + final Long memberId); } diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/repository/SurveySubmissionRepositoryTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/repository/SurveySubmissionRepositoryTest.java index 20245916..2359d2b5 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/repository/SurveySubmissionRepositoryTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/repository/SurveySubmissionRepositoryTest.java @@ -195,8 +195,9 @@ void findByMember_IdAndDeletedAtIsNull() { SurveySubmission.builder().member(member).survey(survey).selectedOption(option).build()); List actual = - surveySubmissionRepository.findWithSurveyByMemberIdAndBundleIdAndDeletedAtIsNull( - member.getId(), bundle.getId()); + surveySubmissionRepository + .findByMemberIdAndBundleIdAndDeletedAtIsNullWithSurveyAndSurveyBundle( + member.getId(), bundle.getId()); assertAll( () -> then(actual).hasSize(1), () -> then(actual.get(0).getSurvey()).isEqualTo(survey)); @@ -204,7 +205,7 @@ void findByMember_IdAndDeletedAtIsNull() { @Transactional @Test - void 회원이_참여한_설문_응답_리스트를_설문_번들과_함께_조회한다() { + void 회원이_참여한_설문_응답_리스트를_번들과_설문_옵션과_함께_조회한다() { Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); BalanceSurvey survey = @@ -228,8 +229,9 @@ void findByMember_IdAndDeletedAtIsNull() { SurveySubmission.builder().member(member).survey(survey).selectedOption(option).build()); List actual = - surveySubmissionRepository.findWithSurveyBundlesByMemberIdAndDeletedAtIsNull( - member.getId()); + surveySubmissionRepository + .findByMemberIdAndDeletedAtIsNullWithSurveyAndSurveyBundleAndSurveyOption( + member.getId()); assertAll( () -> then(actual).hasSize(1), From e93a695f2654b4697d017573153e6352104a8e42 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sun, 16 Feb 2025 19:27:11 +0900 Subject: [PATCH 08/22] =?UTF-8?q?[#95]=20feat:=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=20dto=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../survey/service/event/CreateCharacterEvent.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/event/CreateCharacterEvent.java diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/event/CreateCharacterEvent.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/event/CreateCharacterEvent.java new file mode 100644 index 00000000..b08cfd88 --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/event/CreateCharacterEvent.java @@ -0,0 +1,13 @@ +package org.nexters.jaknaesocore.domain.survey.service.event; + +import java.util.List; +import org.nexters.jaknaesocore.domain.member.model.Member; +import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; +import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; +import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; + +public record CreateCharacterEvent( + Member member, + SurveyBundle bundle, + List scores, + List submissions) {} From 709493b5983b2ec79ba050f5afa7fb1a2107cf14 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sun, 16 Feb 2025 21:15:05 +0900 Subject: [PATCH 09/22] =?UTF-8?q?[#95]=20feat:=20=EC=95=84=EC=A7=81=20?= =?UTF-8?q?=EC=99=84=EC=84=B1=EB=90=98=EC=A7=80=20=EC=95=8A=EC=9D=80=20?= =?UTF-8?q?=EC=BA=90=EB=A6=AD=ED=84=B0=EB=8F=84=20=EB=A6=AC=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EB=A1=9C=20=EC=A0=84=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../character/model/CharacterRecords.java | 17 ++++++++ .../character/service/CharacterService.java | 37 ++++++++++------- .../service/dto/CharactersResponse.java | 7 +--- .../service/dto/SimpleCharacterResponse.java | 7 ++++ .../service/dto/SimpleCharacterResponses.java | 34 ++++++++++++++++ .../character/model/CharacterRecordsTest.java | 40 +++++++++++++++++++ .../service/CharacterServiceTest.java | 37 +++++++++++++++-- .../controller/CharacterControllerTest.java | 7 +++- 8 files changed, 160 insertions(+), 26 deletions(-) create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecords.java create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java create mode 100644 jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecordsTest.java diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecords.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecords.java new file mode 100644 index 00000000..c7dfde60 --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecords.java @@ -0,0 +1,17 @@ +package org.nexters.jaknaesocore.domain.character.model; + +import java.util.List; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class CharacterRecords { + + private final List records; + + public boolean isIncompleteCharacter(final Long bundleId) { + if (bundleId == null) { + return false; + } + return records.stream().noneMatch(record -> record.getSurveyBundle().getId().equals(bundleId)); + } +} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java index fa2f945d..d12faae5 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java @@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j; import org.nexters.jaknaesocore.common.support.error.CustomException; import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; +import org.nexters.jaknaesocore.domain.character.model.CharacterRecords; import org.nexters.jaknaesocore.domain.character.model.Characters; import org.nexters.jaknaesocore.domain.character.model.ValueCharacter; import org.nexters.jaknaesocore.domain.character.repository.CharacterRecordRepository; @@ -17,9 +18,10 @@ import org.nexters.jaknaesocore.domain.character.service.dto.CharacterValueReportCommand; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterValueReportResponse; import org.nexters.jaknaesocore.domain.character.service.dto.CharactersResponse; -import org.nexters.jaknaesocore.domain.character.service.dto.CharactersResponse.SimpleCharacterResponse; +import org.nexters.jaknaesocore.domain.character.service.dto.SimpleCharacterResponses; import org.nexters.jaknaesocore.domain.member.repository.MemberRepository; import org.nexters.jaknaesocore.domain.survey.model.Keyword; +import org.nexters.jaknaesocore.domain.survey.repository.SurveySubmissionRepository; import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; @@ -34,6 +36,7 @@ public class CharacterService { private final MemberRepository memberRepository; private final CharacterRecordRepository characterRecordRepository; private final ValueCharacterRepository valueCharacterRepository; + private final SurveySubmissionRepository surveySubmissionRepository; private Map valueCharacters; @@ -85,19 +88,25 @@ public CharacterResponse getCurrentCharacter(final Long memberId) { public CharactersResponse getCharacters(final Long memberId) { memberRepository.findMember(memberId); - final List characters = - characterRecordRepository - .findByMemberIdAndDeletedAtIsNullWithMemberAndSurveyBundle(memberId) - .stream() - .map( - it -> - SimpleCharacterResponse.builder() - .characterNo(it.getCharacterNo()) - .characterId(it.getId()) - .bundleId(it.getSurveyBundle().getId()) - .build()) - .toList(); - return new CharactersResponse(characters); + final List records = + characterRecordRepository.findByMemberIdAndDeletedAtIsNullWithMemberAndSurveyBundle( + memberId); + final CharacterRecords characterRecords = new CharacterRecords(records); + final Long bundleId = getLatestBundleId(memberId); + + final SimpleCharacterResponses responses = new SimpleCharacterResponses(); + records.forEach(responses::addCompleteResponse); + if (characterRecords.isIncompleteCharacter(bundleId)) { + responses.addIncompleteResponse(bundleId); + } + return new CharactersResponse(responses.getResponses()); + } + + private Long getLatestBundleId(final Long memberId) { + return surveySubmissionRepository + .findTopByMember_IdAndDeletedAtIsNullOrderByCreatedAtDesc(memberId) + .map(it -> it.getSurvey().getSurveyBundle().getId()) + .orElse(null); } @Transactional(readOnly = true) diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/CharactersResponse.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/CharactersResponse.java index c0842c2a..ce7389ab 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/CharactersResponse.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/CharactersResponse.java @@ -1,10 +1,5 @@ package org.nexters.jaknaesocore.domain.character.service.dto; import java.util.List; -import lombok.Builder; -public record CharactersResponse(List characters) { - - @Builder - public record SimpleCharacterResponse(String characterNo, Long characterId, Long bundleId) {} -} +public record CharactersResponse(List characters) {} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java new file mode 100644 index 00000000..75af2dc0 --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java @@ -0,0 +1,7 @@ +package org.nexters.jaknaesocore.domain.character.service.dto; + +import lombok.Builder; + +@Builder +public record SimpleCharacterResponse( + String characterNo, Long characterId, Long bundleId, Boolean isCompleted) {} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java new file mode 100644 index 00000000..d83a1a50 --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java @@ -0,0 +1,34 @@ +package org.nexters.jaknaesocore.domain.character.service.dto; + +import java.util.ArrayList; +import java.util.List; +import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; + +public class SimpleCharacterResponses { + + private final List responses = new ArrayList<>(); + + public void addCompleteResponse(final CharacterRecord record) { + responses.add( + SimpleCharacterResponse.builder() + .characterNo(record.getCharacterNo()) + .characterId(record.getId()) + .bundleId(record.getSurveyBundle().getId()) + .isCompleted(true) + .build()); + } + + public void addIncompleteResponse(final Long bundleId) { + responses.add( + SimpleCharacterResponse.builder() + .characterNo("TODO") + .characterId(null) + .bundleId(bundleId) + .isCompleted(false) + .build()); + } + + public List getResponses() { + return responses; + } +} diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecordsTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecordsTest.java new file mode 100644 index 00000000..afff64cb --- /dev/null +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecordsTest.java @@ -0,0 +1,40 @@ +package org.nexters.jaknaesocore.domain.character.model; + +import static org.assertj.core.api.BDDAssertions.then; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.util.List; +import org.junit.jupiter.api.Test; +import org.nexters.jaknaesocore.common.support.IntegrationTest; +import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; +import org.nexters.jaknaesocore.domain.survey.repository.SurveyBundleRepository; +import org.springframework.beans.factory.annotation.Autowired; + +class CharacterRecordsTest extends IntegrationTest { + + @Autowired private SurveyBundleRepository surveyBundleRepository; + + @Test + void 번들_아이디로_캐릭터가_완성되었는지_확인한다() { + final SurveyBundle completeBundle1 = surveyBundleRepository.save(new SurveyBundle()); + final SurveyBundle completeBundle2 = surveyBundleRepository.save(new SurveyBundle()); + final SurveyBundle incompleteBundle = surveyBundleRepository.save(new SurveyBundle()); + final CharacterRecords characterRecords = + new CharacterRecords( + List.of( + CharacterRecord.builder().characterNo("첫번째").surveyBundle(completeBundle1).build(), + CharacterRecord.builder() + .characterNo("두번째") + .surveyBundle(completeBundle2) + .build())); + + final boolean actual1 = characterRecords.isIncompleteCharacter(completeBundle1.getId()); + final boolean actual2 = characterRecords.isIncompleteCharacter(completeBundle2.getId()); + final boolean actual3 = characterRecords.isIncompleteCharacter(incompleteBundle.getId()); + + assertAll( + () -> then(actual1).isEqualTo(false), + () -> then(actual2).isEqualTo(false), + () -> then(actual3).isEqualTo(true)); + } +} diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java index 0e86f480..7b56239e 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java @@ -200,7 +200,7 @@ class whenMemberFound { @DisplayName("회원의 캐릭터 리스트를 반환한다.") void shouldReturnCharacters() { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); - final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); + final SurveyBundle completeBundle = surveyBundleRepository.save(new SurveyBundle()); final ValueCharacter valueCharacter = valueCharacterRepository.save(new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", SUCCESS)); characterRecordRepository.save( @@ -210,17 +210,46 @@ void shouldReturnCharacters() { .startDate(LocalDate.now().minusDays(15)) .endDate(LocalDate.now()) .member(member) - .surveyBundle(bundle) + .surveyBundle(completeBundle) + .build()); + + final SurveyBundle incompleteBundle = surveyBundleRepository.save(new SurveyBundle()); + final BalanceSurvey survey = + surveyRepository.save( + new BalanceSurvey( + "꿈에 그리던 드림 기업에 입사했다. 연봉도 좋지만, 무엇보다 회사의 근무 방식이 나와 잘 맞는 것 같다. 우리 회사의 근무 방식은...", + incompleteBundle)); + final SurveyOption option = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(survey) + .content("자율 출퇴근제로 원하는 시간에 근무하며 창의적인 성과 내기") + .scores( + List.of( + KeywordScore.builder() + .keyword(SELF_DIRECTION) + .score(BigDecimal.ONE) + .build())) + .build()); + surveySubmissionRepository.save( + SurveySubmission.builder() + .survey(survey) + .member(member) + .selectedOption(option) .build()); final CharactersResponse actual = sut.getCharacters(member.getId()); assertAll( - () -> then(actual.characters()).hasSize(1), + () -> then(actual.characters()).hasSize(2), () -> then(actual.characters().get(0)) .extracting("characterNo", "bundleId") - .containsExactly("첫번째", bundle.getId())); + .containsExactly("첫번째", completeBundle.getId()), + () -> + then(actual.characters().get(1)) + .extracting("characterNo", "bundleId") + .containsExactly("TODO", incompleteBundle.getId())); // 추후 같이 수정 } } } diff --git a/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java b/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java index 51aae460..76cb161c 100644 --- a/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java +++ b/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java @@ -26,7 +26,7 @@ import org.nexters.jaknaesocore.domain.character.service.dto.CharacterValueReportCommand; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterValueReportResponse; import org.nexters.jaknaesocore.domain.character.service.dto.CharactersResponse; -import org.nexters.jaknaesocore.domain.character.service.dto.CharactersResponse.SimpleCharacterResponse; +import org.nexters.jaknaesocore.domain.character.service.dto.SimpleCharacterResponse; import org.nexters.jaknaesocore.domain.survey.model.Keyword; import org.nexters.jaknaesoserver.common.support.ControllerTest; import org.nexters.jaknaesoserver.common.support.WithMockCustomUser; @@ -75,10 +75,13 @@ class CharacterControllerTest extends ControllerTest { .description("캐릭터 회차"), fieldWithPath("data.characters[].characterId") .type(SimpleType.NUMBER) - .description("캐릭터 아이디"), + .description("캐릭터 아이디 (캐릭터가 완성되지 않은 경우 null)"), fieldWithPath("data.characters[].bundleId") .type(SimpleType.NUMBER) .description("설문 번들 아이디"), + fieldWithPath("data.characters[].isCompleted") + .type(SimpleType.BOOLEAN) + .description("설문 번들 완료 여부"), fieldWithPath("error").description("에러").optional()) .responseSchema(schema("CharactersResponse")) .build()))); From c9e7767a0ad6df6ef9cd5a5db21d07424888b0f4 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sun, 16 Feb 2025 21:26:33 +0900 Subject: [PATCH 10/22] =?UTF-8?q?[#95]=20refactor:=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EA=B0=9D=EC=B2=B4=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../character/model/CharacterRecords.java | 17 ------- .../character/service/CharacterService.java | 10 +--- .../service/dto/SimpleCharacterResponses.java | 49 ++++++++++++------- .../character/model/CharacterRecordsTest.java | 40 --------------- 4 files changed, 33 insertions(+), 83 deletions(-) delete mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecords.java delete mode 100644 jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecordsTest.java diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecords.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecords.java deleted file mode 100644 index c7dfde60..00000000 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecords.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.nexters.jaknaesocore.domain.character.model; - -import java.util.List; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -public class CharacterRecords { - - private final List records; - - public boolean isIncompleteCharacter(final Long bundleId) { - if (bundleId == null) { - return false; - } - return records.stream().noneMatch(record -> record.getSurveyBundle().getId().equals(bundleId)); - } -} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java index d12faae5..5e503ec0 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java @@ -8,7 +8,6 @@ import lombok.extern.slf4j.Slf4j; import org.nexters.jaknaesocore.common.support.error.CustomException; import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; -import org.nexters.jaknaesocore.domain.character.model.CharacterRecords; import org.nexters.jaknaesocore.domain.character.model.Characters; import org.nexters.jaknaesocore.domain.character.model.ValueCharacter; import org.nexters.jaknaesocore.domain.character.repository.CharacterRecordRepository; @@ -91,14 +90,9 @@ public CharactersResponse getCharacters(final Long memberId) { final List records = characterRecordRepository.findByMemberIdAndDeletedAtIsNullWithMemberAndSurveyBundle( memberId); - final CharacterRecords characterRecords = new CharacterRecords(records); - final Long bundleId = getLatestBundleId(memberId); - final SimpleCharacterResponses responses = new SimpleCharacterResponses(); - records.forEach(responses::addCompleteResponse); - if (characterRecords.isIncompleteCharacter(bundleId)) { - responses.addIncompleteResponse(bundleId); - } + final SimpleCharacterResponses responses = + new SimpleCharacterResponses(getLatestBundleId(memberId), records); return new CharactersResponse(responses.getResponses()); } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java index d83a1a50..8caa41cd 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java @@ -1,31 +1,44 @@ package org.nexters.jaknaesocore.domain.character.service.dto; -import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; public class SimpleCharacterResponses { - private final List responses = new ArrayList<>(); + private List responses; - public void addCompleteResponse(final CharacterRecord record) { - responses.add( - SimpleCharacterResponse.builder() - .characterNo(record.getCharacterNo()) - .characterId(record.getId()) - .bundleId(record.getSurveyBundle().getId()) - .isCompleted(true) - .build()); + public SimpleCharacterResponses(final Long latestBundleId, final List records) { + this.responses = records.stream().map(this::toCompletedResponse).collect(Collectors.toList()); + + if (isIncompleteCharacter(latestBundleId, records)) { + this.responses.add(toIncompleteResponse(latestBundleId)); + } + } + + private boolean isIncompleteCharacter(final Long bundleId, final List records) { + return bundleId != null + && records.stream() + .noneMatch(record -> Objects.equals(record.getSurveyBundle().getId(), bundleId)); + } + + private SimpleCharacterResponse toCompletedResponse(final CharacterRecord record) { + return SimpleCharacterResponse.builder() + .characterNo(record.getCharacterNo()) + .characterId(record.getId()) + .bundleId(record.getSurveyBundle().getId()) + .isCompleted(true) + .build(); } - public void addIncompleteResponse(final Long bundleId) { - responses.add( - SimpleCharacterResponse.builder() - .characterNo("TODO") - .characterId(null) - .bundleId(bundleId) - .isCompleted(false) - .build()); + private SimpleCharacterResponse toIncompleteResponse(final Long bundleId) { + return SimpleCharacterResponse.builder() + .characterNo("TODO") + .characterId(null) + .bundleId(bundleId) + .isCompleted(false) + .build(); } public List getResponses() { diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecordsTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecordsTest.java deleted file mode 100644 index afff64cb..00000000 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecordsTest.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.nexters.jaknaesocore.domain.character.model; - -import static org.assertj.core.api.BDDAssertions.then; -import static org.junit.jupiter.api.Assertions.assertAll; - -import java.util.List; -import org.junit.jupiter.api.Test; -import org.nexters.jaknaesocore.common.support.IntegrationTest; -import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; -import org.nexters.jaknaesocore.domain.survey.repository.SurveyBundleRepository; -import org.springframework.beans.factory.annotation.Autowired; - -class CharacterRecordsTest extends IntegrationTest { - - @Autowired private SurveyBundleRepository surveyBundleRepository; - - @Test - void 번들_아이디로_캐릭터가_완성되었는지_확인한다() { - final SurveyBundle completeBundle1 = surveyBundleRepository.save(new SurveyBundle()); - final SurveyBundle completeBundle2 = surveyBundleRepository.save(new SurveyBundle()); - final SurveyBundle incompleteBundle = surveyBundleRepository.save(new SurveyBundle()); - final CharacterRecords characterRecords = - new CharacterRecords( - List.of( - CharacterRecord.builder().characterNo("첫번째").surveyBundle(completeBundle1).build(), - CharacterRecord.builder() - .characterNo("두번째") - .surveyBundle(completeBundle2) - .build())); - - final boolean actual1 = characterRecords.isIncompleteCharacter(completeBundle1.getId()); - final boolean actual2 = characterRecords.isIncompleteCharacter(completeBundle2.getId()); - final boolean actual3 = characterRecords.isIncompleteCharacter(incompleteBundle.getId()); - - assertAll( - () -> then(actual1).isEqualTo(false), - () -> then(actual2).isEqualTo(false), - () -> then(actual3).isEqualTo(true)); - } -} From 85a1eaa90817ddef9b5394e3660924285e54bdbb Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Sun, 16 Feb 2025 23:39:18 +0900 Subject: [PATCH 11/22] =?UTF-8?q?[#95]=20feat:=20=EC=BA=90=EB=A6=AD?= =?UTF-8?q?=ED=84=B0=20=EC=83=9D=EC=84=B1=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=98=B8=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../survey/repository/SurveyRepository.java | 4 + .../domain/survey/service/SurveyService.java | 50 ++- .../survey/service/SurveyServiceTest.java | 352 ++++++++++++------ 3 files changed, 295 insertions(+), 111 deletions(-) diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/SurveyRepository.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/SurveyRepository.java index a0bad312..13ba159b 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/SurveyRepository.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/SurveyRepository.java @@ -1,6 +1,7 @@ package org.nexters.jaknaesocore.domain.survey.repository; import java.util.List; +import java.util.Optional; import org.nexters.jaknaesocore.domain.survey.model.Survey; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -9,4 +10,7 @@ public interface SurveyRepository extends JpaRepository { @Query("SELECT s FROM Survey s JOIN FETCH s.options WHERE s.id IN :surveyIds") List findAllByIdWithOptions(List surveyIds); + + @Query("SELECT s FROM Survey s JOIN FETCH s.surveyBundle WHERE s.id = :id") + Optional findByIdWithSurveyBundle(final Long id); } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/SurveyService.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/SurveyService.java index 0e05609b..16bb048f 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/SurveyService.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/SurveyService.java @@ -2,7 +2,10 @@ import java.time.LocalDate; import java.time.LocalDateTime; -import java.util.*; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; @@ -10,12 +13,29 @@ import org.nexters.jaknaesocore.common.support.error.CustomException; import org.nexters.jaknaesocore.domain.member.model.Member; import org.nexters.jaknaesocore.domain.member.repository.MemberRepository; -import org.nexters.jaknaesocore.domain.survey.dto.*; -import org.nexters.jaknaesocore.domain.survey.model.*; +import org.nexters.jaknaesocore.domain.survey.dto.OnboardingSubmissionResult; +import org.nexters.jaknaesocore.domain.survey.dto.OnboardingSubmissionsCommand; +import org.nexters.jaknaesocore.domain.survey.dto.OnboardingSurveyResponse; +import org.nexters.jaknaesocore.domain.survey.dto.SurveyHistoryDetailResponse; +import org.nexters.jaknaesocore.domain.survey.dto.SurveyHistoryResponse; +import org.nexters.jaknaesocore.domain.survey.dto.SurveyResponse; +import org.nexters.jaknaesocore.domain.survey.dto.SurveySubmissionCommand; +import org.nexters.jaknaesocore.domain.survey.dto.SurveySubmissionHistoryCommand; +import org.nexters.jaknaesocore.domain.survey.dto.SurveySubmissionHistoryResponse; +import org.nexters.jaknaesocore.domain.survey.model.KeywordScores; +import org.nexters.jaknaesocore.domain.survey.model.OnboardingSurvey; +import org.nexters.jaknaesocore.domain.survey.model.Survey; +import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; +import org.nexters.jaknaesocore.domain.survey.model.SurveyOption; +import org.nexters.jaknaesocore.domain.survey.model.SurveyRecord; +import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; +import org.nexters.jaknaesocore.domain.survey.model.SurveySubmissions; import org.nexters.jaknaesocore.domain.survey.repository.OnboardingSurveyRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveyBundleRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveyRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveySubmissionRepository; +import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -28,6 +48,7 @@ public class SurveyService { private final SurveySubmissionRepository surveySubmissionRepository; private final SurveyRepository surveyRepository; private final OnboardingSurveyRepository onboardingSurveyRepository; + private final ApplicationEventPublisher eventPublisher; @Transactional(readOnly = true) public SurveyResponse getNextSurvey(final Long bundleId, final Long memberId) { @@ -123,7 +144,7 @@ private SurveyHistoryResponse getNextBundleHistory(List submis public void submitSurvey(SurveySubmissionCommand command, LocalDateTime submittedAt) { Survey survey = surveyRepository - .findById(command.surveyId()) + .findByIdWithSurveyBundle(command.surveyId()) .orElseThrow(() -> CustomException.SURVEY_NOT_FOUND); SurveyOption surveyOption = survey.getOptionById(command.optionId()); Member member = @@ -135,6 +156,15 @@ public void submitSurvey(SurveySubmissionCommand command, LocalDateTime submitte SurveySubmission.create(member, survey, surveyOption, command.comment(), submittedAt); surveySubmissionRepository.save(surveySubmission); + + final SurveyBundle bundle = survey.getSurveyBundle(); + final List submissions = + surveySubmissionRepository + .findByMemberIdAndBundleIdAndDeletedAtIsNullWithSurveyAndSurveyBundle( + member.getId(), bundle.getId()); + if (bundle.isAllSubmitted(submissions)) { + publishCreateCharacterEvent(member, bundle, submissions); + } } @Transactional(readOnly = true) @@ -174,6 +204,18 @@ public void submitOnboardingSurvey( surveySubmissionRepository.saveAll(submissions); member.completeOnboarding(submittedAt); + + // FIXME: 확인 후 주석 제거 필요 (온보딩 번들 전달) + // createCharacter(member, null, submissions); + } + + private void publishCreateCharacterEvent( + final Member member, final SurveyBundle bundle, final List submissions) { + final List surveys = submissions.stream().map(SurveySubmission::getSurvey).toList(); + final KeywordScores scores = new KeywordScores(surveys); + + eventPublisher.publishEvent( + new CreateCharacterEvent(member, bundle, scores.getKeywordScores(), submissions)); } private Member getMember(Long memberId) { diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java index 2540accb..8b418284 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java @@ -1,27 +1,52 @@ package org.nexters.jaknaesocore.domain.survey.service; -import static org.assertj.core.api.BDDAssertions.*; +import static org.assertj.core.api.BDDAssertions.then; +import static org.assertj.core.api.BDDAssertions.thenThrownBy; +import static org.assertj.core.api.BDDAssertions.tuple; +import static org.mockito.BDDMockito.any; +import static org.mockito.BDDMockito.never; +import static org.mockito.BDDMockito.verify; +import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SELF_DIRECTION; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.List; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; import org.nexters.jaknaesocore.common.support.IntegrationTest; import org.nexters.jaknaesocore.common.support.error.CustomException; +import org.nexters.jaknaesocore.domain.character.repository.CharacterRecordRepository; +import org.nexters.jaknaesocore.domain.character.repository.ValueReportRepository; +import org.nexters.jaknaesocore.domain.character.service.CharacterService; import org.nexters.jaknaesocore.domain.member.model.Member; import org.nexters.jaknaesocore.domain.member.repository.MemberRepository; -import org.nexters.jaknaesocore.domain.survey.dto.*; -import org.nexters.jaknaesocore.domain.survey.model.*; +import org.nexters.jaknaesocore.domain.survey.dto.OnboardingSubmissionResult; +import org.nexters.jaknaesocore.domain.survey.dto.OnboardingSubmissionsCommand; +import org.nexters.jaknaesocore.domain.survey.dto.OnboardingSurveyResponse; +import org.nexters.jaknaesocore.domain.survey.dto.SurveyHistoryResponse; +import org.nexters.jaknaesocore.domain.survey.dto.SurveyResponse; +import org.nexters.jaknaesocore.domain.survey.dto.SurveySubmissionCommand; +import org.nexters.jaknaesocore.domain.survey.dto.SurveySubmissionHistoryCommand; +import org.nexters.jaknaesocore.domain.survey.dto.SurveySubmissionHistoryResponse; import org.nexters.jaknaesocore.domain.survey.model.BalanceSurvey; import org.nexters.jaknaesocore.domain.survey.model.Keyword; import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; +import org.nexters.jaknaesocore.domain.survey.model.MultipleChoiceSurvey; +import org.nexters.jaknaesocore.domain.survey.model.OnboardingSurvey; import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; import org.nexters.jaknaesocore.domain.survey.model.SurveyOption; +import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; import org.nexters.jaknaesocore.domain.survey.repository.SurveyBundleRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveyOptionRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveyRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveySubmissionRepository; +import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; +import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.bean.override.mockito.MockitoSpyBean; import org.springframework.transaction.annotation.Transactional; class SurveyServiceTest extends IntegrationTest { @@ -33,9 +58,15 @@ class SurveyServiceTest extends IntegrationTest { @Autowired private SurveyBundleRepository surveyBundleRepository; @Autowired private SurveyRepository surveyRepository; @Autowired private SurveyOptionRepository surveyOptionRepository; + @Autowired private CharacterRecordRepository characterRecordRepository; + @Autowired private ValueReportRepository valueReportRepository; + + @MockitoSpyBean private CharacterService characterService; @AfterEach void tearDown() { + valueReportRepository.deleteAllInBatch(); + characterRecordRepository.deleteAllInBatch(); surveySubmissionRepository.deleteAllInBatch(); surveyOptionRepository.deleteAllInBatch(); surveyRepository.deleteAllInBatch(); @@ -77,109 +108,6 @@ void getNextSurvey() { .containsExactly(tuple(option.getId(), "질문 옵션 내용")); } - @DisplayName("submitSurvey 메서드는") - @Nested - class submitSurvey { - - @DisplayName("회원이 존재하지 않으면") - @Nested - class whenMemberNotFound { - @Test - @DisplayName("예외를 발생시킨다") - void throwMemberNotFoundException() { - // given - Member member = Member.create("나민혁", "test@test.com"); - memberRepository.save(member); - SurveyBundle surveyBundle = new SurveyBundle(); - surveyBundleRepository.save(surveyBundle); - BalanceSurvey balanceSurvey = new BalanceSurvey("질문내용", surveyBundle); - surveyRepository.save(balanceSurvey); - List scores = - List.of( - KeywordScore.builder().keyword(Keyword.ADVENTURE).score(BigDecimal.ONE).build(), - KeywordScore.builder().keyword(Keyword.BENEVOLENCE).score(BigDecimal.TWO).build()); - SurveyOption option = - SurveyOption.builder().survey(balanceSurvey).scores(scores).content("질문 옵션 내용").build(); - surveyOptionRepository.save(option); - - SurveySubmissionCommand command = - new SurveySubmissionCommand(option.getId(), balanceSurvey.getId(), 0L, "나는 행복한게 좋으니까"); - - // when - // then - thenThrownBy(() -> surveyService.submitSurvey(command, LocalDateTime.now())) - .isEqualTo(CustomException.MEMBER_NOT_FOUND); - } - } - - @DisplayName("설문을 저장한다") - @Nested - class shouldSubmitted { - @Test - void 설문에_응답을_제출한다() { - // given - Member member = Member.create("나민혁", "test@test.com"); - memberRepository.save(member); - SurveyBundle surveyBundle = new SurveyBundle(); - surveyBundleRepository.save(surveyBundle); - BalanceSurvey balanceSurvey = new BalanceSurvey("질문내용", surveyBundle); - surveyRepository.save(balanceSurvey); - List scores = - List.of( - KeywordScore.builder().keyword(Keyword.ADVENTURE).score(BigDecimal.ONE).build(), - KeywordScore.builder().keyword(Keyword.BENEVOLENCE).score(BigDecimal.TWO).build()); - SurveyOption option = - SurveyOption.builder().survey(balanceSurvey).scores(scores).content("질문 옵션 내용").build(); - surveyOptionRepository.save(option); - - SurveySubmissionCommand command = - new SurveySubmissionCommand( - option.getId(), balanceSurvey.getId(), member.getId(), "나는 행복한게 좋으니까"); - - // when - LocalDateTime submittedAt = LocalDateTime.of(2025, 2, 13, 18, 0, 0); - surveyService.submitSurvey(command, submittedAt); - // then - List submissions = surveySubmissionRepository.findAll(); - then(submissions).hasSize(1); - then(submissions.getFirst()) - .extracting("member.id", "survey.id", "selectedOption.id", "retrospective") - .containsExactly(member.getId(), balanceSurvey.getId(), option.getId(), "나는 행복한게 좋으니까"); - } - } - - @DisplayName("설문이 존재하지 않으면") - @Nested - class whenSurveyNotFound { - @Test - @DisplayName("예외를 발생시킨다") - void throwSurveyNotFoundException() { - // given - Member member = Member.create("나민혁", "test@test.com"); - memberRepository.save(member); - SurveyBundle surveyBundle = new SurveyBundle(); - surveyBundleRepository.save(surveyBundle); - BalanceSurvey balanceSurvey = new BalanceSurvey("질문내용", surveyBundle); - surveyRepository.save(balanceSurvey); - List scores = - List.of( - KeywordScore.builder().keyword(Keyword.ADVENTURE).score(BigDecimal.ONE).build(), - KeywordScore.builder().keyword(Keyword.BENEVOLENCE).score(BigDecimal.TWO).build()); - SurveyOption option = - SurveyOption.builder().survey(balanceSurvey).scores(scores).content("질문 옵션 내용").build(); - surveyOptionRepository.save(option); - - SurveySubmissionCommand command = - new SurveySubmissionCommand(0L, member.getId(), option.getId(), "나는 행복한게 좋으니까"); - - // when - // then - thenThrownBy(() -> surveyService.submitSurvey(command, LocalDateTime.now())) - .isEqualTo(CustomException.SURVEY_NOT_FOUND); - } - } - } - @Disabled("클라이언트의 온보딩 작업이 완료되면 테스트를 진행합니다.") @Test void 설문_기록이_없으면_접근_할_수_없다() { @@ -701,6 +629,216 @@ void throwSurveyNotFoundException() { then(member).extracting("completedOnboardingAt").isEqualTo(submittedAt); } + @DisplayName("submitSurvey 메서드는") + @Nested + class submitSurvey { + + @DisplayName("회원이 존재하지 않으면") + @Nested + class whenMemberNotFound { + + @Test + @DisplayName("예외를 발생시킨다") + void throwMemberNotFoundException() { + // given + Member member = Member.create("나민혁", "test@test.com"); + memberRepository.save(member); + SurveyBundle surveyBundle = new SurveyBundle(); + surveyBundleRepository.save(surveyBundle); + BalanceSurvey balanceSurvey = new BalanceSurvey("질문내용", surveyBundle); + surveyRepository.save(balanceSurvey); + List scores = + List.of( + KeywordScore.builder().keyword(Keyword.ADVENTURE).score(BigDecimal.ONE).build(), + KeywordScore.builder().keyword(Keyword.BENEVOLENCE).score(BigDecimal.TWO).build()); + SurveyOption option = + SurveyOption.builder().survey(balanceSurvey).scores(scores).content("질문 옵션 내용").build(); + surveyOptionRepository.save(option); + + SurveySubmissionCommand command = + new SurveySubmissionCommand(option.getId(), balanceSurvey.getId(), 0L, "나는 행복한게 좋으니까"); + + // when + // then + thenThrownBy(() -> surveyService.submitSurvey(command, LocalDateTime.now())) + .isEqualTo(CustomException.MEMBER_NOT_FOUND); + } + } + + @DisplayName("설문을 저장한다") + @Nested + class shouldSubmitted { + + @Test + void 설문에_응답을_제출한다() { + // given + Member member = Member.create("나민혁", "test@test.com"); + memberRepository.save(member); + SurveyBundle surveyBundle = new SurveyBundle(); + surveyBundleRepository.save(surveyBundle); + BalanceSurvey balanceSurvey = new BalanceSurvey("질문내용", surveyBundle); + surveyRepository.save(balanceSurvey); + List scores = + List.of( + KeywordScore.builder().keyword(Keyword.ADVENTURE).score(BigDecimal.ONE).build(), + KeywordScore.builder().keyword(Keyword.BENEVOLENCE).score(BigDecimal.TWO).build()); + SurveyOption option = + SurveyOption.builder().survey(balanceSurvey).scores(scores).content("질문 옵션 내용").build(); + surveyOptionRepository.save(option); + + SurveySubmissionCommand command = + new SurveySubmissionCommand( + option.getId(), balanceSurvey.getId(), member.getId(), "나는 행복한게 좋으니까"); + + // when + LocalDateTime submittedAt = LocalDateTime.of(2025, 2, 13, 18, 0, 0); + surveyService.submitSurvey(command, submittedAt); + // then + List submissions = surveySubmissionRepository.findAll(); + then(submissions).hasSize(1); + then(submissions.getFirst()) + .extracting("member.id", "survey.id", "selectedOption.id", "retrospective") + .containsExactly(member.getId(), balanceSurvey.getId(), option.getId(), "나는 행복한게 좋으니까"); + } + } + + @DisplayName("설문이 존재하지 않으면") + @Nested + class whenSurveyNotFound { + + @Test + @DisplayName("예외를 발생시킨다") + void throwSurveyNotFoundException() { + // given + Member member = Member.create("나민혁", "test@test.com"); + memberRepository.save(member); + SurveyBundle surveyBundle = new SurveyBundle(); + surveyBundleRepository.save(surveyBundle); + BalanceSurvey balanceSurvey = new BalanceSurvey("질문내용", surveyBundle); + surveyRepository.save(balanceSurvey); + List scores = + List.of( + KeywordScore.builder().keyword(Keyword.ADVENTURE).score(BigDecimal.ONE).build(), + KeywordScore.builder().keyword(Keyword.BENEVOLENCE).score(BigDecimal.TWO).build()); + SurveyOption option = + SurveyOption.builder().survey(balanceSurvey).scores(scores).content("질문 옵션 내용").build(); + surveyOptionRepository.save(option); + + SurveySubmissionCommand command = + new SurveySubmissionCommand(0L, member.getId(), option.getId(), "나는 행복한게 좋으니까"); + + // when + // then + thenThrownBy(() -> surveyService.submitSurvey(command, LocalDateTime.now())) + .isEqualTo(CustomException.SURVEY_NOT_FOUND); + } + } + + @DisplayName("회원과 설문을 찾았고") + @Nested + class whenMemberAndSurveyFound { + + @DisplayName("설문 번들의 모든 설문 응답을 제출하였다면") + @Nested + class whenSurveyBundleIsCompleted { + + @DisplayName("캐릭터를 생성한다.") + @Test + void shouldCreateCharacter() { + final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); + final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); + + final BalanceSurvey survey = + surveyRepository.save( + new BalanceSurvey( + "꿈에 그리던 드림 기업에 입사했다. 연봉도 좋지만, 무엇보다 회사의 근무 방식이 나와 잘 맞는 것 같다. 우리 회사의 근무 방식은...", + bundle)); + final SurveyOption option = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(survey) + .content("자율 출퇴근제로 원하는 시간에 근무하며 창의적인 성과 내기") + .scores( + List.of( + KeywordScore.builder() + .keyword(SELF_DIRECTION) + .score(BigDecimal.ONE) + .build())) + .build()); + + final SurveySubmissionCommand command = + new SurveySubmissionCommand( + option.getId(), + survey.getId(), + member.getId(), + "자유롭게 일하면 집중이 잘되는 시간에 일할 수 있기 때문에 일의 능률이 오를 것 같다."); + final LocalDateTime submittedAt = LocalDateTime.of(2025, 2, 17, 0, 0, 0); + + surveyService.submitSurvey(command, submittedAt); + + verify(characterService).createCharacter(any(CreateCharacterEvent.class)); + } + } + + @DisplayName("설문 번들의 설문 응답이 남아있다면") + @Nested + class whenSurveyBundleIsInProgress { + + @DisplayName("캐릭터를 생성하지 않는다.") + @Test + void shouldNotCreateCharacter() { + final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); + final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); + + final BalanceSurvey survey1 = + surveyRepository.save( + new BalanceSurvey( + "꿈에 그리던 드림 기업에 입사했다. 연봉도 좋지만, 무엇보다 회사의 근무 방식이 나와 잘 맞는 것 같다. 우리 회사의 근무 방식은...", + bundle)); + final BalanceSurvey survey2 = + surveyRepository.save( + new BalanceSurvey("독립에 대한 고민이 깊어지는 요즘... 드디어 결정을 내렸다.", bundle)); + final SurveyOption option1 = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(survey1) + .content("자율 출퇴근제로 원하는 시간에 근무하며 창의적인 성과 내기") + .scores( + List.of( + KeywordScore.builder() + .keyword(SELF_DIRECTION) + .score(BigDecimal.ONE) + .build())) + .build()); + final SurveyOption option2 = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(survey2) + .content("내 취향대로 꾸민 집에서 자유롭게 생활하기") + .scores( + List.of( + KeywordScore.builder() + .keyword(SELF_DIRECTION) + .score(BigDecimal.ONE) + .build())) + .build()); + + final SurveySubmissionCommand command = + new SurveySubmissionCommand( + option1.getId(), + survey1.getId(), + member.getId(), + "자유롭게 일하면 집중이 잘되는 시간에 일할 수 있기 때문에 일의 능률이 오를 것 같다."); + final LocalDateTime submittedAt = LocalDateTime.of(2025, 2, 17, 0, 0, 0); + + surveyService.submitSurvey(command, submittedAt); + + verify(characterService, never()).createCharacter(any(CreateCharacterEvent.class)); + } + } + } + } + @Test void 마지막_제출이_온보딩일_경우_당일이어도_질문에_대한_응답이_가능하다() { // given From f1d9b9d418041dd2d0723dfffeb450d666aa879d Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Mon, 17 Feb 2025 00:13:35 +0900 Subject: [PATCH 12/22] =?UTF-8?q?[#95]=20fix:=20rebase=20=EC=A4=91=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=EB=90=9C=20=EC=BD=94=EB=93=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jaknaesocore/domain/survey/service/SurveyServiceTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java index 8b418284..11a3c7cd 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java @@ -44,7 +44,6 @@ import org.nexters.jaknaesocore.domain.survey.repository.SurveyRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveySubmissionRepository; import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; -import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.bean.override.mockito.MockitoSpyBean; import org.springframework.transaction.annotation.Transactional; From d10ff596595c1b477883ba04bd690c5be359a29d Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Mon, 17 Feb 2025 00:14:51 +0900 Subject: [PATCH 13/22] =?UTF-8?q?[#95]=20chore:=20=EB=88=84=EB=9D=BD?= =?UTF-8?q?=EB=90=9C=20ddl=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 누락했거나 오류 있는 ddl 수정 --- ...1_alter_table_member_add_name_col_add_email_col.sql | 2 +- .../sql/057/002_create_table_character_record.sql | 3 ++- .../057/003_create_table_character_value_report.sql | 10 +++++----- ...acter_record_drop_type_col_drop_description_col.sql | 3 +++ ...ble_character_record_add_value_character_id_col.sql | 2 ++ 5 files changed, 13 insertions(+), 7 deletions(-) create mode 100644 jaknaeso-core/src/main/resources/sql/093/002_alter_table_character_record_drop_type_col_drop_description_col.sql create mode 100644 jaknaeso-core/src/main/resources/sql/093/003_alter_table_character_record_add_value_character_id_col.sql diff --git a/jaknaeso-core/src/main/resources/sql/037/001_alter_table_member_add_name_col_add_email_col.sql b/jaknaeso-core/src/main/resources/sql/037/001_alter_table_member_add_name_col_add_email_col.sql index 64f2a78c..272f5966 100644 --- a/jaknaeso-core/src/main/resources/sql/037/001_alter_table_member_add_name_col_add_email_col.sql +++ b/jaknaeso-core/src/main/resources/sql/037/001_alter_table_member_add_name_col_add_email_col.sql @@ -1,3 +1,3 @@ alter table member - add name varchar(60) + add name varchar(60), add email varchar(255); \ No newline at end of file diff --git a/jaknaeso-core/src/main/resources/sql/057/002_create_table_character_record.sql b/jaknaeso-core/src/main/resources/sql/057/002_create_table_character_record.sql index bb6c2099..47cba915 100644 --- a/jaknaeso-core/src/main/resources/sql/057/002_create_table_character_record.sql +++ b/jaknaeso-core/src/main/resources/sql/057/002_create_table_character_record.sql @@ -6,7 +6,8 @@ create table if not exists character_record description varchar(255), start_date date, end_date date, - bundle_id bigint, + bundle_id bigint not null, + member_id bigint not null, created_at timestamp(6), updated_at timestamp(6), deleted_at timestamp(6) diff --git a/jaknaeso-core/src/main/resources/sql/057/003_create_table_character_value_report.sql b/jaknaeso-core/src/main/resources/sql/057/003_create_table_character_value_report.sql index 7dc3849a..e23b4095 100644 --- a/jaknaeso-core/src/main/resources/sql/057/003_create_table_character_value_report.sql +++ b/jaknaeso-core/src/main/resources/sql/057/003_create_table_character_value_report.sql @@ -1,8 +1,8 @@ create table if not exists character_value_report ( - id bigint auto_increment primary key, - character_id bigint, - created_at timestamp(6), - updated_at timestamp(6), - deleted_at timestamp(6) + id bigint auto_increment primary key, + character_record_id bigint, + created_at timestamp(6), + updated_at timestamp(6), + deleted_at timestamp(6) ); \ No newline at end of file diff --git a/jaknaeso-core/src/main/resources/sql/093/002_alter_table_character_record_drop_type_col_drop_description_col.sql b/jaknaeso-core/src/main/resources/sql/093/002_alter_table_character_record_drop_type_col_drop_description_col.sql new file mode 100644 index 00000000..4bf324fb --- /dev/null +++ b/jaknaeso-core/src/main/resources/sql/093/002_alter_table_character_record_drop_type_col_drop_description_col.sql @@ -0,0 +1,3 @@ +alter table character_record + drop column type, + drop column description; \ No newline at end of file diff --git a/jaknaeso-core/src/main/resources/sql/093/003_alter_table_character_record_add_value_character_id_col.sql b/jaknaeso-core/src/main/resources/sql/093/003_alter_table_character_record_add_value_character_id_col.sql new file mode 100644 index 00000000..ec4d030a --- /dev/null +++ b/jaknaeso-core/src/main/resources/sql/093/003_alter_table_character_record_add_value_character_id_col.sql @@ -0,0 +1,2 @@ +alter table character_record + add value_character_id bigint; \ No newline at end of file From 2b958539b6006580e5ff9387161b39a467e323c5 Mon Sep 17 00:00:00 2001 From: kimyu0218 Date: Mon, 17 Feb 2025 00:15:21 +0900 Subject: [PATCH 14/22] =?UTF-8?q?[#95]=20chore:=20ddl=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/sql/095/001_drop_table_value_reports.sql | 1 + .../sql/095/002_drop_table_character_value_report.sql | 1 + .../sql/095/003_create_table_value_report.sql | 10 ++++++++++ 3 files changed, 12 insertions(+) create mode 100644 jaknaeso-core/src/main/resources/sql/095/001_drop_table_value_reports.sql create mode 100644 jaknaeso-core/src/main/resources/sql/095/002_drop_table_character_value_report.sql create mode 100644 jaknaeso-core/src/main/resources/sql/095/003_create_table_value_report.sql diff --git a/jaknaeso-core/src/main/resources/sql/095/001_drop_table_value_reports.sql b/jaknaeso-core/src/main/resources/sql/095/001_drop_table_value_reports.sql new file mode 100644 index 00000000..1bd13152 --- /dev/null +++ b/jaknaeso-core/src/main/resources/sql/095/001_drop_table_value_reports.sql @@ -0,0 +1 @@ +drop table if exists value_reports; \ No newline at end of file diff --git a/jaknaeso-core/src/main/resources/sql/095/002_drop_table_character_value_report.sql b/jaknaeso-core/src/main/resources/sql/095/002_drop_table_character_value_report.sql new file mode 100644 index 00000000..064872a3 --- /dev/null +++ b/jaknaeso-core/src/main/resources/sql/095/002_drop_table_character_value_report.sql @@ -0,0 +1 @@ +drop table character_value_report; \ No newline at end of file diff --git a/jaknaeso-core/src/main/resources/sql/095/003_create_table_value_report.sql b/jaknaeso-core/src/main/resources/sql/095/003_create_table_value_report.sql new file mode 100644 index 00000000..afcb4881 --- /dev/null +++ b/jaknaeso-core/src/main/resources/sql/095/003_create_table_value_report.sql @@ -0,0 +1,10 @@ +create table if not exists value_report +( + id bigint auto_increment primary key, + keyword varchar(30), + percentage decimal(5,2), + character_record_id bigint not null, + created_at timestamp(6), + updated_at timestamp(6), + deleted_at timestamp(6) +); \ No newline at end of file From 687964c0752d5a6ce141f80f2163a3b22e5df8a2 Mon Sep 17 00:00:00 2001 From: pythonstrup Date: Mon, 17 Feb 2025 14:44:58 +0900 Subject: [PATCH 15/22] =?UTF-8?q?[#95]=20feat:=20=EC=BA=90=EB=A6=AD?= =?UTF-8?q?=ED=84=B0=20=EC=A3=BC=EC=9A=94=20=ED=8A=B9=EC=84=B1,=20?= =?UTF-8?q?=EA=B0=95=EC=A0=90,=20=EB=8B=A8=EC=A0=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../character/model/CharacterRecord.java | 17 +++++ .../character/model/CharacterTrait.java | 28 ++++++++ .../character/model/CharacterTraitType.java | 7 ++ .../character/model/CharacterTraits.java | 27 +++++++ .../character/model/ValueCharacter.java | 8 +++ .../character/service/CharacterService.java | 24 +------ .../service/dto/CharacterResponse.java | 53 +++++++++----- .../service/CharacterServiceTest.java | 4 +- .../controller/CharacterControllerTest.java | 72 +++++++++++++------ 9 files changed, 175 insertions(+), 65 deletions(-) create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTrait.java create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraitType.java create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraits.java diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java index 26aefd14..8a4d3212 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java @@ -14,6 +14,7 @@ import lombok.NoArgsConstructor; import org.nexters.jaknaesocore.common.model.BaseTimeEntity; import org.nexters.jaknaesocore.domain.member.model.Member; +import org.nexters.jaknaesocore.domain.survey.model.Keyword; import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; @Getter @@ -75,4 +76,20 @@ public static CharacterRecord of( return new CharacterRecord( characterNo, valueCharacter, startDate, endDate, member, surveyBundle, valueReports); } + + public Keyword getKeyword() { + return valueCharacter.getKeyword(); + } + + public String getName() { + return valueCharacter.getName(); + } + + public String getDescription() { + return valueCharacter.getDescription(); + } + + public List getTraitsByType(final CharacterTraitType characterTraitType) { + return valueCharacter.getTraitsByType(characterTraitType); + } } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTrait.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTrait.java new file mode 100644 index 00000000..33c1a2c6 --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTrait.java @@ -0,0 +1,28 @@ +package org.nexters.jaknaesocore.domain.character.model; + +import static jakarta.persistence.FetchType.LAZY; + +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.nexters.jaknaesocore.common.model.BaseTimeEntity; + +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class CharacterTrait extends BaseTimeEntity { + + @ManyToOne(fetch = LAZY) + @JoinColumn(name = "value_character_id") + private ValueCharacter valueCharacter; + + @Getter private String description; + + @Enumerated(EnumType.STRING) + @Getter + private CharacterTraitType type; +} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraitType.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraitType.java new file mode 100644 index 00000000..5e95caa5 --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraitType.java @@ -0,0 +1,7 @@ +package org.nexters.jaknaesocore.domain.character.model; + +public enum CharacterTraitType { + MAIN_TRAIT, + STRENGTH, + WEAKNESS, +} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraits.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraits.java new file mode 100644 index 00000000..78eec3b8 --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraits.java @@ -0,0 +1,27 @@ +package org.nexters.jaknaesocore.domain.character.model; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Embeddable; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; +import java.util.List; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.SQLRestriction; + +@Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class CharacterTraits { + + @OneToMany(mappedBy = "valueCharacter", cascade = CascadeType.PERSIST) + @SQLRestriction("deleted_at IS NULL") + private List values = new ArrayList<>(); + + public static CharacterTraits empty() { + return new CharacterTraits(); + } + + public List getByType(final CharacterTraitType type) { + return values.stream().filter(t -> t.getType().equals(type)).toList(); + } +} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacter.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacter.java index 86262065..d0992662 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacter.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacter.java @@ -1,8 +1,10 @@ package org.nexters.jaknaesocore.domain.character.model; +import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; import jakarta.persistence.Enumerated; +import java.util.List; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -21,9 +23,15 @@ public class ValueCharacter extends BaseEntity { @Enumerated(EnumType.STRING) private Keyword keyword; + @Embedded private CharacterTraits characterTraits = CharacterTraits.empty(); + public ValueCharacter(final String name, final String description, final Keyword keyword) { this.name = name; this.description = description; this.keyword = keyword; } + + public List getTraitsByType(final CharacterTraitType type) { + return characterTraits.getByType(type); + } } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java index 5e503ec0..9cc9ecc8 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java @@ -51,17 +51,7 @@ void setUp() { public CharacterResponse getCharacter(final CharacterCommand command) { return characterRecordRepository .findByIdAndMemberIdAndDeletedAtIsNullWithMember(command.memberId(), command.characterId()) - .map( - it -> - CharacterResponse.builder() - .characterId(it.getId()) - .characterNo(it.getCharacterNo()) - .valueCharacter(it.getValueCharacter()) - .name(it.getValueCharacter().getName()) - .description(it.getValueCharacter().getDescription()) - .startDate(it.getStartDate()) - .endDate(it.getEndDate()) - .build()) + .map(CharacterResponse::of) .orElseThrow(() -> CustomException.CHARACTER_NOT_FOUND); } @@ -69,17 +59,7 @@ public CharacterResponse getCharacter(final CharacterCommand command) { public CharacterResponse getCurrentCharacter(final Long memberId) { return characterRecordRepository .findTopByMemberIdAndDeletedAtIsNullWithMember(memberId) - .map( - it -> - CharacterResponse.builder() - .characterId(it.getId()) - .characterNo(it.getCharacterNo()) - .valueCharacter(it.getValueCharacter()) - .name(it.getValueCharacter().getName()) - .description(it.getValueCharacter().getDescription()) - .startDate(it.getStartDate()) - .endDate(it.getEndDate()) - .build()) + .map(CharacterResponse::of) .orElseThrow(() -> CustomException.CHARACTER_NOT_FOUND); } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/CharacterResponse.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/CharacterResponse.java index 1e2dcfbb..50d7476d 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/CharacterResponse.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/CharacterResponse.java @@ -1,34 +1,51 @@ package org.nexters.jaknaesocore.domain.character.service.dto; -import java.time.LocalDate; +import java.util.List; import lombok.Builder; -import org.nexters.jaknaesocore.domain.character.model.ValueCharacter; +import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; +import org.nexters.jaknaesocore.domain.character.model.CharacterTrait; +import org.nexters.jaknaesocore.domain.character.model.CharacterTraitType; +import org.nexters.jaknaesocore.domain.survey.model.Keyword; +@Builder public record CharacterResponse( Long characterId, String characterNo, - String characterType, + Keyword characterType, String name, String description, + List mainTraits, + List strengths, + List weaknesses, String startDate, String endDate) { @Builder - public static CharacterResponse of( - final Long characterId, - final String characterNo, - final ValueCharacter valueCharacter, - final String name, - final String description, - final LocalDate startDate, - final LocalDate endDate) { + public static CharacterResponse of(final CharacterRecord characterRecord) { return new CharacterResponse( - characterId, - characterNo, - valueCharacter.getKeyword().name(), - name, - description, - startDate.toString(), - endDate.toString()); + characterRecord.getId(), + characterRecord.getCharacterNo(), + characterRecord.getKeyword(), + characterRecord.getName(), + characterRecord.getDescription(), + characterRecord.getTraitsByType(CharacterTraitType.MAIN_TRAIT).stream() + .map(CharacterTraitResponse::of) + .toList(), + characterRecord.getTraitsByType(CharacterTraitType.STRENGTH).stream() + .map(CharacterTraitResponse::of) + .toList(), + characterRecord.getTraitsByType(CharacterTraitType.WEAKNESS).stream() + .map(CharacterTraitResponse::of) + .toList(), + characterRecord.getStartDate().toString(), + characterRecord.getEndDate().toString()); + } + + @Builder + public record CharacterTraitResponse(String description) { + + public static CharacterTraitResponse of(final CharacterTrait characterTrait) { + return new CharacterTraitResponse(characterTrait.getDescription()); + } } } diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java index 7b56239e..17eb2852 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java @@ -125,7 +125,7 @@ void shouldReturnCharacter() { then(actual) .extracting("characterNo", "characterType") - .containsExactly("첫번째", valueCharacter.getKeyword().name()); + .containsExactly("첫번째", valueCharacter.getKeyword()); } } } @@ -171,7 +171,7 @@ void shouldReturnCharacter() { then(actual) .extracting("characterNo", "characterType") - .containsExactly("첫번째", valueCharacter.getKeyword().name()); + .containsExactly("첫번째", valueCharacter.getKeyword()); } } } diff --git a/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java b/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java index 76cb161c..cd3123b5 100644 --- a/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java +++ b/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java @@ -23,6 +23,7 @@ import org.nexters.jaknaesocore.domain.character.model.ValueReport; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterCommand; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterResponse; +import org.nexters.jaknaesocore.domain.character.service.dto.CharacterResponse.CharacterTraitResponse; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterValueReportCommand; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterValueReportResponse; import org.nexters.jaknaesocore.domain.character.service.dto.CharactersResponse; @@ -90,19 +91,8 @@ class CharacterControllerTest extends ControllerTest { @WithMockCustomUser @Test void 특정_캐릭터_정보를_조회한다() throws Exception { - - ValueCharacter valueCharacter = new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", Keyword.SUCCESS); given(characterService.getCharacter(new CharacterCommand(1L, 1L))) - .willReturn( - CharacterResponse.builder() - .characterId(1L) - .characterNo("첫번째") - .valueCharacter(valueCharacter) - .name(valueCharacter.getName()) - .description(valueCharacter.getDescription()) - .startDate(LocalDate.now().minusDays(15)) - .endDate(LocalDate.now()) - .build()); + .willReturn(createCharacterResponse()); mockMvc .perform( @@ -144,6 +134,15 @@ class CharacterControllerTest extends ControllerTest { fieldWithPath("data.description") .type(SimpleType.STRING) .description("캐릭터 설명"), + fieldWithPath("data.mainTraits[].description") + .type(SimpleType.STRING) + .description("캐릭터 주요 특성"), + fieldWithPath("data.strengths[].description") + .type(SimpleType.STRING) + .description("캐릭터 강점"), + fieldWithPath("data.weaknesses[].description") + .type(SimpleType.STRING) + .description("캐릭터 약점"), fieldWithPath("data.startDate") .type(SimpleType.STRING) .description("시작 일자"), @@ -160,17 +159,7 @@ class CharacterControllerTest extends ControllerTest { void 현재_캐릭터_정보를_조회한다() throws Exception { ValueCharacter valueCharacter = new ValueCharacter("성취를 쫓는 노력가", "성공 캐릭터 설명", Keyword.SUCCESS); - given(characterService.getCurrentCharacter(1L)) - .willReturn( - CharacterResponse.builder() - .characterId(1L) - .characterNo("첫번째") - .valueCharacter(valueCharacter) - .name(valueCharacter.getName()) - .description(valueCharacter.getDescription()) - .startDate(LocalDate.now().minusDays(15)) - .endDate(LocalDate.now()) - .build()); + given(characterService.getCurrentCharacter(1L)).willReturn(createCharacterResponse()); mockMvc .perform( @@ -208,6 +197,15 @@ class CharacterControllerTest extends ControllerTest { fieldWithPath("data.description") .type(SimpleType.STRING) .description("캐릭터 설명"), + fieldWithPath("data.mainTraits[].description") + .type(SimpleType.STRING) + .description("캐릭터 주요 특성"), + fieldWithPath("data.strengths[].description") + .type(SimpleType.STRING) + .description("캐릭터 강점"), + fieldWithPath("data.weaknesses[].description") + .type(SimpleType.STRING) + .description("캐릭터 약점"), fieldWithPath("data.startDate") .type(SimpleType.STRING) .description("시작 일자"), @@ -263,4 +261,32 @@ class CharacterControllerTest extends ControllerTest { .responseSchema(schema("CharacterValueReportResponse")) .build()))); } + + private CharacterResponse createCharacterResponse() { + return CharacterResponse.builder() + .characterId(1L) + .characterNo("첫번째") + .characterType(Keyword.SUCCESS) + .name("성취를 쫓는 노력가") + .description( + "목표를 이루고 영향력을 가지는 것을 중요하게 여기는\n노력가 유형은 끊임없는 노력과 성과를 내는 것을 중요시 여겨요.\n사회에서 의미 있는 위치를 차지하고 싶어하는 야망가!") + .mainTraits( + List.of( + CharacterTraitResponse.builder() + .description("목표를 이루기 위해 끊임없이 노력하며, 성장하는 과정에서 보람을 느껴요.") + .build())) + .strengths( + List.of( + CharacterTraitResponse.builder() + .description("강한 추진력과 목표 지향적인 태도로 원하는 결과를 만들어내요.") + .build())) + .weaknesses( + List.of( + CharacterTraitResponse.builder() + .description("성과 중심적인 태도가 타인과의 관계에 영향을 줄 수 있어요.") + .build())) + .startDate(LocalDate.now().minusDays(15).toString()) + .endDate(LocalDate.now().toString()) + .build(); + } } From 085464678ace7aa4549cab465af7a891e762c779 Mon Sep 17 00:00:00 2001 From: pythonstrup Date: Mon, 17 Feb 2025 14:48:04 +0900 Subject: [PATCH 16/22] =?UTF-8?q?[#95]=20chore:=20=EC=BA=90=EB=A6=AD?= =?UTF-8?q?=ED=84=B0=20=EC=A3=BC=EC=9A=94=20=ED=8A=B9=EC=84=B1,=20?= =?UTF-8?q?=EA=B0=95=EC=A0=90,=20=EB=8B=A8=EC=A0=90=20sql=20=EC=8A=A4?= =?UTF-8?q?=ED=82=A4=EB=A7=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sql/095/004_create_table_character_trait.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 jaknaeso-core/src/main/resources/sql/095/004_create_table_character_trait.sql diff --git a/jaknaeso-core/src/main/resources/sql/095/004_create_table_character_trait.sql b/jaknaeso-core/src/main/resources/sql/095/004_create_table_character_trait.sql new file mode 100644 index 00000000..2440e396 --- /dev/null +++ b/jaknaeso-core/src/main/resources/sql/095/004_create_table_character_trait.sql @@ -0,0 +1,10 @@ +create table if not exists character_trait +( + id bigint auto_increment primary key, + value_character_id bigint unsigned not null, + type varchar(20) not null, + description varchar(255) not null, + created_at timestamp(6), + updated_at timestamp(6), + deleted_at timestamp(6) +); \ No newline at end of file From 8af2f983617d55d73867301f89e848deb0eeab22 Mon Sep 17 00:00:00 2001 From: pythonstrup Date: Mon, 17 Feb 2025 18:54:40 +0900 Subject: [PATCH 17/22] =?UTF-8?q?[#95]=20test:=20CharacterTraits=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../character/model/CharacterTrait.java | 11 ++ .../character/model/CharacterTraits.java | 10 ++ .../character/model/CharacterTraitsTest.java | 101 ++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraitsTest.java diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTrait.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTrait.java index 33c1a2c6..0cc75392 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTrait.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTrait.java @@ -8,6 +8,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.nexters.jaknaesocore.common.model.BaseTimeEntity; @@ -25,4 +26,14 @@ public class CharacterTrait extends BaseTimeEntity { @Enumerated(EnumType.STRING) @Getter private CharacterTraitType type; + + @Builder + private CharacterTrait( + final ValueCharacter valueCharacter, + final String description, + final CharacterTraitType type) { + this.valueCharacter = valueCharacter; + this.description = description; + this.type = type; + } } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraits.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraits.java index 78eec3b8..26bfb126 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraits.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraits.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; import lombok.AccessLevel; +import lombok.Builder; import lombok.NoArgsConstructor; import org.hibernate.annotations.SQLRestriction; @@ -17,6 +18,15 @@ public class CharacterTraits { @SQLRestriction("deleted_at IS NULL") private List values = new ArrayList<>(); + @Builder + private CharacterTraits(final List values) { + this.values = values; + } + + public static CharacterTraits of(final List values) { + return new CharacterTraits(values); + } + public static CharacterTraits empty() { return new CharacterTraits(); } diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraitsTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraitsTest.java new file mode 100644 index 00000000..b55d452e --- /dev/null +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/model/CharacterTraitsTest.java @@ -0,0 +1,101 @@ +package org.nexters.jaknaesocore.domain.character.model; + +import static org.assertj.core.api.BDDAssertions.then; +import static org.junit.jupiter.api.Assertions.*; + +import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class CharacterTraitsTest { + + @Nested + @DisplayName("getByType 메소드는") + class getByType { + + @Nested + @DisplayName("MAIN_TRAIT을 전달받으면, ") + class whenMainTrait { + + @Test + @DisplayName("주요 특성 목록만 반환한다.") + void shouldOnlyReturnMainTraits() { + final CharacterTraits sut = + createCharacterTraits( + CharacterTraitType.MAIN_TRAIT, + CharacterTraitType.STRENGTH, + CharacterTraitType.WEAKNESS); + + then(sut.getByType(CharacterTraitType.MAIN_TRAIT)) + .hasSize(1) + .extracting("type") + .containsExactly(CharacterTraitType.MAIN_TRAIT); + } + } + + @Nested + @DisplayName("MAIN_TRAIT을 전달 받았는데 목록이 비어있다면, ") + class whenMainTraitButEmpty { + + @Test + @DisplayName("빈 배열을 반환한다.") + void shouldReturnEmptyList() { + final CharacterTraits sut = + createCharacterTraits(CharacterTraitType.STRENGTH, CharacterTraitType.WEAKNESS); + + then(sut.getByType(CharacterTraitType.MAIN_TRAIT)).hasSize(0); + } + } + + @Nested + @DisplayName("STRENGTH을 전달받으면, ") + class whenStrength { + + @Test + @DisplayName("주요 특성 목록만 반환한다.") + void shouldOnlyReturnStrengthTraits() { + final CharacterTraits sut = + createCharacterTraits( + CharacterTraitType.MAIN_TRAIT, + CharacterTraitType.STRENGTH, + CharacterTraitType.WEAKNESS); + + then(sut.getByType(CharacterTraitType.STRENGTH)) + .hasSize(1) + .extracting("type") + .containsExactly(CharacterTraitType.STRENGTH); + } + } + + @Nested + @DisplayName("WEAKNESS을 전달받으면, ") + class whenWeakness { + + @Test + @DisplayName("주요 특성 목록만 반환한다.") + void shouldOnlyReturnWeaknessTraits() { + final CharacterTraits sut = + createCharacterTraits( + CharacterTraitType.MAIN_TRAIT, + CharacterTraitType.STRENGTH, + CharacterTraitType.WEAKNESS); + + then(sut.getByType(CharacterTraitType.WEAKNESS)) + .hasSize(1) + .extracting("type") + .containsExactly(CharacterTraitType.WEAKNESS); + } + } + } + + private CharacterTrait createCharacterTrait(final CharacterTraitType type) { + return CharacterTrait.builder().type(type).build(); + } + + private CharacterTraits createCharacterTraits(final CharacterTraitType... type) { + return CharacterTraits.builder() + .values(Stream.of(type).map(this::createCharacterTrait).toList()) + .build(); + } +} From 60be7a259caae79cf2b5ec6abbe258404bec6376 Mon Sep 17 00:00:00 2001 From: pythonstrup Date: Mon, 17 Feb 2025 20:44:36 +0900 Subject: [PATCH 18/22] =?UTF-8?q?[#95]=20feat:=20=EC=BA=90=EB=A6=AD?= =?UTF-8?q?=ED=84=B0=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=EB=A1=9C=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/util/OrdinalFormatter.java | 120 +++++++++++++++ .../character/model/CharacterRecord.java | 64 +++++++- .../domain/character/model/Characters.java | 40 +---- .../character/model/ValueCharacter.java | 2 + .../character/model/ValueCharacters.java | 32 ++++ .../repository/CharacterRecordRepository.java | 18 ++- .../character/service/CharacterService.java | 79 +++++----- .../domain/survey/model/KeywordScores.java | 15 +- .../survey/model/SurveySubmissions.java | 8 + .../OnboardingSurveyRepository.java | 6 +- .../domain/survey/service/SurveyService.java | 44 +++--- .../095/005_alter_table_character_record.sql | 2 + .../CharacterRecordRepositoryTest.java | 97 +++++++++--- .../service/CharacterServiceTest.java | 44 ++++-- .../survey/service/SurveyServiceTest.java | 138 +++++++++++++++--- 15 files changed, 544 insertions(+), 165 deletions(-) create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/common/util/OrdinalFormatter.java create mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacters.java create mode 100644 jaknaeso-core/src/main/resources/sql/095/005_alter_table_character_record.sql diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/common/util/OrdinalFormatter.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/common/util/OrdinalFormatter.java new file mode 100644 index 00000000..bc27882a --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/common/util/OrdinalFormatter.java @@ -0,0 +1,120 @@ +package org.nexters.jaknaesocore.common.util; + +import static java.util.Map.entry; + +import java.util.Map; + +public class OrdinalFormatter { + + private static final Map ORDINALS = + Map.ofEntries( + entry(1, "첫번째"), + entry(2, "두번째"), + entry(3, "세번째"), + entry(4, "네번째"), + entry(5, "다섯번째"), + entry(6, "여섯번째"), + entry(7, "일곱번째"), + entry(8, "여덟번째"), + entry(9, "아홉번째"), + entry(10, "열번째"), + entry(11, "열한번째"), + entry(12, "열두번째"), + entry(13, "열세번째"), + entry(14, "열네번째"), + entry(15, "열다섯번째"), + entry(16, "열여섯번째"), + entry(17, "열일곱번째"), + entry(18, "열여덟번째"), + entry(19, "열아홉번째"), + entry(20, "스무번째"), + entry(21, "스물한번째"), + entry(22, "스물두번째"), + entry(23, "스물세번째"), + entry(24, "스물네번째"), + entry(25, "스물다섯번째"), + entry(26, "스물여섯번째"), + entry(27, "스물일곱번째"), + entry(28, "스물여덟번째"), + entry(29, "스물아홉번째"), + entry(30, "서른번째"), + entry(31, "서른한번째"), + entry(32, "서른두번째"), + entry(33, "서른세번째"), + entry(34, "서른네번째"), + entry(35, "서른다섯번째"), + entry(36, "서른여섯번째"), + entry(37, "서른일곱번째"), + entry(38, "서른여덟번째"), + entry(39, "서른아홉번째"), + entry(40, "마흔번째"), + entry(41, "마흔한번째"), + entry(42, "마흔두번째"), + entry(43, "마흔세번째"), + entry(44, "마흔네번째"), + entry(45, "마흔다섯번째"), + entry(46, "마흔여섯번째"), + entry(47, "마흔일곱번째"), + entry(48, "마흔여덟번째"), + entry(49, "마흔아홉번째"), + entry(50, "쉰번째"), + entry(51, "쉰한번째"), + entry(52, "쉰두번째"), + entry(53, "쉰세번째"), + entry(54, "쉰네번째"), + entry(55, "쉰다섯번째"), + entry(56, "쉰여섯번째"), + entry(57, "쉰일곱번째"), + entry(58, "쉰여덟번째"), + entry(59, "쉰아홉번째"), + entry(60, "예순번째"), + entry(61, "예순한번째"), + entry(62, "예순두번째"), + entry(63, "예순세번째"), + entry(64, "예순네번째"), + entry(65, "예순다섯번째"), + entry(66, "예순여섯번째"), + entry(67, "예순일곱번째"), + entry(68, "예순여덟번째"), + entry(69, "예순아홉번째"), + entry(70, "일흔번째"), + entry(71, "일흔한번째"), + entry(72, "일흔두번째"), + entry(73, "일흔세번째"), + entry(74, "일흔네번째"), + entry(75, "일흔다섯번째"), + entry(76, "일흔여섯번째"), + entry(77, "일흔일곱번째"), + entry(78, "일흔여덟번째"), + entry(79, "일흔아홉번째"), + entry(80, "여든번째"), + entry(81, "여든한번째"), + entry(82, "여든두번째"), + entry(83, "여든세번째"), + entry(84, "여든네번째"), + entry(85, "여든다섯번째"), + entry(86, "여든여섯번째"), + entry(87, "여든일곱번째"), + entry(88, "여든여덟번째"), + entry(89, "여든아홉번째"), + entry(90, "아흔번째"), + entry(91, "아흔한번째"), + entry(92, "아흔두번째"), + entry(93, "아흔세번째"), + entry(94, "아흔네번째"), + entry(95, "아흔다섯번째"), + entry(96, "아흔여섯번째"), + entry(97, "아흔일곱번째"), + entry(98, "아흔여덟번째"), + entry(99, "아흔아홉번째"), + entry(100, "백번째")); + + private static String FORMAT = "%s %s"; + private static String DEFAULT_ORDINAL = "첫번째"; + private static String CHARACTER_WORD = "캐릭터"; + + public static String getCharacterNo(final Integer ordinalNumber) { + return String.format( + FORMAT, ORDINALS.getOrDefault(ordinalNumber, DEFAULT_ORDINAL), CHARACTER_WORD); + } +} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java index 8a4d3212..df7e015b 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/CharacterRecord.java @@ -7,21 +7,25 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import java.time.LocalDate; +import java.util.ArrayList; import java.util.List; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.nexters.jaknaesocore.common.model.BaseTimeEntity; +import org.nexters.jaknaesocore.common.util.OrdinalFormatter; import org.nexters.jaknaesocore.domain.member.model.Member; import org.nexters.jaknaesocore.domain.survey.model.Keyword; import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; +import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity public class CharacterRecord extends BaseTimeEntity { + private int ordinalNumber; private String characterNo; @ManyToOne @@ -41,9 +45,24 @@ public class CharacterRecord extends BaseTimeEntity { private SurveyBundle surveyBundle; @OneToMany(mappedBy = "characterRecord", cascade = CascadeType.PERSIST, orphanRemoval = true) - private List valueReports; + private List valueReports = new ArrayList<>(); private CharacterRecord( + final int ordinalNumber, + final String characterNo, + final Member member, + final SurveyBundle surveyBundle, + final LocalDate startDate) { + this.ordinalNumber = ordinalNumber; + this.characterNo = characterNo; + this.member = member; + this.surveyBundle = surveyBundle; + this.startDate = startDate; + } + + @Builder + private CharacterRecord( + final int ordinalNumber, final String characterNo, final ValueCharacter valueCharacter, final LocalDate startDate, @@ -51,6 +70,7 @@ private CharacterRecord( final Member member, final SurveyBundle surveyBundle, final List valueReports) { + this.ordinalNumber = ordinalNumber; this.characterNo = characterNo; this.valueCharacter = valueCharacter; this.startDate = startDate; @@ -64,17 +84,45 @@ private CharacterRecord( } } - @Builder public static CharacterRecord of( - final String characterNo, - final ValueCharacter valueCharacter, - final LocalDate startDate, - final LocalDate endDate, + final CharacterRecord previousRecord, + final Member member, + final SurveyBundle bundle, + final LocalDate startDate) { + final int ordinalNumber = previousRecord.getOrdinalNumber() + 1; + return new CharacterRecord( + ordinalNumber, OrdinalFormatter.getCharacterNo(ordinalNumber), member, bundle, startDate); + } + + public static CharacterRecord ofFirst( final Member member, final SurveyBundle surveyBundle, - final List valueReports) { + final ValueCharacter valueCharacter, + final List valueReports, + List submissions) { + final int first = 1; return new CharacterRecord( - characterNo, valueCharacter, startDate, endDate, member, surveyBundle, valueReports); + first, + OrdinalFormatter.getCharacterNo(first), + valueCharacter, + submissions.getFirst().getSubmittedAt().toLocalDate(), + submissions.getLast().getSubmittedAt().toLocalDate(), + member, + surveyBundle, + valueReports); + } + + public void updateRecord( + final ValueCharacter valueCharacter, + final List valueReports, + final List submissions) { + this.valueCharacter = valueCharacter; + this.startDate = submissions.getFirst().getSubmittedAt().toLocalDate(); + this.endDate = submissions.getLast().getSubmittedAt().toLocalDate(); + if (valueReports != null) { + this.valueReports = valueReports; + this.valueReports.forEach(it -> it.updateCharacterRecord(this)); + } } public Keyword getKeyword() { diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/Characters.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/Characters.java index cadde3e1..1877378b 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/Characters.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/Characters.java @@ -1,8 +1,6 @@ package org.nexters.jaknaesocore.domain.character.model; import java.math.BigDecimal; -import java.time.LocalDate; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -11,47 +9,26 @@ import lombok.Builder; import lombok.RequiredArgsConstructor; import org.nexters.jaknaesocore.common.model.ScaledBigDecimal; -import org.nexters.jaknaesocore.domain.member.model.Member; import org.nexters.jaknaesocore.domain.survey.model.Keyword; import org.nexters.jaknaesocore.domain.survey.model.KeywordMetrics; import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; -import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public class Characters { - private final Long characterNo; - private final Member member; - private final SurveyBundle bundle; private final List scores; private final List submissions; - private final Map valueCharacters; @Builder public static Characters of( - final Long characterNo, - final Member member, - final SurveyBundle bundle, - final List scores, - final List submissions, - final Map valueCharacters) { - return new Characters(characterNo, member, bundle, scores, submissions, valueCharacters); + final List scores, final List submissions) { + return new Characters(scores, submissions); } - public CharacterRecord provideCharacterRecord() { + public List provideCharacterRecord() { final List valueReports = provideValueReport(); - final ValueCharacter valueCharacter = findTopValueCharacter(valueReports); - return CharacterRecord.builder() - .characterNo("TODO 수정") - .valueCharacter(valueCharacter) - .valueReports(valueReports) - .member(member) - .surveyBundle(bundle) - .valueReports(valueReports) - .startDate(bundle.getCreatedAt().toLocalDate()) - .endDate(LocalDate.now()) - .build(); + return valueReports; } private List provideValueReport() { @@ -84,13 +61,4 @@ private Map calculateKeywordWeights( }); return weightMap; } - - private ValueCharacter findTopValueCharacter(final List valueReports) { - final ValueReport topReport = - valueReports.stream() - .max(Comparator.comparing(ValueReport::getPercentage)) - .orElseThrow(() -> new IllegalStateException("ValueReport가 비어 있습니다.")); - - return valueCharacters.get(topReport.getKeyword()); - } } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacter.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacter.java index d0992662..999681e8 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacter.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacter.java @@ -6,6 +6,7 @@ import jakarta.persistence.Enumerated; import java.util.List; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import org.nexters.jaknaesocore.common.model.BaseEntity; @@ -25,6 +26,7 @@ public class ValueCharacter extends BaseEntity { @Embedded private CharacterTraits characterTraits = CharacterTraits.empty(); + @Builder public ValueCharacter(final String name, final String description, final Keyword keyword) { this.name = name; this.description = description; diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacters.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacters.java new file mode 100644 index 00000000..ad6f7c7b --- /dev/null +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ValueCharacters.java @@ -0,0 +1,32 @@ +package org.nexters.jaknaesocore.domain.character.model; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.nexters.jaknaesocore.domain.survey.model.Keyword; + +public class ValueCharacters { + + private final Map values; + + private ValueCharacters(final Map values) { + this.values = values; + } + + public static ValueCharacters of(final List values) { + return new ValueCharacters( + values.stream() + .collect( + Collectors.toMap(ValueCharacter::getKeyword, valueCharacter -> valueCharacter))); + } + + public ValueCharacter findTopValueCharacter(final List valueReports) { + final ValueReport topReport = + valueReports.stream() + .max(Comparator.comparing(ValueReport::getPercentage)) + .orElseThrow(() -> new IllegalStateException("ValueReport가 비어 있습니다.")); + + return values.get(topReport.getKeyword()); + } +} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepository.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepository.java index 46b97159..55a69f24 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepository.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepository.java @@ -9,9 +9,14 @@ public interface CharacterRecordRepository extends JpaRepository { @Query( - "SELECT c FROM CharacterRecord c JOIN FETCH c.member cm " - + "WHERE cm.id = :memberId AND c.deletedAt IS NULL ORDER BY c.endDate DESC LIMIT 1") - Optional findTopByMemberIdAndDeletedAtIsNullWithMember(final Long memberId); + "SELECT c FROM CharacterRecord c " + + "JOIN FETCH c.member cm " + + "LEFT JOIN c.valueCharacter vc " + + "WHERE cm.id = :memberId " + + "AND vc.id IS NOT NULL " + + "AND c.deletedAt IS NULL " + + "ORDER BY c.endDate DESC LIMIT 1") + Optional findLatestCompletedCharacter(final Long memberId); @Query( "SELECT c FROM CharacterRecord c JOIN FETCH c.member cm " @@ -30,4 +35,11 @@ List findByMemberIdAndDeletedAtIsNullWithMemberAndSurveyBundle( "SELECT c FROM CharacterRecord c JOIN FETCH c.valueReports cr " + "WHERE c.id = :id AND c.deletedAt IS NULL") Optional findByIdAndDeletedAtIsNullWithValueReports(final Long id); + + @Query( + "SELECT c FROM CharacterRecord c " + + "WHERE c.member.id = :memberId " + + "AND c.surveyBundle.id = :bundleId " + + "AND c.deletedAt IS NULL") + Optional findByMemberIdAndBundleId(final Long memberId, final Long bundleId); } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java index 9cc9ecc8..bb5347df 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java @@ -1,15 +1,15 @@ package org.nexters.jaknaesocore.domain.character.service; -import jakarta.annotation.PostConstruct; +import java.time.LocalDate; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.nexters.jaknaesocore.common.support.error.CustomException; import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; import org.nexters.jaknaesocore.domain.character.model.Characters; import org.nexters.jaknaesocore.domain.character.model.ValueCharacter; +import org.nexters.jaknaesocore.domain.character.model.ValueCharacters; +import org.nexters.jaknaesocore.domain.character.model.ValueReport; import org.nexters.jaknaesocore.domain.character.repository.CharacterRecordRepository; import org.nexters.jaknaesocore.domain.character.repository.ValueCharacterRepository; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterCommand; @@ -18,13 +18,13 @@ import org.nexters.jaknaesocore.domain.character.service.dto.CharacterValueReportResponse; import org.nexters.jaknaesocore.domain.character.service.dto.CharactersResponse; import org.nexters.jaknaesocore.domain.character.service.dto.SimpleCharacterResponses; +import org.nexters.jaknaesocore.domain.member.model.Member; import org.nexters.jaknaesocore.domain.member.repository.MemberRepository; -import org.nexters.jaknaesocore.domain.survey.model.Keyword; +import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; +import org.nexters.jaknaesocore.domain.survey.model.SurveyBundle; +import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; import org.nexters.jaknaesocore.domain.survey.repository.SurveySubmissionRepository; -import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; -import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @Slf4j @@ -37,16 +37,6 @@ public class CharacterService { private final ValueCharacterRepository valueCharacterRepository; private final SurveySubmissionRepository surveySubmissionRepository; - private Map valueCharacters; - - @PostConstruct - void setUp() { - valueCharacters = - valueCharacterRepository.findAll().stream() - .collect( - Collectors.toMap(ValueCharacter::getKeyword, valueCharacter -> valueCharacter)); - } - @Transactional(readOnly = true) public CharacterResponse getCharacter(final CharacterCommand command) { return characterRecordRepository @@ -58,7 +48,7 @@ public CharacterResponse getCharacter(final CharacterCommand command) { @Transactional(readOnly = true) public CharacterResponse getCurrentCharacter(final Long memberId) { return characterRecordRepository - .findTopByMemberIdAndDeletedAtIsNullWithMember(memberId) + .findLatestCompletedCharacter(memberId) .map(CharacterResponse::of) .orElseThrow(() -> CustomException.CHARACTER_NOT_FOUND); } @@ -93,22 +83,45 @@ public CharacterValueReportResponse getCharacterReport( return CharacterValueReportResponse.of(characterRecord.getValueReports()); } - @EventListener - @Transactional(propagation = Propagation.MANDATORY) - public void createCharacter(final CreateCharacterEvent event) { + @Transactional + public void createFirstCharacter( + Member member, + SurveyBundle bundle, + List scores, + List submissions) { final Characters characters = - Characters.builder() - .member(event.member()) - .bundle(event.bundle()) - .scores(event.scores()) - .submissions(event.submissions()) - .valueCharacters(valueCharacters) - .build(); - characterRecordRepository.save(characters.provideCharacterRecord()); + Characters.builder().scores(scores).submissions(submissions).build(); + final List valueReports = characters.provideCharacterRecord(); + final ValueCharacter valueCharacter = + ValueCharacters.of(valueCharacterRepository.findAll()).findTopValueCharacter(valueReports); + characterRecordRepository.save( + CharacterRecord.ofFirst(member, bundle, valueCharacter, valueReports, submissions)); + } + + @Transactional + public void createCharacter(Member member, SurveyBundle bundle, LocalDate startDate) { + final CharacterRecord previousRecord = + characterRecordRepository + .findLatestCompletedCharacter(member.getId()) + .orElseThrow(() -> CustomException.CHARACTER_NOT_FOUND); + characterRecordRepository.save(CharacterRecord.of(previousRecord, member, bundle, startDate)); + } - log.info( - "Handled CreateCharacterEvent for memberId {} and bundleId {}", - event.member().getId(), - event.bundle().getId()); + @Transactional + public void updateCharacter( + Member member, + SurveyBundle bundle, + List scores, + List submissions) { + final Characters characters = + Characters.builder().scores(scores).submissions(submissions).build(); + final List valueReports = characters.provideCharacterRecord(); + final ValueCharacter valueCharacter = + ValueCharacters.of(valueCharacterRepository.findAll()).findTopValueCharacter(valueReports); + final CharacterRecord characterRecord = + characterRecordRepository + .findByMemberIdAndBundleId(member.getId(), bundle.getId()) + .orElseThrow(() -> CustomException.CHARACTER_NOT_FOUND); + characterRecord.updateRecord(valueCharacter, valueReports, submissions); } } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordScores.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordScores.java index d70674eb..89c28ada 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordScores.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/KeywordScores.java @@ -1,18 +1,19 @@ package org.nexters.jaknaesocore.domain.survey.model; import java.util.List; -import java.util.stream.Collectors; +import lombok.Getter; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class KeywordScores { - private final List surveys; + @Getter private final List values; - public List getKeywordScores() { - return surveys.stream() - .flatMap(survey -> survey.getOptions().stream()) - .flatMap(option -> option.getScores().stream()) - .collect(Collectors.toList()); + public static KeywordScores of(List values) { + return new KeywordScores( + values.stream() + .flatMap(survey -> survey.getOptions().stream()) + .flatMap(option -> option.getScores().stream()) + .toList()); } } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/SurveySubmissions.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/SurveySubmissions.java index ccf076a7..ec506ca0 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/SurveySubmissions.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/model/SurveySubmissions.java @@ -9,10 +9,18 @@ public class SurveySubmissions { private final List submissions; + public static SurveySubmissions of(List submissions) { + return new SurveySubmissions(submissions); + } + public List getSubmittedSurvey(final Long memberId) { return submissions.stream() .filter(submission -> submission.getMember().getId().equals(memberId)) .map(SurveySubmission::getSurvey) .collect(Collectors.toList()); } + + public boolean isFirstSubmitted() { + return submissions.size() == 1; + } } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/OnboardingSurveyRepository.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/OnboardingSurveyRepository.java index 49df6d10..4db5325f 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/OnboardingSurveyRepository.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/repository/OnboardingSurveyRepository.java @@ -1,6 +1,10 @@ package org.nexters.jaknaesocore.domain.survey.repository; +import java.util.Optional; import org.nexters.jaknaesocore.domain.survey.model.OnboardingSurvey; import org.springframework.data.jpa.repository.JpaRepository; -public interface OnboardingSurveyRepository extends JpaRepository {} +public interface OnboardingSurveyRepository extends JpaRepository { + + Optional findTopBy(); +} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/SurveyService.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/SurveyService.java index 16bb048f..3b0f6093 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/SurveyService.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/survey/service/SurveyService.java @@ -11,6 +11,7 @@ import lombok.RequiredArgsConstructor; import org.nexters.jaknaesocore.common.model.BaseEntity; import org.nexters.jaknaesocore.common.support.error.CustomException; +import org.nexters.jaknaesocore.domain.character.service.CharacterService; import org.nexters.jaknaesocore.domain.member.model.Member; import org.nexters.jaknaesocore.domain.member.repository.MemberRepository; import org.nexters.jaknaesocore.domain.survey.dto.OnboardingSubmissionResult; @@ -34,8 +35,6 @@ import org.nexters.jaknaesocore.domain.survey.repository.SurveyBundleRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveyRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveySubmissionRepository; -import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -48,7 +47,7 @@ public class SurveyService { private final SurveySubmissionRepository surveySubmissionRepository; private final SurveyRepository surveyRepository; private final OnboardingSurveyRepository onboardingSurveyRepository; - private final ApplicationEventPublisher eventPublisher; + private final CharacterService characterService; @Transactional(readOnly = true) public SurveyResponse getNextSurvey(final Long bundleId, final Long memberId) { @@ -162,11 +161,22 @@ public void submitSurvey(SurveySubmissionCommand command, LocalDateTime submitte surveySubmissionRepository .findByMemberIdAndBundleIdAndDeletedAtIsNullWithSurveyAndSurveyBundle( member.getId(), bundle.getId()); + if (SurveySubmissions.of(submissions).isFirstSubmitted()) { + characterService.createCharacter(member, bundle, submittedAt.toLocalDate()); + } if (bundle.isAllSubmitted(submissions)) { - publishCreateCharacterEvent(member, bundle, submissions); + completeCharacter(member, bundle, submissions); } } + private void completeCharacter( + final Member member, final SurveyBundle bundle, final List submissions) { + final List surveys = submissions.stream().map(SurveySubmission::getSurvey).toList(); + final KeywordScores scores = KeywordScores.of(surveys); + + characterService.updateCharacter(member, bundle, scores.getValues(), submissions); + } + @Transactional(readOnly = true) public SurveySubmissionHistoryResponse getSurveySubmissionHistory( final SurveySubmissionHistoryCommand command) { @@ -200,22 +210,18 @@ public void submitOnboardingSurvey( createSurveyToSelectedOption(command.submissions(), surveyMap); List submissions = - createSubmissionsBy(submittedAt, surveyToSelectedOption, member); - - surveySubmissionRepository.saveAll(submissions); + surveySubmissionRepository.saveAll( + createSubmissionsBy(submittedAt, surveyToSelectedOption, member)); member.completeOnboarding(submittedAt); - - // FIXME: 확인 후 주석 제거 필요 (온보딩 번들 전달) - // createCharacter(member, null, submissions); - } - - private void publishCreateCharacterEvent( - final Member member, final SurveyBundle bundle, final List submissions) { - final List surveys = submissions.stream().map(SurveySubmission::getSurvey).toList(); - final KeywordScores scores = new KeywordScores(surveys); - - eventPublisher.publishEvent( - new CreateCharacterEvent(member, bundle, scores.getKeywordScores(), submissions)); + final SurveyBundle onboardingBundle = + onboardingSurveyRepository + .findTopBy() + .orElseThrow(() -> CustomException.SURVEY_NOT_FOUND) + .getSurveyBundle(); + final KeywordScores scores = + KeywordScores.of(submissions.stream().map(SurveySubmission::getSurvey).toList()); + characterService.createFirstCharacter( + member, onboardingBundle, scores.getValues(), submissions); } private Member getMember(Long memberId) { diff --git a/jaknaeso-core/src/main/resources/sql/095/005_alter_table_character_record.sql b/jaknaeso-core/src/main/resources/sql/095/005_alter_table_character_record.sql new file mode 100644 index 00000000..993bba0d --- /dev/null +++ b/jaknaeso-core/src/main/resources/sql/095/005_alter_table_character_record.sql @@ -0,0 +1,2 @@ +alter table character_record + add ordinal_number int null after id; diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java index f0ff65e7..4376040b 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/repository/CharacterRecordRepositoryTest.java @@ -9,6 +9,8 @@ import java.time.LocalDate; import java.util.List; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.nexters.jaknaesocore.common.model.ScaledBigDecimal; import org.nexters.jaknaesocore.common.support.IntegrationTest; @@ -43,30 +45,77 @@ void tearDown() { memberRepository.deleteAllInBatch(); } - @Test - void 회원의_현재_캐릭터를_조회한다() { - final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); - final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); - - sut.saveAll( - List.of( - CharacterRecord.builder() - .characterNo("첫번째") - .endDate(LocalDate.now().minusDays(15)) - .member(member) - .surveyBundle(bundle) - .build(), - CharacterRecord.builder() - .characterNo("두번째") - .endDate(LocalDate.now()) - .member(member) - .surveyBundle(bundle) - .build())); - - final CharacterRecord actual = - sut.findTopByMemberIdAndDeletedAtIsNullWithMember(member.getId()).get(); - - then(actual.getCharacterNo()).isEqualTo("두번째"); + @Nested + @DisplayName("findLatestCompletedCharacter 메소드는 ") + class findLatestCompletedCharacter { + + @Nested + @DisplayName("모든 데이터에 ValueCharacter가 지정되어 있으면, ") + class whenValueCharacterIsNotNull { + + @Test + void 가장_최신의_캐릭터를_조회한다() { + final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); + final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); + final ValueCharacter valueCharacter = + valueCharacterRepository.save(ValueCharacter.builder().build()); + + sut.saveAll( + List.of( + CharacterRecord.builder() + .characterNo("첫번째") + .endDate(LocalDate.now().minusDays(15)) + .member(member) + .surveyBundle(bundle) + .valueCharacter(valueCharacter) + .build(), + CharacterRecord.builder() + .characterNo("두번째") + .endDate(LocalDate.now()) + .member(member) + .surveyBundle(bundle) + .valueCharacter(valueCharacter) + .build())); + + final CharacterRecord actual = sut.findLatestCompletedCharacter(member.getId()).get(); + + then(actual.getCharacterNo()).isEqualTo("두번째"); + } + } + + @Nested + @DisplayName("지정된 ValueCharacter가 없는 데이터가 있는 경우, ") + class whenValueCharacterIsNull { + + @Test + void ValueCharacter가_있는_데이터만_고려하여_가장_최신의_캐릭터를_조회한다() { + final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); + final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); + final ValueCharacter valueCharacter = + valueCharacterRepository.save(ValueCharacter.builder().build()); + + sut.saveAll( + List.of( + CharacterRecord.builder() + .characterNo("첫번째") + .endDate(LocalDate.now().minusDays(15)) + .member(member) + .surveyBundle(bundle) + .valueCharacter(valueCharacter) + .build(), + CharacterRecord.builder() + .characterNo("두번째") + .endDate(LocalDate.now()) + .member(member) + .surveyBundle(bundle) + .valueCharacter(null) + .build())); + + final CharacterRecord actual = sut.findLatestCompletedCharacter(member.getId()).get(); + + then(actual.getCharacterNo()).isEqualTo("첫번째"); + } + } } @Test diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java index 17eb2852..21856b1e 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java @@ -10,6 +10,7 @@ import java.math.BigDecimal; import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.List; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.DisplayName; @@ -41,7 +42,6 @@ import org.nexters.jaknaesocore.domain.survey.repository.SurveyOptionRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveyRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveySubmissionRepository; -import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.annotation.DirtiesContext.ClassMode; @@ -304,12 +304,12 @@ void shouldReturnReport() { } @Nested - @DisplayName("createCharacter 메소드는") - class createCharacter { + @DisplayName("createFirstCharacter 메소드는") + class createFirstCharacter { @Transactional @Test - @DisplayName("회원의 캐릭터를 생성한다.") + @DisplayName("온보딩 후 회원의 첫번째 캐릭터를 생성한다.") void shouldCreateCharacter() { final Member member = memberRepository.save(Member.create("홍길동", "test@example.com")); final SurveyBundle bundle = surveyBundleRepository.save(new SurveyBundle()); @@ -388,18 +388,36 @@ void shouldCreateCharacter() { final List submissions = surveySubmissionRepository.saveAll( List.of( - SurveySubmission.builder().survey(survey1).selectedOption(option1).build(), - SurveySubmission.builder().survey(survey2).selectedOption(option2).build(), - SurveySubmission.builder().survey(survey3).selectedOption(option3).build(), - SurveySubmission.builder().survey(survey4).selectedOption(option4).build(), - SurveySubmission.builder().survey(survey5).selectedOption(option5).build())); + SurveySubmission.builder() + .survey(survey1) + .selectedOption(option1) + .submittedAt(LocalDateTime.of(2025, 2, 11, 0, 0)) + .build(), + SurveySubmission.builder() + .survey(survey2) + .selectedOption(option2) + .submittedAt(LocalDateTime.of(2025, 2, 12, 0, 0)) + .build(), + SurveySubmission.builder() + .survey(survey3) + .selectedOption(option3) + .submittedAt(LocalDateTime.of(2025, 2, 13, 0, 0)) + .build(), + SurveySubmission.builder() + .survey(survey4) + .selectedOption(option4) + .submittedAt(LocalDateTime.of(2025, 2, 14, 0, 0)) + .build(), + SurveySubmission.builder() + .survey(survey5) + .selectedOption(option5) + .submittedAt(LocalDateTime.of(2025, 2, 15, 0, 0)) + .build())); final KeywordScores scores = - new KeywordScores(List.of(survey1, survey2, survey3, survey4, survey5)); - final CreateCharacterEvent event = - new CreateCharacterEvent(member, bundle, scores.getKeywordScores(), submissions); + KeywordScores.of(List.of(survey1, survey2, survey3, survey4, survey5)); - sut.createCharacter(event); + sut.createFirstCharacter(member, bundle, scores.getValues(), submissions); assertAll( () -> then(characterRecordRepository.findAll()).hasSize(1), diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java index 11a3c7cd..5d83fdd3 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java @@ -3,9 +3,6 @@ import static org.assertj.core.api.BDDAssertions.then; import static org.assertj.core.api.BDDAssertions.thenThrownBy; import static org.assertj.core.api.BDDAssertions.tuple; -import static org.mockito.BDDMockito.any; -import static org.mockito.BDDMockito.never; -import static org.mockito.BDDMockito.verify; import static org.nexters.jaknaesocore.domain.survey.model.Keyword.SELF_DIRECTION; import java.math.BigDecimal; @@ -18,7 +15,10 @@ import org.junit.jupiter.api.Test; import org.nexters.jaknaesocore.common.support.IntegrationTest; import org.nexters.jaknaesocore.common.support.error.CustomException; +import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; +import org.nexters.jaknaesocore.domain.character.model.ValueCharacter; import org.nexters.jaknaesocore.domain.character.repository.CharacterRecordRepository; +import org.nexters.jaknaesocore.domain.character.repository.ValueCharacterRepository; import org.nexters.jaknaesocore.domain.character.repository.ValueReportRepository; import org.nexters.jaknaesocore.domain.character.service.CharacterService; import org.nexters.jaknaesocore.domain.member.model.Member; @@ -43,7 +43,6 @@ import org.nexters.jaknaesocore.domain.survey.repository.SurveyOptionRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveyRepository; import org.nexters.jaknaesocore.domain.survey.repository.SurveySubmissionRepository; -import org.nexters.jaknaesocore.domain.survey.service.event.CreateCharacterEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.bean.override.mockito.MockitoSpyBean; import org.springframework.transaction.annotation.Transactional; @@ -59,6 +58,7 @@ class SurveyServiceTest extends IntegrationTest { @Autowired private SurveyOptionRepository surveyOptionRepository; @Autowired private CharacterRecordRepository characterRecordRepository; @Autowired private ValueReportRepository valueReportRepository; + @Autowired private ValueCharacterRepository valueCharacterRepository; @MockitoSpyBean private CharacterService characterService; @@ -71,6 +71,7 @@ void tearDown() { surveyRepository.deleteAllInBatch(); surveyBundleRepository.deleteAllInBatch(); memberRepository.deleteAllInBatch(); + valueCharacterRepository.deleteAllInBatch(); } @DisplayName("설문을 조회한다.") @@ -664,30 +665,64 @@ void throwMemberNotFoundException() { } } - @DisplayName("설문을 저장한다") + @DisplayName("첫 설문을 시도하면, ") @Nested - class shouldSubmitted { + class whenFirstSubmitAndNotCompleted { @Test - void 설문에_응답을_제출한다() { + void 설문에_응답을_제출하고_빈_캐릭터를_생성한다() { // given Member member = Member.create("나민혁", "test@test.com"); memberRepository.save(member); - SurveyBundle surveyBundle = new SurveyBundle(); + + final ValueCharacter valueCharacter = + valueCharacterRepository.save( + ValueCharacter.builder() + .name("아낌없이 주는 보금자리 유형") + .description("보금자리 유형 설명") + .keyword(Keyword.BENEVOLENCE) + .build()); + + final SurveyBundle onboardingBundle = surveyBundleRepository.save(new SurveyBundle()); + OnboardingSurvey onboardingSurvey = + surveyRepository.save(new OnboardingSurvey("온보딩질문내용1", onboardingBundle)); + characterRecordRepository.save( + CharacterRecord.builder() + .valueCharacter(valueCharacter) + .ordinalNumber(1) + .characterNo("첫번째 캐릭터") + .member(member) + .surveyBundle(onboardingBundle) + .build()); + + final SurveyBundle surveyBundle = new SurveyBundle(); surveyBundleRepository.save(surveyBundle); - BalanceSurvey balanceSurvey = new BalanceSurvey("질문내용", surveyBundle); - surveyRepository.save(balanceSurvey); + BalanceSurvey balanceSurvey1 = + surveyRepository.save(new BalanceSurvey("질문내용1", surveyBundle)); + BalanceSurvey balanceSurvey2 = + surveyRepository.save(new BalanceSurvey("질문내용2", surveyBundle)); List scores = List.of( KeywordScore.builder().keyword(Keyword.ADVENTURE).score(BigDecimal.ONE).build(), KeywordScore.builder().keyword(Keyword.BENEVOLENCE).score(BigDecimal.TWO).build()); - SurveyOption option = - SurveyOption.builder().survey(balanceSurvey).scores(scores).content("질문 옵션 내용").build(); - surveyOptionRepository.save(option); + SurveyOption option1 = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(balanceSurvey1) + .scores(scores) + .content("질문 옵션 내용1") + .build()); + SurveyOption option2 = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(balanceSurvey2) + .scores(scores) + .content("질문 옵션 내용2") + .build()); SurveySubmissionCommand command = new SurveySubmissionCommand( - option.getId(), balanceSurvey.getId(), member.getId(), "나는 행복한게 좋으니까"); + option1.getId(), balanceSurvey1.getId(), member.getId(), "나는 행복한게 좋으니까"); // when LocalDateTime submittedAt = LocalDateTime.of(2025, 2, 13, 18, 0, 0); @@ -697,7 +732,15 @@ class shouldSubmitted { then(submissions).hasSize(1); then(submissions.getFirst()) .extracting("member.id", "survey.id", "selectedOption.id", "retrospective") - .containsExactly(member.getId(), balanceSurvey.getId(), option.getId(), "나는 행복한게 좋으니까"); + .containsExactly( + member.getId(), balanceSurvey1.getId(), option1.getId(), "나는 행복한게 좋으니까"); + then(characterRecordRepository.findAll()) + .hasSize(2) + .extracting( + "ordinalNumber", "characterNo", "member.id", "surveyBundle.id", "valueCharacter") + .containsExactly( + tuple(1, "첫번째 캐릭터", member.getId(), onboardingBundle.getId(), valueCharacter), + tuple(2, "두번째 캐릭터", member.getId(), surveyBundle.getId(), null)); } } @@ -765,6 +808,25 @@ void shouldCreateCharacter() { .build())) .build()); + // 가치관 캐릭터 + final ValueCharacter valueCharacter = + valueCharacterRepository.save( + ValueCharacter.builder() + .name("마이웨이 유형") + .description("마이웨이 유형 설명") + .keyword(SELF_DIRECTION) + .build()); + // 온보딩 캐릭터 + final SurveyBundle onboardingBundle = surveyBundleRepository.save(new SurveyBundle()); + characterRecordRepository.save( + CharacterRecord.builder() + .ordinalNumber(1) + .characterNo("첫번째 캐릭터") + .valueCharacter(valueCharacter) + .member(member) + .surveyBundle(onboardingBundle) + .build()); + final SurveySubmissionCommand command = new SurveySubmissionCommand( option.getId(), @@ -774,8 +836,22 @@ void shouldCreateCharacter() { final LocalDateTime submittedAt = LocalDateTime.of(2025, 2, 17, 0, 0, 0); surveyService.submitSurvey(command, submittedAt); - - verify(characterService).createCharacter(any(CreateCharacterEvent.class)); + then(characterRecordRepository.findAll()) + .hasSize(2) + .extracting( + "ordinalNumber", + "characterNo", + "member.id", + "surveyBundle.id", + "valueCharacter.id") + .containsExactly( + tuple( + 1, + "첫번째 캐릭터", + member.getId(), + onboardingBundle.getId(), + valueCharacter.getId()), + tuple(2, "두번째 캐릭터", member.getId(), bundle.getId(), valueCharacter.getId())); } } @@ -797,6 +873,7 @@ void shouldNotCreateCharacter() { final BalanceSurvey survey2 = surveyRepository.save( new BalanceSurvey("독립에 대한 고민이 깊어지는 요즘... 드디어 결정을 내렸다.", bundle)); + final BalanceSurvey survey3 = surveyRepository.save(new BalanceSurvey("세번째 질문", bundle)); final SurveyOption option1 = surveyOptionRepository.save( SurveyOption.builder() @@ -821,18 +898,37 @@ void shouldNotCreateCharacter() { .score(BigDecimal.ONE) .build())) .build()); + final SurveyOption option3 = + surveyOptionRepository.save( + SurveyOption.builder() + .survey(survey3) + .content("세번째 답변") + .scores( + List.of( + KeywordScore.builder() + .keyword(SELF_DIRECTION) + .score(BigDecimal.ONE) + .build())) + .build()); + + surveySubmissionRepository.save( + SurveySubmission.builder() + .survey(survey1) + .member(member) + .selectedOption(option1) + .submittedAt(LocalDateTime.of(2025, 2, 17, 0, 0, 0)) + .build()); final SurveySubmissionCommand command = new SurveySubmissionCommand( - option1.getId(), - survey1.getId(), + option2.getId(), + survey2.getId(), member.getId(), "자유롭게 일하면 집중이 잘되는 시간에 일할 수 있기 때문에 일의 능률이 오를 것 같다."); final LocalDateTime submittedAt = LocalDateTime.of(2025, 2, 17, 0, 0, 0); surveyService.submitSurvey(command, submittedAt); - - verify(characterService, never()).createCharacter(any(CreateCharacterEvent.class)); + then(characterRecordRepository.findAll()).hasSize(0); } } } From 32f94969a1aaca05968822c0da9b1ed9def762ba Mon Sep 17 00:00:00 2001 From: pythonstrup Date: Mon, 17 Feb 2025 20:50:20 +0900 Subject: [PATCH 19/22] =?UTF-8?q?[#95]=20test:=20=EC=98=A8=EB=B3=B4?= =?UTF-8?q?=EB=94=A9=20=EC=BA=90=EB=A6=AD=ED=84=B0=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../survey/service/SurveyServiceTest.java | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java index 5d83fdd3..b4eaab10 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/survey/service/SurveyServiceTest.java @@ -571,6 +571,14 @@ void getNextSurvey() { memberRepository.save(member); SurveyBundle surveyBundle = new SurveyBundle(); + final ValueCharacter valueCharacter = + valueCharacterRepository.save( + ValueCharacter.builder() + .name("아낌없이 주는 보금자리 유형") + .description("보금자리 유형 설명") + .keyword(Keyword.BENEVOLENCE) + .build()); + surveyBundleRepository.save(surveyBundle); OnboardingSurvey survey1 = @@ -588,19 +596,25 @@ void getNextSurvey() { surveyRepository.saveAll(List.of(survey1, survey2, survey3, survey4)); - List scores = + List scores1 = List.of( KeywordScore.builder().keyword(Keyword.ADVENTURE).score(BigDecimal.ONE).build(), KeywordScore.builder().keyword(Keyword.BENEVOLENCE).score(BigDecimal.TWO).build()); + List scores2 = + List.of( + KeywordScore.builder() + .keyword(Keyword.ADVENTURE) + .score(BigDecimal.valueOf(-1)) + .build()); SurveyOption option1 = - SurveyOption.builder().survey(survey1).scores(scores).content("전혀 나와 같지않다.").build(); + SurveyOption.builder().survey(survey1).scores(scores1).content("전혀 나와 같지않다.").build(); SurveyOption option2 = - SurveyOption.builder().survey(survey2).scores(scores).content("나와 같지 않다.").build(); + SurveyOption.builder().survey(survey2).scores(scores1).content("나와 같지 않다.").build(); SurveyOption option3 = - SurveyOption.builder().survey(survey3).scores(scores).content("나와 조금 같다.").build(); + SurveyOption.builder().survey(survey3).scores(scores2).content("나와 조금 같다.").build(); SurveyOption option4 = - SurveyOption.builder().survey(survey4).scores(scores).content("나와 같다.").build(); + SurveyOption.builder().survey(survey4).scores(scores2).content("나와 같다.").build(); surveyOptionRepository.saveAll(List.of(option1, option2, option3, option4)); LocalDateTime submittedAt = LocalDateTime.of(2025, 2, 13, 18, 25, 0); @@ -627,6 +641,25 @@ void getNextSurvey() { tuple(member.getId(), survey3.getId(), option3.getId(), submittedAt), tuple(member.getId(), survey4.getId(), option4.getId(), submittedAt)); then(member).extracting("completedOnboardingAt").isEqualTo(submittedAt); + then(characterRecordRepository.findAll()) + .hasSize(1) + .extracting( + "ordinalNumber", + "characterNo", + "member.id", + "surveyBundle.id", + "valueCharacter.id", + "startDate", + "endDate") + .containsExactly( + tuple( + 1, + "첫번째 캐릭터", + member.getId(), + surveyBundle.getId(), + valueCharacter.getId(), + submittedAt.toLocalDate(), + submittedAt.toLocalDate())); } @DisplayName("submitSurvey 메서드는") From b9ddddf0e67e8fdb659a3b26c667b7b0323a2067 Mon Sep 17 00:00:00 2001 From: pythonstrup Date: Mon, 17 Feb 2025 21:21:40 +0900 Subject: [PATCH 20/22] =?UTF-8?q?[#95]=20feat:=20=EC=BA=90=EB=A6=AD?= =?UTF-8?q?=ED=84=B0=20=EC=A0=95=EC=B1=85=20=EB=B3=80=EA=B2=BD=EC=97=90=20?= =?UTF-8?q?=EB=94=B0=EB=A5=B8=20=EC=BA=90=EB=A6=AD=ED=84=B0=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../character/service/CharacterService.java | 14 ++------ .../service/dto/SimpleCharacterResponse.java | 19 ++++++++++- .../service/dto/SimpleCharacterResponses.java | 34 +------------------ .../service/CharacterServiceTest.java | 12 ++++++- 4 files changed, 32 insertions(+), 47 deletions(-) diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java index bb5347df..cba5efc7 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java @@ -17,7 +17,7 @@ import org.nexters.jaknaesocore.domain.character.service.dto.CharacterValueReportCommand; import org.nexters.jaknaesocore.domain.character.service.dto.CharacterValueReportResponse; import org.nexters.jaknaesocore.domain.character.service.dto.CharactersResponse; -import org.nexters.jaknaesocore.domain.character.service.dto.SimpleCharacterResponses; +import org.nexters.jaknaesocore.domain.character.service.dto.SimpleCharacterResponse; import org.nexters.jaknaesocore.domain.member.model.Member; import org.nexters.jaknaesocore.domain.member.repository.MemberRepository; import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; @@ -60,17 +60,7 @@ public CharactersResponse getCharacters(final Long memberId) { final List records = characterRecordRepository.findByMemberIdAndDeletedAtIsNullWithMemberAndSurveyBundle( memberId); - - final SimpleCharacterResponses responses = - new SimpleCharacterResponses(getLatestBundleId(memberId), records); - return new CharactersResponse(responses.getResponses()); - } - - private Long getLatestBundleId(final Long memberId) { - return surveySubmissionRepository - .findTopByMember_IdAndDeletedAtIsNullOrderByCreatedAtDesc(memberId) - .map(it -> it.getSurvey().getSurveyBundle().getId()) - .orElse(null); + return new CharactersResponse(SimpleCharacterResponse.listOf(records)); } @Transactional(readOnly = true) diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java index 75af2dc0..761c7b52 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java @@ -1,7 +1,24 @@ package org.nexters.jaknaesocore.domain.character.service.dto; +import java.util.List; +import java.util.stream.Collectors; import lombok.Builder; +import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; @Builder public record SimpleCharacterResponse( - String characterNo, Long characterId, Long bundleId, Boolean isCompleted) {} + String characterNo, Long characterId, Long bundleId, Boolean isCompleted) { + + public static List listOf(final List records) { + return records.stream().map(SimpleCharacterResponse::of).collect(Collectors.toList()); + } + + public static SimpleCharacterResponse of(final CharacterRecord record) { + return SimpleCharacterResponse.builder() + .characterNo(record.getCharacterNo()) + .characterId(record.getId()) + .bundleId(record.getSurveyBundle().getId()) + .isCompleted(true) + .build(); + } +} diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java index 8caa41cd..5d9a7dcc 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java @@ -1,29 +1,10 @@ package org.nexters.jaknaesocore.domain.character.service.dto; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; public class SimpleCharacterResponses { - private List responses; - - public SimpleCharacterResponses(final Long latestBundleId, final List records) { - this.responses = records.stream().map(this::toCompletedResponse).collect(Collectors.toList()); - - if (isIncompleteCharacter(latestBundleId, records)) { - this.responses.add(toIncompleteResponse(latestBundleId)); - } - } - - private boolean isIncompleteCharacter(final Long bundleId, final List records) { - return bundleId != null - && records.stream() - .noneMatch(record -> Objects.equals(record.getSurveyBundle().getId(), bundleId)); - } - - private SimpleCharacterResponse toCompletedResponse(final CharacterRecord record) { + public static SimpleCharacterResponse of(final CharacterRecord record) { return SimpleCharacterResponse.builder() .characterNo(record.getCharacterNo()) .characterId(record.getId()) @@ -31,17 +12,4 @@ private SimpleCharacterResponse toCompletedResponse(final CharacterRecord record .isCompleted(true) .build(); } - - private SimpleCharacterResponse toIncompleteResponse(final Long bundleId) { - return SimpleCharacterResponse.builder() - .characterNo("TODO") - .characterId(null) - .bundleId(bundleId) - .isCompleted(false) - .build(); - } - - public List getResponses() { - return responses; - } } diff --git a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java index 21856b1e..1b97173f 100644 --- a/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java +++ b/jaknaeso-core/src/test/java/org/nexters/jaknaesocore/domain/character/service/CharacterServiceTest.java @@ -214,6 +214,16 @@ void shouldReturnCharacters() { .build()); final SurveyBundle incompleteBundle = surveyBundleRepository.save(new SurveyBundle()); + characterRecordRepository.save( + CharacterRecord.builder() + .characterNo("두번째") + .valueCharacter(null) + .startDate(LocalDate.now().minusDays(15)) + .endDate(LocalDate.now()) + .member(member) + .surveyBundle(incompleteBundle) + .build()); + final BalanceSurvey survey = surveyRepository.save( new BalanceSurvey( @@ -249,7 +259,7 @@ void shouldReturnCharacters() { () -> then(actual.characters().get(1)) .extracting("characterNo", "bundleId") - .containsExactly("TODO", incompleteBundle.getId())); // 추후 같이 수정 + .containsExactly("두번째", incompleteBundle.getId())); // 추후 같이 수정 } } } From 25fac90283ebf548caf13ee8ef76e3d0d73924a2 Mon Sep 17 00:00:00 2001 From: pythonstrup Date: Mon, 17 Feb 2025 21:35:09 +0900 Subject: [PATCH 21/22] =?UTF-8?q?[#95]=20feat:=20Characters=20=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95=20(=3D>=20ScoreEvaluato?= =?UTF-8?q?r)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{Characters.java => ScoreEvaluator.java} | 17 ++++++++++------- .../character/service/CharacterService.java | 12 +++++------- 2 files changed, 15 insertions(+), 14 deletions(-) rename jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/{Characters.java => ScoreEvaluator.java} (85%) diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/Characters.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ScoreEvaluator.java similarity index 85% rename from jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/Characters.java rename to jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ScoreEvaluator.java index 1877378b..63d75212 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/Characters.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/model/ScoreEvaluator.java @@ -5,28 +5,31 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import lombok.AccessLevel; import lombok.Builder; -import lombok.RequiredArgsConstructor; import org.nexters.jaknaesocore.common.model.ScaledBigDecimal; import org.nexters.jaknaesocore.domain.survey.model.Keyword; import org.nexters.jaknaesocore.domain.survey.model.KeywordMetrics; import org.nexters.jaknaesocore.domain.survey.model.KeywordScore; import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission; -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) -public class Characters { +public class ScoreEvaluator { private final List scores; private final List submissions; @Builder - public static Characters of( + private ScoreEvaluator( final List scores, final List submissions) { - return new Characters(scores, submissions); + this.scores = scores; + this.submissions = submissions; } - public List provideCharacterRecord() { + public static ScoreEvaluator of( + final List scores, final List submissions) { + return new ScoreEvaluator(scores, submissions); + } + + public List generateValueReports() { final List valueReports = provideValueReport(); return valueReports; } diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java index cba5efc7..105840c4 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/CharacterService.java @@ -6,7 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.nexters.jaknaesocore.common.support.error.CustomException; import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; -import org.nexters.jaknaesocore.domain.character.model.Characters; +import org.nexters.jaknaesocore.domain.character.model.ScoreEvaluator; import org.nexters.jaknaesocore.domain.character.model.ValueCharacter; import org.nexters.jaknaesocore.domain.character.model.ValueCharacters; import org.nexters.jaknaesocore.domain.character.model.ValueReport; @@ -79,9 +79,8 @@ public void createFirstCharacter( SurveyBundle bundle, List scores, List submissions) { - final Characters characters = - Characters.builder().scores(scores).submissions(submissions).build(); - final List valueReports = characters.provideCharacterRecord(); + final List valueReports = + ScoreEvaluator.of(scores, submissions).generateValueReports(); final ValueCharacter valueCharacter = ValueCharacters.of(valueCharacterRepository.findAll()).findTopValueCharacter(valueReports); characterRecordRepository.save( @@ -103,9 +102,8 @@ public void updateCharacter( SurveyBundle bundle, List scores, List submissions) { - final Characters characters = - Characters.builder().scores(scores).submissions(submissions).build(); - final List valueReports = characters.provideCharacterRecord(); + final List valueReports = + ScoreEvaluator.of(scores, submissions).generateValueReports(); final ValueCharacter valueCharacter = ValueCharacters.of(valueCharacterRepository.findAll()).findTopValueCharacter(valueReports); final CharacterRecord characterRecord = From 3108ac15705edb10d7a6c3597941fa7355f2debc Mon Sep 17 00:00:00 2001 From: pythonstrup Date: Mon, 17 Feb 2025 21:41:53 +0900 Subject: [PATCH 22/22] =?UTF-8?q?[#95]=20chore:=20=EC=BA=90=EB=A6=AD?= =?UTF-8?q?=ED=84=B0=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20API=20?= =?UTF-8?q?=EC=8A=A4=ED=8E=99=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/dto/SimpleCharacterResponse.java | 6 +++--- .../service/dto/SimpleCharacterResponses.java | 15 --------------- .../controller/CharacterControllerTest.java | 3 +++ 3 files changed, 6 insertions(+), 18 deletions(-) delete mode 100644 jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java index 761c7b52..fb452876 100644 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java +++ b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponse.java @@ -1,20 +1,20 @@ package org.nexters.jaknaesocore.domain.character.service.dto; import java.util.List; -import java.util.stream.Collectors; import lombok.Builder; import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; @Builder public record SimpleCharacterResponse( - String characterNo, Long characterId, Long bundleId, Boolean isCompleted) { + int ordinalNumber, String characterNo, Long characterId, Long bundleId, Boolean isCompleted) { public static List listOf(final List records) { - return records.stream().map(SimpleCharacterResponse::of).collect(Collectors.toList()); + return records.stream().map(SimpleCharacterResponse::of).toList(); } public static SimpleCharacterResponse of(final CharacterRecord record) { return SimpleCharacterResponse.builder() + .ordinalNumber(record.getOrdinalNumber()) .characterNo(record.getCharacterNo()) .characterId(record.getId()) .bundleId(record.getSurveyBundle().getId()) diff --git a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java b/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java deleted file mode 100644 index 5d9a7dcc..00000000 --- a/jaknaeso-core/src/main/java/org/nexters/jaknaesocore/domain/character/service/dto/SimpleCharacterResponses.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.nexters.jaknaesocore.domain.character.service.dto; - -import org.nexters.jaknaesocore.domain.character.model.CharacterRecord; - -public class SimpleCharacterResponses { - - public static SimpleCharacterResponse of(final CharacterRecord record) { - return SimpleCharacterResponse.builder() - .characterNo(record.getCharacterNo()) - .characterId(record.getId()) - .bundleId(record.getSurveyBundle().getId()) - .isCompleted(true) - .build(); - } -} diff --git a/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java b/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java index cd3123b5..d3f12c64 100644 --- a/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java +++ b/jaknaeso-server/src/test/java/org/nexters/jaknaesoserver/domain/character/controller/CharacterControllerTest.java @@ -71,6 +71,9 @@ class CharacterControllerTest extends ControllerTest { fieldWithPath("result") .type(SimpleType.STRING) .description("API 요청 결과 (성공/실패)"), + fieldWithPath("data.characters[].ordinalNumber") + .type(SimpleType.NUMBER) + .description("캐릭터 순서 번호"), fieldWithPath("data.characters[].characterNo") .type(SimpleType.STRING) .description("캐릭터 회차"),