diff --git a/src/main/java/com/haru/api/domain/moodTracker/controller/MoodTrackerController.java b/src/main/java/com/haru/api/domain/moodTracker/controller/MoodTrackerController.java index fb739eb7..6fae7c65 100644 --- a/src/main/java/com/haru/api/domain/moodTracker/controller/MoodTrackerController.java +++ b/src/main/java/com/haru/api/domain/moodTracker/controller/MoodTrackerController.java @@ -12,6 +12,7 @@ import com.haru.api.global.annotation.AuthUser; import com.haru.api.global.annotation.AuthWorkspace; import com.haru.api.global.apiPayload.code.status.SuccessStatus; +import com.haru.api.global.util.HashIdUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; @@ -32,6 +33,7 @@ public class MoodTrackerController { // 읽기 전용 private final MoodTrackerQueryService moodTrackerQueryService; + private final HashIdUtil hashIdUtil; @GetMapping("/workspaces/{workspaceId}") @@ -137,39 +139,36 @@ public ApiResponse sendMoodTrackerSurveyLink( @PostMapping("/{mood-tracker-hashed-Id}/answer") @Operation( - summary = "분위기 트래커 설문 답변 제출 API", - description = "# [v1.1 (2025-08-05)](https://www.notion.so/2265da7802c580c58d36e73639e41291) 해당 ID의 분위기 트래커 설문 답변을 제출합니다." + summary = "분위기 트래커 설문 답변 제출 API (비인증)", + description = "# [v1.2 (2025-08-19)](https://www.notion.so/2265da7802c580c58d36e73639e41291) 해당 ID의 분위기 트래커 설문 답변을 제출합니다." ) @Parameters({ @Parameter(name = "mood-tracker-hashed-Id", description = "해시된 16자 분위기 트래커 ID (Path Variable)", required = true) }) public ApiResponse submitMoodTrackerSurveyAnswers( @PathVariable("mood-tracker-hashed-Id") String moodTrackerHashedId, - @Valid @RequestBody MoodTrackerRequestDTO.SurveyAnswerList request, - @Parameter(hidden = true) @AuthMoodTracker MoodTracker moodTracker + @Valid @RequestBody MoodTrackerRequestDTO.SurveyAnswerList request ) { - moodTrackerCommandService.submitSurveyAnswers(moodTracker, request); + moodTrackerCommandService.submitSurveyAnswers(hashIdUtil.decode(moodTrackerHashedId), request); return ApiResponse.of(SuccessStatus.MOOD_TRACKER_ANSWER_SUBMIT, null); } - @GetMapping("/{mood-tracker-hashed-Id}") + @GetMapping("/{mood-tracker-hashed-Id}/bases") @Operation( - summary = "분위기 트래커 설문 팀분위기 베이스 정보 조회 API", - description = "# [v1.0 (2025-08-19)](https://www.notion.so/2545da7802c580dd9742d971d3a4bc08?source=copy_link) 분위기 트래커(moodTrackerId)에 대한 베이스 정보를 조회합니다." + summary = "분위기 트래커 설문 팀분위기 베이스 정보 조회 API (비인증)", + description = "# [v1.1 (2025-08-19)](https://www.notion.so/2545da7802c580dd9742d971d3a4bc08?source=copy_link) 분위기 트래커(moodTrackerId)에 대한 베이스 정보를 조회합니다." ) @Parameters({ @Parameter(name = "mood-tracker-hashed-Id", description = "분위기 트래커 ID (Hashed, Path Variable)", required = true) }) public ApiResponse getMoodTrackerBaseResult( - @PathVariable(name = "mood-tracker-hashed-Id") String moodTrackerHashedId, - @Parameter(hidden = true) @AuthUser User user, - @Parameter(hidden = true) @AuthMoodTracker MoodTracker moodTracker + @PathVariable(name = "mood-tracker-hashed-Id") String moodTrackerHashedId ) { - MoodTrackerResponseDTO.BaseResult result = moodTrackerQueryService.getBaseResult(user, moodTracker); + MoodTrackerResponseDTO.BaseResult result = moodTrackerQueryService.getBaseResult(hashIdUtil.decode(moodTrackerHashedId)); return ApiResponse.onSuccess(result); @@ -177,19 +176,17 @@ public ApiResponse getMoodTrackerBaseResult( @GetMapping("/{mood-tracker-hashed-Id}/questions") @Operation( - summary = "분위기 트래커 설문 문항 조회 API", - description = "# [v1.2 (2025-08-05)](https://www.notion.so/2295da7802c580dbb88aee8687b69e32) 분위기 트래커(moodTrackerId)에 해당하는 설문 문항들을 조회합니다." + summary = "분위기 트래커 설문 문항 조회 API (비인증)", + description = "# [v1.3 (2025-08-19)](https://www.notion.so/2295da7802c580dbb88aee8687b69e32) 분위기 트래커(moodTrackerId)에 해당하는 설문 문항들을 조회합니다." ) @Parameters({ @Parameter(name = "mood-tracker-hashed-Id", description = "분위기 트래커 ID (Hashed, Path Variable)", required = true) }) public ApiResponse getMoodTrackerQuestionResult( - @PathVariable(name = "mood-tracker-hashed-Id") String moodTrackerHashedId, - @Parameter(hidden = true) @AuthUser User user, - @Parameter(hidden = true) @AuthMoodTracker MoodTracker moodTracker + @PathVariable(name = "mood-tracker-hashed-Id") String moodTrackerHashedId ) { - MoodTrackerResponseDTO.QuestionResult result = moodTrackerQueryService.getQuestionResult(user, moodTracker); + MoodTrackerResponseDTO.QuestionResult result = moodTrackerQueryService.getQuestionResult(hashIdUtil.decode(moodTrackerHashedId)); return ApiResponse.onSuccess(result); diff --git a/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerCommandService.java b/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerCommandService.java index 660f5dfa..3920ffd8 100644 --- a/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerCommandService.java +++ b/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerCommandService.java @@ -26,7 +26,7 @@ void sendSurveyLink( MoodTracker moodTracker ); void submitSurveyAnswers( - MoodTracker moodTracker, + Long moodTrackerId, MoodTrackerRequestDTO.SurveyAnswerList request ); MoodTrackerResponseDTO.ReportDownLoadLinkResponse getDownloadLink( diff --git a/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerCommandServiceImpl.java b/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerCommandServiceImpl.java index 0f245e22..255c4fdd 100644 --- a/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerCommandServiceImpl.java +++ b/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerCommandServiceImpl.java @@ -180,11 +180,14 @@ public void sendSurveyLink( @Override @Transactional public void submitSurveyAnswers( - MoodTracker moodTracker, + Long moodTrackerId, MoodTrackerRequestDTO.SurveyAnswerList request ) { + MoodTracker foundMoodTracker = moodTrackerRepository.findById(moodTrackerId) + .orElseThrow(() -> new MoodTrackerHandler(ErrorStatus.MOOD_TRACKER_NOT_FOUND)); + // 마감일 이후이면 답변 불가능 - if(moodTracker.getDueDate().isBefore(LocalDateTime.now())){ + if(foundMoodTracker.getDueDate().isBefore(LocalDateTime.now())){ throw new MoodTrackerHandler(ErrorStatus.MOOD_TRACKER_FINISHED); } @@ -193,7 +196,7 @@ public void submitSurveyAnswers( List checkboxChoiceAnswers = new ArrayList<>(); // 전체 질문을 미리 조회 및 맵에 캐싱 - List foundQuestions = surveyQuestionRepository.findAllByMoodTrackerId(moodTracker.getId()); + List foundQuestions = surveyQuestionRepository.findAllByMoodTrackerId(foundMoodTracker.getId()); Map questionMap = foundQuestions.stream() .collect(Collectors.toMap(SurveyQuestion::getId, q -> q)); @@ -259,7 +262,7 @@ public void submitSurveyAnswers( subjectiveAnswerRepository.saveAll(subjectiveAnswers); // 답변자 수 증가 - moodTrackerRepository.addRespondentsNum(moodTracker.getId()); + moodTrackerRepository.addRespondentsNum(foundMoodTracker.getId()); } @Override diff --git a/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerQueryService.java b/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerQueryService.java index ec232ffb..16494202 100644 --- a/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerQueryService.java +++ b/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerQueryService.java @@ -8,9 +8,9 @@ public interface MoodTrackerQueryService { MoodTrackerResponseDTO.PreviewList getPreviewList(User user, Workspace workspace); - MoodTrackerResponseDTO.BaseResult getBaseResult(User user, MoodTracker moodTracker); + MoodTrackerResponseDTO.BaseResult getBaseResult(Long moodTrackerId); - MoodTrackerResponseDTO.QuestionResult getQuestionResult(User user, MoodTracker moodTracker); + MoodTrackerResponseDTO.QuestionResult getQuestionResult(Long moodTrackerId); MoodTrackerResponseDTO.ReportResult getReportResult(User user, MoodTracker moodTracker); diff --git a/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerQueryServiceImpl.java b/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerQueryServiceImpl.java index 4ac6b189..dfb3b1a0 100644 --- a/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerQueryServiceImpl.java +++ b/src/main/java/com/haru/api/domain/moodTracker/service/MoodTrackerQueryServiceImpl.java @@ -66,38 +66,22 @@ public MoodTrackerResponseDTO.PreviewList getPreviewList(User user, Workspace wo @Override @Transactional(readOnly = true) - @TrackLastOpened - public MoodTrackerResponseDTO.BaseResult getBaseResult(User user, MoodTracker moodTracker) { - - // 워크스페이스 권한 조회 - UserWorkspace foundUserWorkspace = userWorkspaceRepository.findByWorkspaceIdAndUserId( - moodTracker.getWorkspace().getId(), user.getId() - ).orElseThrow(() -> new UserWorkspaceHandler(ErrorStatus.USER_WORKSPACE_NOT_FOUND)); - - // 권한 검증 - boolean hasAccess = - // 워크스페이스 생성자 - foundUserWorkspace.getAuth().equals(Auth.ADMIN) - // 해당 MoodTracker 생성자 - || moodTracker.getCreator().getId().equals(user.getId()) - // 공개된 설문 - || moodTracker.getVisibility().equals(MoodTrackerVisibility.PUBLIC); - - if (!hasAccess) { - throw new MoodTrackerHandler(ErrorStatus.MOOD_TRACKER_ACCESS_DENIED); - } + public MoodTrackerResponseDTO.BaseResult getBaseResult(Long moodTrackerId) { + MoodTracker foundMoodTracker = moodTrackerRepository.findById(moodTrackerId) + .orElseThrow(() -> new MoodTrackerHandler(ErrorStatus.MOOD_TRACKER_NOT_FOUND)); - return MoodTrackerConverter.toBaseResultDTO(moodTracker, hashIdUtil); + return MoodTrackerConverter.toBaseResultDTO(foundMoodTracker, hashIdUtil); } @Override @Transactional(readOnly = true) - @TrackLastOpened - public MoodTrackerResponseDTO.QuestionResult getQuestionResult(User user, MoodTracker moodTracker) { + public MoodTrackerResponseDTO.QuestionResult getQuestionResult(Long moodTrackerId) { + MoodTracker foundMoodTracker = moodTrackerRepository.findById(moodTrackerId) + .orElseThrow(() -> new MoodTrackerHandler(ErrorStatus.MOOD_TRACKER_NOT_FOUND)); - List questionList = surveyQuestionRepository.findAllByMoodTrackerId(moodTracker.getId()); + List questionList = surveyQuestionRepository.findAllByMoodTrackerId(foundMoodTracker.getId()); - return MoodTrackerConverter.toQuestionResultDTO(moodTracker, questionList, hashIdUtil); + return MoodTrackerConverter.toQuestionResultDTO(foundMoodTracker, questionList, hashIdUtil); } @Override diff --git a/src/main/java/com/haru/api/domain/user/security/jwt/JwtAuthenticationFilter.java b/src/main/java/com/haru/api/domain/user/security/jwt/JwtAuthenticationFilter.java index 9efa6f29..719858d2 100644 --- a/src/main/java/com/haru/api/domain/user/security/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/haru/api/domain/user/security/jwt/JwtAuthenticationFilter.java @@ -43,8 +43,9 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { "/api/v1/sns/oauth/callback", "/api/v1/users/signup/same", "/favicon.ico", - "/api/v1//mood-trackers/*/questions", - "/api/v1//mood-trackers/*/responses" + "/api/v1/mood-trackers/*/questions", + "/api/v1/mood-trackers/*/answer", + "/api/v1/mood-trackers/*/bases" }; private final JwtUtils jwtUtils; private final RedisTemplate redisTemplate; diff --git a/src/main/java/com/haru/api/domain/user/security/jwt/SecurityUtil.java b/src/main/java/com/haru/api/domain/user/security/jwt/SecurityUtil.java index 8277033d..9968bc5f 100644 --- a/src/main/java/com/haru/api/domain/user/security/jwt/SecurityUtil.java +++ b/src/main/java/com/haru/api/domain/user/security/jwt/SecurityUtil.java @@ -14,8 +14,9 @@ private SecurityUtil() { } public static Long getCurrentUserId() { final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null || authentication.getName() == null) { - throw new RuntimeException("Security Context 에 인증 정보가 없습니다."); + if (authentication == null || !authentication.isAuthenticated() + || authentication.getPrincipal().equals("anonymousUser")) { + return null; // 또는 Optional.empty() } return Long.parseLong(authentication.getName());