Skip to content

Commit

Permalink
[#59] feat: 온보딩 설문 제출 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
NaMinhyeok committed Feb 14, 2025
1 parent 33d0a89 commit e6c7b49
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package org.nexters.jaknaesocore.domain.survey.dto;

public record OnboardingSubmissionResult(Long surveyId, Long optionId) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.nexters.jaknaesocore.domain.survey.dto;

import java.util.List;

public record OnboardingSubmissionsCommand(
List<OnboardingSubmissionResult> submissions, Long memberId) {}
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package org.nexters.jaknaesocore.domain.survey.repository;

import java.util.List;
import org.nexters.jaknaesocore.domain.survey.model.Survey;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

public interface SurveyRepository extends JpaRepository<Survey, Long> {}
public interface SurveyRepository extends JpaRepository<Survey, Long> {

@Query("SELECT s FROM Survey s JOIN FETCH s.options WHERE s.id IN :surveyIds")
List<Survey> findAllByIdWithOptions(List<Long> surveyIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.nexters.jaknaesocore.common.model.BaseEntity;
Expand Down Expand Up @@ -144,4 +142,64 @@ public OnboardingSurveyResponse getOnboardingSurveys() {
.map(SurveyResponse::of)
.collect(Collectors.collectingAndThen(Collectors.toList(), OnboardingSurveyResponse::new));
}

@Transactional
public void submitOnboardingSurvey(
OnboardingSubmissionsCommand command, LocalDateTime submittedAt) {
Member member = getMember(command.memberId());

List<Long> surveyIds = extractSurveyIdsBy(command);
Map<Long, Survey> surveyMap = createSurveyMapBy(surveyIds);

Map<Survey, SurveyOption> surveyToSelectedOption =
createSurveyToSelectedOption(command.submissions(), surveyMap);

List<SurveySubmission> submissions =
createSubmissionsBy(submittedAt, surveyToSelectedOption, member);

surveySubmissionRepository.saveAll(submissions);
}

private Member getMember(Long memberId) {
return memberRepository.findById(memberId).orElseThrow(() -> CustomException.MEMBER_NOT_FOUND);
}

private Map<Long, Survey> createSurveyMapBy(List<Long> surveyIds) {
return surveyRepository.findAllByIdWithOptions(surveyIds).stream()
.collect(Collectors.toMap(Survey::getId, survey -> survey));
}

private List<SurveySubmission> createSubmissionsBy(
LocalDateTime submittedAt, Map<Survey, SurveyOption> surveyToSelectedOption, Member member) {
return surveyToSelectedOption.entrySet().stream()
.map(
entry ->
SurveySubmission.create(
member, entry.getKey(), entry.getValue(), null, submittedAt))
.toList();
}

private List<Long> extractSurveyIdsBy(OnboardingSubmissionsCommand command) {
return command.submissions().stream()
.map(OnboardingSubmissionResult::surveyId)
.distinct()
.toList();
}

private Map<Survey, SurveyOption> createSurveyToSelectedOption(
List<OnboardingSubmissionResult> submissionResults, Map<Long, Survey> surveyMap) {
Map<Survey, SurveyOption> surveyOptionMap =
submissionResults.stream()
.map(
submission -> {
Survey survey = surveyMap.get(submission.surveyId());
if (survey == null) {
throw CustomException.SURVEY_NOT_FOUND;
}
SurveyOption option = survey.getOptionById(submission.optionId());
return Map.entry(survey, option);
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return surveyOptionMap;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -631,4 +631,68 @@ void throwSurveyNotFoundException() {
"그/그녀에게 자신의 능력을 보여주는 것이 매우 중요하다. 사람들이 자신이 하는 일을 인정해주길 바란다.",
"ONBOARDING"));
}

@Test
void 온보딩_설문을_제출한다() {
// given
Member member = Member.create("나민혁", "[email protected]");
memberRepository.save(member);
SurveyBundle surveyBundle = new SurveyBundle();

surveyBundleRepository.save(surveyBundle);

OnboardingSurvey survey1 =
new OnboardingSurvey(
"새로운 아이디어를 갖고 창의적인 것이 그/그녀에게 중요하다. 그/그녀는 일을 자신만의 독특한 방식으로 하는 것을 좋아한다.", surveyBundle);
OnboardingSurvey survey2 =
new OnboardingSurvey("그/그녀에게 부자가 되는 것은 중요하다. 많은 돈과 비싼 물건들을 가지길 원한다.", surveyBundle);
OnboardingSurvey survey3 =
new OnboardingSurvey(
"세상의 모든 사람들이 평등하게 대우받아야 한다고 생각한다. 그/그녀는 모든 사람이 인생에서 동등한 기회를 가져야 한다고 믿는다.",
surveyBundle);
OnboardingSurvey survey4 =
new OnboardingSurvey(
"그/그녀에게 자신의 능력을 보여주는 것이 매우 중요하다. 사람들이 자신이 하는 일을 인정해주길 바란다.", surveyBundle);

surveyRepository.saveAll(List.of(survey1, survey2, survey3, survey4));

List<KeywordScore> scores =
List.of(
KeywordScore.builder().keyword(Keyword.ADVENTURE).score(BigDecimal.ONE).build(),
KeywordScore.builder().keyword(Keyword.BENEVOLENCE).score(BigDecimal.TWO).build());

SurveyOption option1 =
SurveyOption.builder().survey(survey1).scores(scores).content("전혀 나와 같지않다.").build();
SurveyOption option2 =
SurveyOption.builder().survey(survey2).scores(scores).content("나와 같지 않다.").build();
SurveyOption option3 =
SurveyOption.builder().survey(survey3).scores(scores).content("나와 조금 같다.").build();
SurveyOption option4 =
SurveyOption.builder().survey(survey4).scores(scores).content("나와 같다.").build();

surveyOptionRepository.saveAll(List.of(option1, option2, option3, option4));
LocalDateTime submittedAt = LocalDateTime.now();

OnboardingSubmissionsCommand command =
new OnboardingSubmissionsCommand(
List.of(
new OnboardingSubmissionResult(survey1.getId(), option1.getId()),
new OnboardingSubmissionResult(survey2.getId(), option2.getId()),
new OnboardingSubmissionResult(survey3.getId(), option3.getId()),
new OnboardingSubmissionResult(survey4.getId(), option4.getId())),
member.getId());
// when
surveyService.submitOnboardingSurvey(command, submittedAt);
// then
List<SurveySubmission> submissions = surveySubmissionRepository.findAll();

then(submissions).hasSize(4);
then(submissions)
.extracting("member.id", "survey.id", "selectedOption.id", "submittedAt")
.containsExactlyInAnyOrder(
tuple(member.getId(), survey1.getId(), option1.getId(), submittedAt),
tuple(member.getId(), survey2.getId(), option2.getId(), submittedAt),
tuple(member.getId(), survey3.getId(), option3.getId(), submittedAt),
tuple(member.getId(), survey4.getId(), option4.getId(), submittedAt));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.nexters.jaknaesocore.domain.survey.dto.*;
import org.nexters.jaknaesocore.domain.survey.service.SurveyService;
import org.nexters.jaknaesoserver.domain.auth.model.CustomUserDetails;
import org.nexters.jaknaesoserver.domain.survey.controller.dto.OnboardingSubmissionRequest;
import org.nexters.jaknaesoserver.domain.survey.controller.dto.SurveySubmissionRequest;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
Expand Down Expand Up @@ -67,4 +68,15 @@ public ApiResponse<SurveySubmissionHistoryResponse> getSurveyHistoryByMemberId(
public ApiResponse<OnboardingSurveyResponse> getOnboardingSurvey() {
return ApiResponse.success(surveyService.getOnboardingSurveys());
}

@ResponseStatus(HttpStatus.NO_CONTENT)
@PostMapping("/onboarding/submission")
public ApiResponse<?> submitOnboardingSurvey(
@AuthenticationPrincipal CustomUserDetails member,
@Valid @RequestBody OnboardingSubmissionRequest request) {
LocalDateTime submittedAt = LocalDateTime.now();

surveyService.submitOnboardingSurvey(request.toCommand(member.getMemberId()), submittedAt);
return ApiResponse.success();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package org.nexters.jaknaesoserver.domain.survey.controller.dto;

public record OnboardingSubmissionInfoRequest(Long surveyId, Long optionId) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.nexters.jaknaesoserver.domain.survey.controller.dto;

import java.util.List;
import org.nexters.jaknaesocore.domain.survey.dto.OnboardingSubmissionResult;
import org.nexters.jaknaesocore.domain.survey.dto.OnboardingSubmissionsCommand;

public record OnboardingSubmissionRequest(List<OnboardingSubmissionInfoRequest> submissionsInfo) {
public OnboardingSubmissionsCommand toCommand(Long memberId) {
return new OnboardingSubmissionsCommand(
submissionsInfo.stream()
.map(
submissionInfo ->
new OnboardingSubmissionResult(
submissionInfo.surveyId(), submissionInfo.optionId()))
.toList(),
memberId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.nexters.jaknaesocore.domain.survey.model.SurveyRecord;
import org.nexters.jaknaesoserver.common.support.ControllerTest;
import org.nexters.jaknaesoserver.common.support.WithMockCustomUser;
import org.nexters.jaknaesoserver.domain.survey.controller.dto.OnboardingSubmissionInfoRequest;
import org.nexters.jaknaesoserver.domain.survey.controller.dto.OnboardingSubmissionRequest;
import org.nexters.jaknaesoserver.domain.survey.controller.dto.SurveySubmissionRequest;
import org.springframework.http.MediaType;

Expand Down Expand Up @@ -350,4 +352,48 @@ void getSurveyHistory() throws Exception {
.responseSchema(Schema.schema("onboardingSurveyResponse"))
.build())));
}

@WithMockCustomUser
@Test
void 온보딩_설문에_응답을_제출한다() throws Exception {
willDoNothing()
.given(surveyService)
.submitOnboardingSurvey(any(OnboardingSubmissionsCommand.class), any(LocalDateTime.class));

OnboardingSubmissionRequest request =
new OnboardingSubmissionRequest(
List.of(
new OnboardingSubmissionInfoRequest(1L, 1L),
new OnboardingSubmissionInfoRequest(2L, 7L),
new OnboardingSubmissionInfoRequest(3L, 13L)));

mockMvc
.perform(
post("/api/v1/surveys/onboarding/submission")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(request))
.with(csrf()))
.andExpect(status().isNoContent())
.andDo(
document(
"survey-submit-onboarding",
resource(
ResourceSnippetParameters.builder()
.description("온보딩 설문 제출")
.tag("Survey Domain")
.requestFields(
fieldWithPath("submissionsInfo[].surveyId")
.type(SimpleType.NUMBER)
.description("설문 ID"),
fieldWithPath("submissionsInfo[].optionId")
.type(SimpleType.NUMBER)
.description("설문지 선택지 ID"))
.responseFields(
fieldWithPath("result").type(SimpleType.STRING).description("결과"),
fieldWithPath("data").description("데이터").optional(),
fieldWithPath("error").description("에러").optional())
.requestSchema(Schema.schema("onboardingSubmissionRequest"))
.responseSchema(Schema.schema("surveyResponse"))
.build())));
}
}

0 comments on commit e6c7b49

Please sign in to comment.