Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import kgu.developers.domain.graduationUser.application.query.GraduationUserQueryService;
import kgu.developers.domain.graduationUser.domain.GraduationType;
import kgu.developers.domain.graduationUser.domain.GraduationUser;
import kgu.developers.domain.schedule.application.query.ScheduleQueryService;
import kgu.developers.domain.schedule.domain.Schedule;
import kgu.developers.domain.schedule.domain.SubmissionType;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

Expand All @@ -13,6 +16,7 @@
public class GraduationUserFacade {
private final GraduationUserQueryService graduationUserQueryService;
private final GraduationUserCommandService graduationUserCommandService;
private final ScheduleQueryService scheduleQueryService;

public void updateGraduationType(GraduationType type) {
GraduationUser graduationUser = graduationUserQueryService.me();
Expand All @@ -26,6 +30,8 @@ public void updateGraduationUserEmail(String email) {

public MyGraduationUserResponse getMyGraduationUser() {
GraduationUser graduationUser = graduationUserQueryService.me();
return MyGraduationUserResponse.from(graduationUser);
SubmissionType submissionType = MyGraduationUserResponse.requiredSubmissionType(graduationUser);
Schedule schedule = (submissionType == null) ? null : scheduleQueryService.getBySubmissionType(submissionType);
return MyGraduationUserResponse.from(graduationUser, schedule);
Comment on lines 31 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find and examine ScheduleQueryService
fd -type f -name "*.java" | xargs rg -l "ScheduleQueryService" | head -20

Repository: kgu-developers/aics-server

Length of output: 1407


🏁 Script executed:

#!/bin/bash
# Look for ScheduleQueryService class definition
rg -n "class ScheduleQueryService" -A 20

Repository: kgu-developers/aics-server

Length of output: 5508


🏁 Script executed:

#!/bin/bash
# Search for getBySubmissionType method definition
rg -n "getBySubmissionType" -B 2 -A 5

Repository: kgu-developers/aics-server

Length of output: 9292


🏁 Script executed:

#!/bin/bash
# Find MyGraduationUserResponse class and from() method
rg -n "class MyGraduationUserResponse" -A 30

Repository: kgu-developers/aics-server

Length of output: 52


🏁 Script executed:

#!/bin/bash
# Search for MyGraduationUserResponse.from() method
rg -n "from\(" -B 2 -A 10 | grep -A 10 "MyGraduationUserResponse"

Repository: kgu-developers/aics-server

Length of output: 4763


🏁 Script executed:

#!/bin/bash
# Find ScheduleNotFoundException to understand exception type
rg -n "ScheduleNotFoundException" -B 2 -A 5

Repository: kgu-developers/aics-server

Length of output: 14587


스케줄 미존재 시 예외 처리 필요

getBySubmissionType()은 스케줄이 없을 때 ScheduleNotFoundException을 던지도록 구현되어 있습니다. 현재 코드에서는 submissionType == null인 경우만 방어하고 있어서, submissionType이 non-null이지만 해당 스케줄이 존재하지 않으면 예외가 처리되지 않아 500 에러로 응답하게 됩니다. 이는 MyGraduationUserResponse.from()의 null 스케줄 fallback 로직이 동작할 수 없음을 의미합니다.

Optional을 활용하거나 예외를 캐치하여 schedule을 null 처리하는 방식으로 개선해주세요:

// 방법 1: Optional 활용
Schedule schedule = (submissionType == null) ? null : scheduleQueryService.findBySubmissionType(submissionType).orElse(null);

// 방법 2: 예외 캐치
Schedule schedule = null;
if (submissionType != null) {
    try {
        schedule = scheduleQueryService.getBySubmissionType(submissionType);
    } catch (ScheduleNotFoundException e) {
        // schedule은 null로 유지
    }
}
🤖 Prompt for AI Agents
In
`@aics-api/src/main/java/kgu/developers/api/graduationUser/application/GraduationUserFacade.java`
around lines 31 - 35, getMyGraduationUser currently only guards against
submissionType == null but calls
scheduleQueryService.getBySubmissionType(submissionType) which throws
ScheduleNotFoundException when no schedule exists; update getMyGraduationUser to
either use
scheduleQueryService.findBySubmissionType(submissionType).orElse(null) or wrap
the getBySubmissionType call in a try/catch for ScheduleNotFoundException and
set schedule to null so MyGraduationUserResponse.from(graduationUser, schedule)
receives a null schedule instead of letting the exception propagate.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,73 @@
import io.swagger.v3.oas.annotations.media.Schema;
import kgu.developers.domain.graduationUser.domain.GraduationType;
import kgu.developers.domain.graduationUser.domain.GraduationUser;
import kgu.developers.domain.schedule.domain.Schedule;
import kgu.developers.domain.schedule.domain.SubmissionType;
import lombok.Builder;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

@Builder
public record MyGraduationUserResponse(
@Schema(description = "현재 상태", example = "GRADUATION_TYPE_NOT_SUBMITTED")
GraduationUserStatus status
@Schema(description = "제목", example = "최종 보고서를 제출하지 않았어요.")
String title,

@Schema(description = "내용", example = "최종 보고서 마감 기한은 2025년 10월 30일이에요.")
String description
) {
public static MyGraduationUserResponse from(GraduationUser graduationUser) {
private static final DateTimeFormatter KOREAN_DATE = DateTimeFormatter.ofPattern("yyyy년 M월 d일");


public static MyGraduationUserResponse from(GraduationUser graduationUser, Schedule schedule) {
GraduationUserStatus status = determineStatus(graduationUser);

String title = switch (status) {
case GRADUATION_TYPE_NOT_SUBMITTED -> "졸업 유형을 아직 선택하지 않았어요.";
case PROFESSOR_NOT_ASSIGNED -> "지도교수가 아직 배정되지 않았어요.";
case MID_THESIS_NOT_SUBMITTED -> "중간 보고서를 제출하지 않았어요.";
case FINAL_THESIS_NOT_SUBMITTED -> "최종 보고서를 제출하지 않았어요.";
case CERTIFICATE_NOT_SUBMITTED -> "자격증을 제출하지 않았어요.";
case GRADUATION_REQUIREMENTS_MET -> "졸업 요건을 충족했어요.";
};

String description = switch (status) {
case MID_THESIS_NOT_SUBMITTED -> deadlineMessage("중간 보고서", schedule);
case FINAL_THESIS_NOT_SUBMITTED -> deadlineMessage("최종 보고서", schedule);
case CERTIFICATE_NOT_SUBMITTED -> deadlineMessage("자격증", schedule);

case GRADUATION_TYPE_NOT_SUBMITTED ->
"졸업 유형(보고서/자격증)을 먼저 선택해주세요.";
case PROFESSOR_NOT_ASSIGNED ->
"지도교수 배정을 완료해야 다음 절차를 진행할 수 있어요.";
case GRADUATION_REQUIREMENTS_MET ->
"현재 기준으로 필요한 졸업 요건이 모두 완료되었어요.";
};

return MyGraduationUserResponse.builder()
.status(determineStatus(graduationUser))
.build();
.title(title)
.description(description)
.build();
}

/**
* 서비스에서 schedule 조회할 때 쓰라고 status -> SubmissionType 매핑도 제공
*/
public static SubmissionType requiredSubmissionType(GraduationUser graduationUser) {
GraduationUserStatus status = determineStatus(graduationUser);

return switch (status) {
case MID_THESIS_NOT_SUBMITTED -> SubmissionType.MIDTHESIS;
case FINAL_THESIS_NOT_SUBMITTED -> SubmissionType.FINALTHESIS;
case CERTIFICATE_NOT_SUBMITTED -> SubmissionType.CERTIFICATE;
default -> null; // schedule 필요 없는 상태들
};
}

private static String deadlineMessage(String target, Schedule schedule) {
LocalDateTime endDate = (schedule == null) ? null : schedule.getEndDate();
String formatted = (endDate == null) ? "미정" : endDate.format(KOREAN_DATE);
return target + " 마감 기한은 " + formatted + "이에요.";
}

private static GraduationUserStatus determineStatus(GraduationUser graduationUser) {
Expand All @@ -32,8 +88,7 @@ private static GraduationUserStatus determineStatus(GraduationUser graduationUse
if (graduationUser.getFinalThesisId() == null) {
return GraduationUserStatus.FINAL_THESIS_NOT_SUBMITTED;
}
}
else if (graduationUser.getGraduationType() == GraduationType.CERTIFICATE) {
} else if (graduationUser.getGraduationType() == GraduationType.CERTIFICATE) {
if (graduationUser.getCertificateId() == null) {
return GraduationUserStatus.CERTIFICATE_NOT_SUBMITTED;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,18 @@ public void init() {
LocalDateTime.of(3000, 1, 1,0,0)
));

ScheduleQueryService scheduleQueryService = new ScheduleQueryService(fakeScheduleRepository);
GraduationUserCommandService graduationUserCommandService = new GraduationUserCommandService(
fakeGraduationUserRepository,
new ScheduleQueryService(fakeScheduleRepository)
scheduleQueryService
);

BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
graduationuserFacade = new GraduationUserFacade(graduationUserQueryService,graduationUserCommandService);
graduationuserFacade = new GraduationUserFacade(
graduationUserQueryService,
graduationUserCommandService,
scheduleQueryService
);

User user = fakeUserRepository.save(User.builder()
.id("202411345")
Expand Down Expand Up @@ -125,6 +130,6 @@ public void getMyGraduationUser_Success() {
MyGraduationUserResponse response = graduationuserFacade.getMyGraduationUser();

//then
assertEquals(response.status().name(),"GRADUATION_TYPE_NOT_SUBMITTED");
assertEquals("졸업 유형을 아직 선택하지 않았어요.", response.title());
}
}