diff --git a/auth/auth-interceptor/src/main/java/me/nalab/auth/interceptor/JwtDecryptInterceptorConfigurer.java b/auth/auth-interceptor/src/main/java/me/nalab/auth/interceptor/JwtDecryptInterceptorConfigurer.java index a84da892..b57b22da 100644 --- a/auth/auth-interceptor/src/main/java/me/nalab/auth/interceptor/JwtDecryptInterceptorConfigurer.java +++ b/auth/auth-interceptor/src/main/java/me/nalab/auth/interceptor/JwtDecryptInterceptorConfigurer.java @@ -32,6 +32,7 @@ public class JwtDecryptInterceptorConfigurer implements WebMvcConfigurer { "/v1/surveys/*/bookmarks/cancels", "/v1/gallerys/logins", "/v1/gallerys", + "/v1/surveys/bookmarks*", }; @Override diff --git a/support/e2e/v1_12_find_bookmarked_survey.hurl b/support/e2e/v1_12_find_bookmarked_survey.hurl new file mode 100644 index 00000000..96840ffe --- /dev/null +++ b/support/e2e/v1_12_find_bookmarked_survey.hurl @@ -0,0 +1,180 @@ +POST http://nalab-server:8080/v1/oauth/default # Default provider를 통해서 로그인 진행 +{ + "nickname": "find_bookmakred_survey1", + "email": "find_bookmakred_survey1@12345" +} + +HTTP 200 +[Asserts] +header "Content-type" == "application/json" + +jsonpath "$.access_token" exists +jsonpath "$.token_type" exists + +[Captures] +token_type_1: jsonpath "$.token_type" +auth_token_1: jsonpath "$.access_token" + +########## + +POST http://nalab-server:8080/v1/surveys # 발급받은 토큰으로 survey를 생성한다. +Authorization: {{ token_type_1 }} {{ auth_token_1 }} +{ + "question_count": 2, + "question": [ + { + "type": "choice", + "form_type": "tendency", + "title": "저는 UI, UI, GUI 중에 어떤 분야를 가장 잘하는 것 같나요?", + "choices": [ + { + "content": "UI", + "order": 1 + }, + { + "content": "UX", + "order": 2 + }, + { + "content": "GUI", + "order": 3 + } + ], + "max_selectable_count": 1, + "order": 1 + }, + { + "type": "short", + "form_type": "strength", + "title": "저는 UX, UI, GUI 중에 어떤 분야에 더 강점이 있나요?", + "order": 2 + } + ] +} + +HTTP 201 +[Asserts] +header "Content-type" == "application/json" + +jsonpath "$.survey_id" exists + +[Captures] +survey_id_1: jsonpath "$.survey_id" + +########## + +POST http://nalab-server:8080/v1/oauth/default # Default provider를 통해서 로그인 진행 +{ + "nickname": "find_bookmakred_survey2", + "email": "find_bookmakred_survey2@12345" +} + +HTTP 200 +[Asserts] +header "Content-type" == "application/json" + +jsonpath "$.access_token" exists +jsonpath "$.token_type" exists + +[Captures] +token_type_2: jsonpath "$.token_type" +auth_token_2: jsonpath "$.access_token" + +########## + +POST http://nalab-server:8080/v1/surveys # 발급받은 토큰으로 survey를 생성한다. +Authorization: {{ token_type_2 }} {{ auth_token_2 }} +{ + "question_count": 2, + "question": [ + { + "type": "choice", + "form_type": "tendency", + "title": "저는 UI, UI, GUI 중에 어떤 분야를 가장 잘하는 것 같나요?", + "choices": [ + { + "content": "UI", + "order": 1 + }, + { + "content": "UX", + "order": 2 + }, + { + "content": "GUI", + "order": 3 + } + ], + "max_selectable_count": 1, + "order": 1 + }, + { + "type": "short", + "form_type": "strength", + "title": "저는 UX, UI, GUI 중에 어떤 분야에 더 강점이 있나요?", + "order": 2 + } + ] +} + +HTTP 201 +[Asserts] +header "Content-type" == "application/json" + +jsonpath "$.survey_id" exists + +[Captures] +survey_id_2: jsonpath "$.survey_id" + +########## + +POST http://nalab-server:8080/v1/surveys/{{ survey_id_1 }}/bookmarks +Authorization: {{ token_type_1 }} {{ auth_token_1 }} + +HTTP 200 +[Asserts] +header "Content-type" == "application/json" + +jsonpath "$.survey_id" == {{ survey_id_1 }} + +########## + +POST http://nalab-server:8080/v1/surveys/{{ survey_id_2 }}/bookmarks +Authorization: {{ token_type_1 }} {{ auth_token_1 }} + +HTTP 200 +[Asserts] +header "Content-type" == "application/json" + +jsonpath "$.survey_id" == {{ survey_id_2 }} + +########## + +GET http://nalab-server:8080/v1/surveys/bookmarks +Authorization: {{ token_type_1 }} {{ auth_token_1 }} + +HTTP 200 +[Asserts] +header "Content-type" == "application/json" + +jsonpath "$.bookmarked_surveys.[0].survey_id" == {{ survey_id_1 }} +jsonpath "$.bookmarked_surveys.[0].nickname" == "find_bookmakred_survey1" + +jsonpath "$.bookmarked_surveys.[1].survey_id" == {{ survey_id_2 }} +jsonpath "$.bookmarked_surveys.[1].nickname" == "find_bookmakred_survey2" + +########## + +GET http://nalab-server:8080/v1/surveys/bookmarks +Authorization: {{ token_type_1 }} {{ auth_token_1 }} + +[QueryStringParams] +last-survey-id: {{ survey_id_1 }} +count: 1 + +HTTP 200 +[Asserts] +header "Content-type" == "application/json" + +jsonpath "$.bookmarked_surveys.[0].survey_id" == {{ survey_id_2 }} +jsonpath "$.bookmarked_surveys.[0].nickname" == "find_bookmakred_survey2" diff --git a/survey/survey-application/src/main/java/me/nalab/survey/application/port/in/web/bookmark/BookmarkedSurveyFindUseCase.java b/survey/survey-application/src/main/java/me/nalab/survey/application/port/in/web/bookmark/BookmarkedSurveyFindUseCase.java new file mode 100644 index 00000000..cee2568c --- /dev/null +++ b/survey/survey-application/src/main/java/me/nalab/survey/application/port/in/web/bookmark/BookmarkedSurveyFindUseCase.java @@ -0,0 +1,13 @@ +package me.nalab.survey.application.port.in.web.bookmark; + +import java.util.List; +import me.nalab.survey.application.common.survey.dto.SurveyBookmarkDto; + +public interface BookmarkedSurveyFindUseCase { + + /** + * targetId를 입력받아 SurveyBookmarkDto를 반환합니다. + */ + List findBookmarkedSurveysByTargetId(Long targetId, Long lastSurveyId, Integer count); + +} diff --git a/survey/survey-application/src/main/java/me/nalab/survey/application/port/out/persistence/findtarget/TargetFindPort.java b/survey/survey-application/src/main/java/me/nalab/survey/application/port/out/persistence/findtarget/TargetFindPort.java index 9cb96216..dcbb1ada 100644 --- a/survey/survey-application/src/main/java/me/nalab/survey/application/port/out/persistence/findtarget/TargetFindPort.java +++ b/survey/survey-application/src/main/java/me/nalab/survey/application/port/out/persistence/findtarget/TargetFindPort.java @@ -1,7 +1,8 @@ package me.nalab.survey.application.port.out.persistence.findtarget; +import java.util.List; import java.util.Optional; - +import java.util.Set; import me.nalab.survey.domain.target.Target; /** @@ -23,4 +24,8 @@ public interface TargetFindPort { */ Target getTargetById(Long targetId); + /** + * surveyId 들로 Target들을 조회합니다. + */ + List findAllTargetBySurveyIds(Set surveyIds); } diff --git a/survey/survey-application/src/main/java/me/nalab/survey/application/service/bookmark/BookmarkedSurveyFindService.java b/survey/survey-application/src/main/java/me/nalab/survey/application/service/bookmark/BookmarkedSurveyFindService.java new file mode 100644 index 00000000..bcba499e --- /dev/null +++ b/survey/survey-application/src/main/java/me/nalab/survey/application/service/bookmark/BookmarkedSurveyFindService.java @@ -0,0 +1,44 @@ +package me.nalab.survey.application.service.bookmark; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import me.nalab.survey.application.common.survey.dto.SurveyBookmarkDto; +import me.nalab.survey.application.port.in.web.bookmark.BookmarkedSurveyFindUseCase; +import me.nalab.survey.application.port.out.persistence.findtarget.TargetFindPort; +import me.nalab.survey.application.port.out.persistence.survey.find.SurveyFindPort; +import me.nalab.survey.domain.target.SurveyBookmark; +import me.nalab.survey.domain.target.Target; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class BookmarkedSurveyFindService implements BookmarkedSurveyFindUseCase { + + private final TargetFindPort targetFindPort; + private final SurveyFindPort surveyFindPort; + + @Override + @Transactional(readOnly = true) + public List findBookmarkedSurveysByTargetId(Long targetId, Long lastSurveyId, Integer count) { + var target = targetFindPort.getTargetById(targetId); + var bookmarkedTargets = targetFindPort.findAllTargetBySurveyIds(getSurveyIds(target, lastSurveyId, count)); + + return bookmarkedTargets.stream() + .map(bookmarkedTarget -> { + var surveyId = bookmarkedTarget.getSurveyList().get(0).getId(); + return SurveyBookmarkDto.from(surveyId, bookmarkedTarget); + }) + .toList(); + } + + private Set getSurveyIds(Target target, Long lastSurveyId, Integer count) { + return target.getBookmarkedSurveys().stream() + .map(SurveyBookmark::surveyId) + .filter(aLong -> aLong > lastSurveyId) + .limit(count) + .collect(Collectors.toSet()); + } +} diff --git a/survey/survey-jpa-adaptor/src/main/java/me/nalab/survey/jpa/adaptor/common/mapper/TargetEntityMapper.java b/survey/survey-jpa-adaptor/src/main/java/me/nalab/survey/jpa/adaptor/common/mapper/TargetEntityMapper.java index 5135c3cd..a3bfca35 100644 --- a/survey/survey-jpa-adaptor/src/main/java/me/nalab/survey/jpa/adaptor/common/mapper/TargetEntityMapper.java +++ b/survey/survey-jpa-adaptor/src/main/java/me/nalab/survey/jpa/adaptor/common/mapper/TargetEntityMapper.java @@ -1,7 +1,9 @@ package me.nalab.survey.jpa.adaptor.common.mapper; +import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import me.nalab.core.data.survey.SurveyEntity; import me.nalab.core.data.target.SurveyBookmarkEntity; import me.nalab.core.data.target.TargetEntity; import me.nalab.survey.domain.target.SurveyBookmark; @@ -40,6 +42,17 @@ public static Target toTarget(TargetEntity targetEntity) { .build(); } + public static Target toTargetWithSurvey(TargetEntity targetEntity, SurveyEntity surveyEntity) { + return Target.builder() + .id(targetEntity.getId()) + .surveyList(List.of(SurveyEntityMapper.toSurvey(surveyEntity))) + .nickname(targetEntity.getNickname()) + .position(targetEntity.getPosition()) + .job(targetEntity.getJob()) + .bookmarkedSurveys(toSurveyBookmark(targetEntity.getBookmarkedSurveys())) + .build(); + } + public static Set toSurveyBookmark(Set surveyBookmarkEntities) { return surveyBookmarkEntities.stream() .map(surveyBookmarkEntity -> new SurveyBookmark(surveyBookmarkEntity.getSurveyId())) diff --git a/survey/survey-jpa-adaptor/src/main/java/me/nalab/survey/jpa/adaptor/findtarget/TargetFindAdaptor.java b/survey/survey-jpa-adaptor/src/main/java/me/nalab/survey/jpa/adaptor/findtarget/TargetFindAdaptor.java index e31101c2..8dcb823d 100644 --- a/survey/survey-jpa-adaptor/src/main/java/me/nalab/survey/jpa/adaptor/findtarget/TargetFindAdaptor.java +++ b/survey/survey-jpa-adaptor/src/main/java/me/nalab/survey/jpa/adaptor/findtarget/TargetFindAdaptor.java @@ -1,8 +1,13 @@ package me.nalab.survey.jpa.adaptor.findtarget; +import java.util.List; +import java.util.Objects; import java.util.Optional; +import java.util.Set; +import me.nalab.core.data.survey.SurveyEntity; import me.nalab.survey.application.exception.TargetDoesNotExistException; +import me.nalab.survey.jpa.adaptor.findtarget.repository.TargetIdFindJpaRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Repository; @@ -17,11 +22,14 @@ public class TargetFindAdaptor implements TargetFindPort { private final TargetFindJpaRepository targetFindJpaRepository; + private final TargetIdFindJpaRepository targetIdFindJpaRepository; @Autowired TargetFindAdaptor( - @Qualifier("findtarget.TargetFindJpaRepository") TargetFindJpaRepository targetFindJpaRepository) { + @Qualifier("findtarget.TargetFindJpaRepository") TargetFindJpaRepository targetFindJpaRepository, + @Qualifier("findtarget.TargetIdFindJpaRepository") TargetIdFindJpaRepository targetIdFindJpaRepository) { this.targetFindJpaRepository = targetFindJpaRepository; + this.targetIdFindJpaRepository = targetIdFindJpaRepository; } @Override @@ -37,4 +45,29 @@ public Target getTargetById(Long targetId) { return TargetEntityMapper.toTarget(targetEntity); } + + @Override + public List findAllTargetBySurveyIds(Set surveyIds) { + var surveys = targetIdFindJpaRepository.findAllById(surveyIds); + var targetIds = surveys + .stream() + .map(SurveyEntity::getTargetId) + .toList(); + + return targetFindJpaRepository.findAllById(targetIds) + .stream() + .map(targetEntity -> { + var surveyEntity = getSurveyEntityByTargetId(targetEntity.getId(), surveys); + return TargetEntityMapper.toTargetWithSurvey(targetEntity, surveyEntity); + }) + .toList(); + } + + private SurveyEntity getSurveyEntityByTargetId(Long targetId, List surveyEntities) { + return surveyEntities.stream() + .filter(entity -> Objects.equals(entity.getTargetId(), targetId)) + .findFirst().orElseThrow( + () -> new IllegalStateException("Cannot find exist survey") + ); + } } diff --git a/survey/survey-web-adaptor/src/main/java/me/nalab/survey/web/adaptor/bookmark/BookmarkedSurveyFindController.java b/survey/survey-web-adaptor/src/main/java/me/nalab/survey/web/adaptor/bookmark/BookmarkedSurveyFindController.java new file mode 100644 index 00000000..c65105f9 --- /dev/null +++ b/survey/survey-web-adaptor/src/main/java/me/nalab/survey/web/adaptor/bookmark/BookmarkedSurveyFindController.java @@ -0,0 +1,33 @@ +package me.nalab.survey.web.adaptor.bookmark; + +import lombok.RequiredArgsConstructor; +import me.nalab.survey.application.port.in.web.bookmark.BookmarkedSurveyFindUseCase; +import me.nalab.survey.web.adaptor.bookmark.response.SurveyBookmarksResponse; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/v1") +@RequiredArgsConstructor +public class BookmarkedSurveyFindController { + + private final BookmarkedSurveyFindUseCase bookmarkedSurveyFindUseCase; + + @GetMapping("/surveys/bookmarks") + @ResponseStatus(HttpStatus.OK) + public SurveyBookmarksResponse findBookmarkedSurveys( + @RequestAttribute("logined") Long loginedTargetId, + @RequestParam(value = "last-survey-id", defaultValue = "0") Long lastSurveyId, + @RequestParam(value = "count", defaultValue = "20") Integer count + ) { + var bookmarkedSurveys = bookmarkedSurveyFindUseCase.findBookmarkedSurveysByTargetId(loginedTargetId, + lastSurveyId, count); + return SurveyBookmarksResponse.of(bookmarkedSurveys); + } + +} diff --git a/survey/survey-web-adaptor/src/main/java/me/nalab/survey/web/adaptor/bookmark/response/SurveyBookmarksResponse.java b/survey/survey-web-adaptor/src/main/java/me/nalab/survey/web/adaptor/bookmark/response/SurveyBookmarksResponse.java new file mode 100644 index 00000000..dcd711a1 --- /dev/null +++ b/survey/survey-web-adaptor/src/main/java/me/nalab/survey/web/adaptor/bookmark/response/SurveyBookmarksResponse.java @@ -0,0 +1,20 @@ +package me.nalab.survey.web.adaptor.bookmark.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import me.nalab.survey.application.common.survey.dto.SurveyBookmarkDto; + +public record SurveyBookmarksResponse( + @JsonProperty("bookmarked_surveys") + List bookmarkedSurveys +) { + + public static SurveyBookmarksResponse of(List surveyBookmarkDtos) { + return new SurveyBookmarksResponse( + surveyBookmarkDtos.stream() + .map(SurveyBookmarkResponse::of) + .toList() + ); + } + +}