Skip to content
Merged

D2M #159

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
fd24245
Merge pull request #153 from On-Survey/main
wonjuneee May 10, 2026
a7f4ce0
feat: μ—΄λ €μžˆλŠ” μ„€λ¬Έ 수 및 졜고 μ°Έμ—¬ 보상 코인 쑰회 API μΆ”κ°€
May 10, 2026
5a2028f
refactor: μ½”λ“œ 리뷰 반영
May 10, 2026
3dcd070
Merge pull request #154 from On-Survey/feat/OMF-337
KJaeKwan May 10, 2026
813b491
fix: /v1/surveys/open-stats 인증 ν•„ν„° ν—ˆμš© 경둜 μΆ”κ°€
May 10, 2026
68f930c
Merge branch 'feat/OMF-338' into develop
May 10, 2026
1ce6463
chore: open-stats AuthFilter에 μΆ”κ°€
May 10, 2026
cd118e8
test: 순수 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 λ‹¨μœ„ ν…ŒμŠ€νŠΈ μΆ”κ°€ (PR 1/9)
May 10, 2026
86b40c4
refactor: ν…ŒμŠ€νŠΈ μ½”λ“œ μ„Ήμ…˜ ꡬ뢄 주석 제거
May 10, 2026
b0a7269
test: Member 도메인 λ‹¨μœ„ ν…ŒμŠ€νŠΈ μΆ”κ°€ (PR 2/9)
May 10, 2026
77d9659
mod: μ„€λ¬Έ 정보 쑰회 μ‹œ μ„Ήμ…˜ 개수λ₯Ό λ°˜ν™˜ν•˜λ„λ‘ μˆ˜μ •ν•˜κ³ , 쿼리문 μ΅œμ ν™”
wonjuneee May 10, 2026
7d85811
chore: Deprecated된 API 및 λ―Έμ‚¬μš© λ©”μ„œλ“œ 제거
wonjuneee May 10, 2026
0b09e46
fix: section이 μ—†λŠ” 단일 μ„€λ¬Έμ˜ μ„Ήμ…˜ 개수λ₯Ό κΈ°λ³Έκ°’ 1둜 처리
wonjuneee May 10, 2026
fc84efc
Merge pull request #156 from On-Survey/feat/OMF-336
wonjuneee May 10, 2026
d679f6b
test: μž”μ—¬ μ„œλΉ„μŠ€ λ ˆμ΄μ–΄ λ‹¨μœ„ ν…ŒμŠ€νŠΈ 일괄 μž‘μ„±
May 10, 2026
d0f67fb
test: μž”μ—¬ μ„œλΉ„μŠ€ λ ˆμ΄μ–΄ λ‹¨μœ„ ν…ŒμŠ€νŠΈ μΆ”κ°€ (question, participation, formRequest)
May 10, 2026
4a18c93
refactor: @RepeatedTest 제거 및 ν™•λ₯ μ  λ‹€μ–‘μ„± ν…ŒμŠ€νŠΈ μ‚­μ œ
May 10, 2026
5acd05f
refactor: μ…€ν”„ 리뷰 반영 - λ―Έμ‚¬μš© import 정리, verify 보완, DisplayName κ°œμ„ 
May 10, 2026
830b9d8
test: 음수 경계 ν…ŒμŠ€νŠΈ 및 serviceAgreed 격리 ν…ŒμŠ€νŠΈ 반영
May 12, 2026
53fc238
test: CodeRabbit 반영 - 경계 μΌ€μ΄μŠ€, never matcher κ°œμ„ , ArgumentCaptor 적용
May 12, 2026
100ec79
Merge pull request #155 from On-Survey/feat/OMF-338-unit-tests
KJaeKwan May 12, 2026
39b3844
Merge pull request #157 from On-Survey/feat/OMF-339-member-tests
KJaeKwan May 12, 2026
210a140
Merge pull request #158 from On-Survey/feat/OMF-340-discount-query-tests
KJaeKwan May 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified gradlew
100644 β†’ 100755
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,16 @@
import OneQ.OnSurvey.domain.participation.entity.ScreeningAnswer;
import OneQ.OnSurvey.domain.participation.model.dto.AnswerInsertDto;
import OneQ.OnSurvey.domain.participation.model.dto.ParticipationCompletionDto;
import OneQ.OnSurvey.domain.participation.model.dto.ParticipationStatus;
import OneQ.OnSurvey.domain.participation.service.answer.AnswerCommand;
import OneQ.OnSurvey.domain.participation.service.response.ResponseCommand;
import OneQ.OnSurvey.domain.question.model.dto.type.DefaultQuestionDto;
import OneQ.OnSurvey.domain.question.service.QuestionQueryService;
import OneQ.OnSurvey.domain.survey.SurveyErrorCode;
import OneQ.OnSurvey.domain.survey.entity.Survey;
import OneQ.OnSurvey.domain.survey.model.SurveyStatus;
import OneQ.OnSurvey.domain.survey.model.request.InsertQuestionAnswerRequest;
import OneQ.OnSurvey.domain.survey.model.request.InsertScreeningAnswerRequest;
import OneQ.OnSurvey.domain.survey.model.request.SurveyParticipationCompletionRequest;
import OneQ.OnSurvey.domain.survey.model.response.*;
import OneQ.OnSurvey.domain.survey.repository.SurveyRepository;
import OneQ.OnSurvey.domain.survey.service.command.SurveyCommandService;
import OneQ.OnSurvey.domain.survey.service.query.SurveyQuery;
import OneQ.OnSurvey.global.auth.custom.CustomUserDetails;
import OneQ.OnSurvey.global.common.exception.CustomException;
import OneQ.OnSurvey.global.common.response.SuccessResponse;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.validation.Valid;
Expand All @@ -32,9 +25,6 @@
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("/v1/survey-participation")
Expand All @@ -47,9 +37,6 @@ public class ParticipationController {
private final ResponseCommand responseCommand;
private final SurveyCommandService surveyCommandService;

private final QuestionQueryService questionQueryService;
private final SurveyRepository surveyRepository;

@GetMapping("surveys/ongoing/all")
@Operation(summary = "μ—΄λ €μžˆλŠ” 섀문을 λͺ¨λ‘ μ‘°νšŒν•©λ‹ˆλ‹€.")
public SuccessResponse<SurveyParticipationResponse> getOngoingSurveyList(
Expand All @@ -68,89 +55,6 @@ public SuccessResponse<SurveyParticipationResponse> getOngoingSurveyList(
return SuccessResponse.ok(results);
}

@Deprecated(forRemoval = true)
@GetMapping("surveys/ongoing")
@Operation(summary = "λ…ΈμΆœ 쀑인 섀문을 μ‘°νšŒν•©λ‹ˆλ‹€.")
public SuccessResponse<SurveyParticipationResponse> getSurveyListOnGoing(
@AuthenticationPrincipal CustomUserDetails principal,
@RequestParam(required = false, defaultValue = "0") Long lastSurveyId,
@RequestParam(defaultValue = "15") Integer size
) {
log.info("[PARTICIPATION] λ…ΈμΆœ 쀑 μ„€λ¬Έ 쑰회 - lastSurveyId: {}, size: {}", lastSurveyId, size);

Pageable recommendedPageable = PageRequest.of(0, size, Sort.by("id"));
Pageable impendingPageable = PageRequest.of(0, size, Sort.by(
Sort.Order.asc("deadline"),
Sort.Order.asc("id")
));

SurveyParticipationResponse.SliceSurveyData recommended = surveyQueryService.getParticipationSurveyList(
lastSurveyId, recommendedPageable, SurveyStatus.ONGOING, principal.getMemberId(), principal.getUserKey()
);
SurveyParticipationResponse.SliceSurveyData impending = surveyQueryService.getParticipationSurveyList(
lastSurveyId, LocalDateTime.now(), impendingPageable, SurveyStatus.ONGOING, principal.getMemberId(), principal.getUserKey()
);

SurveyParticipationResponse response = SurveyParticipationResponse.builder()
.recommended(recommended.getSurveyDataList())
.impending(impending.getSurveyDataList())
.recommendedHasNext(recommended.getHasNext())
.impendingHasNext(impending.getHasNext())
.build();

return SuccessResponse.ok(response);
}

@Deprecated(forRemoval = true)
@GetMapping("surveys/ongoing/recommended")
@Operation(summary = "μ‚¬μš©μž μΆ”μ²œ 섀문을 μ‘°νšŒν•©λ‹ˆλ‹€.")
public SuccessResponse<SurveyParticipationResponse> getRecommendedSurveyList(
@AuthenticationPrincipal CustomUserDetails principal,
@RequestParam(required = false, defaultValue = "0") Long lastSurveyId,
@RequestParam(defaultValue = "15") Integer size
) {
log.info("[PARTICIPATION] μ‚¬μš©μž μΆ”μ²œ μ„€λ¬Έ 쑰회 - lastSurveyId: {}, size: {}", lastSurveyId, size);

Pageable pageable = PageRequest.of(0, size, Sort.by("id"));
SurveyParticipationResponse.SliceSurveyData recommended =
surveyQueryService.getParticipationSurveyList(lastSurveyId, pageable, SurveyStatus.ONGOING, principal.getMemberId(), principal.getUserKey()
);

SurveyParticipationResponse response = SurveyParticipationResponse.builder()
.recommended(recommended.getSurveyDataList())
.recommendedHasNext(recommended.getHasNext())
.build();

return SuccessResponse.ok(response);
}

@Deprecated(forRemoval = true)
@GetMapping("surveys/ongoing/impending")
@Operation(summary = "마감 μž„λ°• 섀문을 μ‘°νšŒν•©λ‹ˆλ‹€.")
public SuccessResponse<SurveyParticipationResponse> getImpendingSurveyList(
@AuthenticationPrincipal CustomUserDetails principal,
@RequestParam(required = false, defaultValue = "0") Long lastSurveyId,
@RequestParam(required = false) LocalDateTime lastDeadline,
@RequestParam(defaultValue = "15") Integer size
) {
log.info("[PARTICIPATION] 마감 μž„λ°• μ„€λ¬Έ 쑰회 - lastSurveyId: {}, lastDeadline: {}, size: {}", lastSurveyId, lastDeadline, size);

Pageable pageable = PageRequest.of(0, size, Sort.by(
Sort.Order.asc("deadline"),
Sort.Order.asc("id")
));
SurveyParticipationResponse.SliceSurveyData impending =
surveyQueryService.getParticipationSurveyList(lastSurveyId, lastDeadline, pageable, SurveyStatus.ONGOING, principal.getMemberId(), principal.getUserKey()
);

SurveyParticipationResponse response = SurveyParticipationResponse.builder()
.impending(impending.getSurveyDataList())
.impendingHasNext(impending.getHasNext())
.build();

return SuccessResponse.ok(response);
}

@GetMapping("surveys/info")
@Operation(summary = "μ„ νƒν•œ μ„€λ¬Έμ˜ κΈ°λ³Έ 정보λ₯Ό μ‘°νšŒν•©λ‹ˆλ‹€.")
public SuccessResponse<ParticipationInfoResponse> getSurveyInfo(
Expand All @@ -174,36 +78,6 @@ public SuccessResponse<ParticipationQuestionResponse> getQuestionsOfSurveyId(
return SuccessResponse.ok(surveyQueryService.getParticipationQuestionInfo(surveyId, section, principal.getUserKey()));
}

/**
* @deprecated
* @code GET /surveys/info
* @code GET /surveys/questions
*/
@Deprecated(forRemoval = true)
@GetMapping("surveys")
@Operation(summary = "μ„ νƒν•œ 섀문을 μ‘°νšŒν•©λ‹ˆλ‹€.")
public SuccessResponse<DeprecatedQuestionResponse> getTotalSurveyInfoOfSurveyId(
@RequestParam Long surveyId,
@AuthenticationPrincipal CustomUserDetails principal
) {
log.info("[PARTICIPATION] μ‘λ‹΅ν•˜κ³ μž ν•˜λŠ” μ„€λ¬Έ λ¬Έν•­μ‘°νšŒ - surveyId: {}", surveyId);

Survey survey = surveyQueryService.getSurveyById(surveyId);

if (surveyQueryService.checkValidSegmentation(surveyId, principal.getUserKey())) {
log.warn("[PARTICIPATION] μ„Έκ·Έλ¨ΌνŠΈ 뢈일치둜 μΈν•œ μ„€λ¬Έ 응닡 λΆˆκ°€ - surveyId: {}, userKey: {}", surveyId, principal.getUserKey());
throw new CustomException(SurveyErrorCode.SURVEY_WRONG_SEGMENTATION);
}

List<DefaultQuestionDto> questionDtoList = questionQueryService.getQuestionDtoListBySurveyId(surveyId);
ParticipationStatus participationStatus = surveyRepository.getParticipationStatus(surveyId, principal.getMemberId());

DeprecatedQuestionResponse body =
DeprecatedQuestionResponse.of(survey, questionDtoList, participationStatus);

return SuccessResponse.ok(body);
}

@GetMapping("surveys/screenings")
@Operation(summary = "μ„Έκ·Έλ©˜ν…Œμ΄μ…˜μ— μΌμΉ˜ν•˜λŠ” μ„€λ¬Έμ˜ μŠ€ν¬λ¦¬λ‹ 문항을 μ‘°νšŒν•©λ‹ˆλ‹€.")
public SuccessResponse<ParticipationScreeningListResponse> getRecommendedScreenings(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package OneQ.OnSurvey.domain.survey.controller;

import OneQ.OnSurvey.domain.survey.model.dto.GlobalStats;
import OneQ.OnSurvey.domain.survey.model.dto.OpenSurveyStats;
import OneQ.OnSurvey.domain.survey.model.response.GlobalStatsResponse;
import OneQ.OnSurvey.domain.survey.model.response.OpenSurveyStatsResponse;
import OneQ.OnSurvey.domain.survey.service.SurveyGlobalStatsService;
import OneQ.OnSurvey.domain.survey.service.query.SurveyQuery;
import OneQ.OnSurvey.global.common.response.SuccessResponse;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
Expand All @@ -16,11 +19,19 @@
public class SurveyStatsController {

private final SurveyGlobalStatsService surveyGlobalStatsService;
private final SurveyQuery surveyQuery;

@GetMapping("/global-stats")
@Operation(summary = "전체 μ„€λ¬Έ μ „μ—­ 톡계 쑰회", description = "전체 섀문에 λŒ€ν•œ 총 λͺ©ν‘œ 수/μ°Έμ—¬μž 수/ν”„λ‘œλͺ¨μ…˜ μ§€κΈ‰μž 수/일간 ν™œμ„± μ‚¬μš©μž 수λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.")
public SuccessResponse<GlobalStatsResponse> getGlobalStats() {
GlobalStats stats = surveyGlobalStatsService.getStats();
return SuccessResponse.ok(GlobalStatsResponse.from(stats));
}

@GetMapping("/open-stats")
@Operation(summary = "μ—΄λ¦° μ„€λ¬Έ 톡계 쑰회", description = "ν˜„μž¬ μ§„ν–‰ 쀑인 μ„€λ¬Έ μˆ˜μ™€ κ°€μž₯ 높은 μ°Έμ—¬ 보상 코인 κΈˆμ•‘μ„ λ°˜ν™˜ν•©λ‹ˆλ‹€.")
public SuccessResponse<OpenSurveyStatsResponse> getOpenStats() {
OpenSurveyStats stats = surveyQuery.getOpenSurveyStats();
return SuccessResponse.ok(OpenSurveyStatsResponse.from(stats));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package OneQ.OnSurvey.domain.survey.model.dto;

public record OpenSurveyStats(
Long openSurveyCount,
Integer maxRewardCoin
) {
public static OpenSurveyStats of(Long openSurveyCount, Integer maxRewardCoin) {
return new OpenSurveyStats(
openSurveyCount != null ? openSurveyCount : 0L,
maxRewardCoin != null ? maxRewardCoin : 0
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package OneQ.OnSurvey.domain.survey.model.dto;

import OneQ.OnSurvey.domain.member.value.Interest;
import OneQ.OnSurvey.domain.participation.model.dto.ParticipationStatus;

import java.time.LocalDateTime;
import java.util.Set;

public record ParticipationInfoVO(
Long surveyId,
String title,
String description,
Integer totalSections,
LocalDateTime deadline,
Set<Interest> interests,
ParticipationStatus participationStatus,
Boolean isFree
) {
public ParticipationInfoVO(
Long surveyId,
String title,
String description,
Integer totalSections,
LocalDateTime deadline,
Set<Interest> interests,
Long screeningId,
Boolean eIsScreened,
Boolean eIsResponded,
Boolean isFree
) {
this(
surveyId, title, description, totalSections, deadline, interests,
ParticipationStatus.generateStatus(screeningId, eIsScreened, eIsResponded),
isFree
);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package OneQ.OnSurvey.domain.survey.model.response;

import OneQ.OnSurvey.domain.survey.model.dto.OpenSurveyStats;

public record OpenSurveyStatsResponse(
Long openSurveyCount,
Integer maxRewardCoin
) {
public static OpenSurveyStatsResponse from(OpenSurveyStats stats) {
return new OpenSurveyStatsResponse(stats.openSurveyCount(), stats.maxRewardCoin());
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
package OneQ.OnSurvey.domain.survey.model.response;

import OneQ.OnSurvey.domain.member.value.Interest;
import OneQ.OnSurvey.domain.participation.model.dto.ParticipationStatus;
import OneQ.OnSurvey.domain.survey.entity.Survey;
import OneQ.OnSurvey.domain.survey.model.dto.ParticipationInfoVO;

import java.time.LocalDateTime;
import java.util.Set;
Expand All @@ -11,6 +10,7 @@ public record ParticipationInfoResponse(
Long surveyId,
String title,
String description,
Integer totalSections,
LocalDateTime deadline,
Set<Interest> interests,
Integer responseCount,
Expand All @@ -20,19 +20,12 @@ public record ParticipationInfoResponse(
Boolean isFree
) {
public static ParticipationInfoResponse from(
Survey survey, int responseCount, ParticipationStatus participationStatus
ParticipationInfoVO vo, int responseCount
) {
return new ParticipationInfoResponse(
survey.getId(),
survey.getTitle(),
survey.getDescription(),
survey.getDeadline(),
survey.getInterests(),
responseCount,
participationStatus.isScreenRequired(),
participationStatus.isScreened(),
participationStatus.isSurveyResponded(),
survey.getIsFree()
vo.surveyId(), vo.title(), vo.description(), vo.totalSections(), vo.deadline(), vo.interests(), responseCount,
vo.participationStatus().isScreenRequired(), vo.participationStatus().isScreened(), vo.participationStatus().isSurveyResponded(),
vo.isFree()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package OneQ.OnSurvey.domain.survey.repository;

import OneQ.OnSurvey.domain.member.dto.MemberSegmentation;
import OneQ.OnSurvey.domain.participation.model.dto.ParticipationStatus;
import OneQ.OnSurvey.domain.survey.entity.Survey;
import OneQ.OnSurvey.domain.survey.model.SurveyStatus;
import OneQ.OnSurvey.domain.survey.model.dto.OngoingSurveyStats;
import OneQ.OnSurvey.domain.survey.model.dto.OpenSurveyStats;
import OneQ.OnSurvey.domain.survey.model.dto.SurveyDetailData;
import OneQ.OnSurvey.domain.survey.model.dto.ParticipationInfoVO;
import OneQ.OnSurvey.domain.survey.model.dto.SurveyListView;
import OneQ.OnSurvey.domain.survey.model.dto.SurveySearchQuery;
import OneQ.OnSurvey.domain.survey.model.dto.SurveyWithEligibility;
Expand All @@ -29,12 +30,10 @@ List<Long> getSurveyIdListByFilters(
Slice<SurveyWithEligibility> getSurveyListWithEligibility(
Long lastSurveyId, LocalDateTime lastDeadline, Pageable pageable,
SurveyStatus status, Long creatorId, Collection<Long> excludedIds, MemberSegmentation memberSegmentation);

Survey save(Survey survey);

SurveyStatus getSurveyStatusById(Long surveyId);
ParticipationStatus getParticipationStatus(Long surveyId, Long memberId);
List<Long> closeDueSurveys();

List<OngoingSurveyStats> findOngoingSurveys();
OpenSurveyStats findOpenSurveyStats();
ParticipationInfoVO getParticipationInfoVO(Long surveyId, Long memberId);
}
Loading
Loading