Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 @@ -294,7 +294,11 @@ public SubmissionResponse reopenSubmission(Long submissionId, String professorId
}

public MilestonePresentationsResponse getMilestonePresentations(Long milestoneId, String userId) {
validatePresentationMilestone(milestoneId);
Milestone milestone = validatePresentationMilestone(milestoneId);
if (!isActiveStudent(milestone.getSectionId(), userId)
&& !sectionQueryService.isActiveSectionOwnedByProfessor(milestone.getSectionId(), userId)) {
throw new AccessDeniedException("해당 분반의 활성 학생 또는 담당 교수만 발표자료를 조회할 수 있습니다.");
}
List<Submission> submissions = submissionQueryService.getSubmissionsOrderedForPresentation(milestoneId);
List<Long> teamIds = submissions.stream().map(Submission::getTeamId).distinct().toList();

Expand Down Expand Up @@ -491,11 +495,12 @@ private boolean isActiveStudent(Long sectionId, String userId) {
.orElse(false);
}

private void validatePresentationMilestone(Long milestoneId) {
private Milestone validatePresentationMilestone(Long milestoneId) {
Milestone milestone = milestoneRepository.findById(milestoneId)
.orElseThrow(() -> new MilestoneNotFoundException(milestoneId));
if (milestone.getType() != MilestoneType.PRESENTATION) {
throw new SubmissionMilestoneTypeMismatchException();
}
return milestone;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,13 @@ ResponseEntity<SubmissionResponse> reopenSubmission(
@Operation(
summary = "발표순서 정렬 팀별 공개자료 목록 API",
description = """
Description : 발표순서로 정렬된 팀별 공개자료 목록을 조회한다. 이전/다음 네비게이션은 이 배열로 프론트에서 처리.
Description : 해당 분반의 활성 학생 또는 담당 교수만 발표순서로 정렬된 팀별 공개자료 목록을 조회할 수 있다.
이전/다음 네비게이션은 이 배열로 프론트에서 처리한다.
Assignee : 담당자명
"""
)
@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = MilestonePresentationsResponse.class)))
@ApiResponse(responseCode = "403", description = "해당 분반의 활성 학생 또는 담당 교수가 아님")
ResponseEntity<MilestonePresentationsResponse> getMilestonePresentations(@PathVariable Long milestoneId, Authentication authentication);

@Operation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class SubmissionFacadeTest {

private MilestoneRepository milestoneRepository;
private SectionQueryService sectionQueryService;
private FakeEnrollmentRepository enrollmentRepository;
private FakeTeamMemberRepository teamMemberRepository;
private FakeSubmissionRepository submissionRepository;
private FakeTeamRepository teamRepository;
Expand Down Expand Up @@ -105,7 +106,7 @@ void setUp() {
new FakeSubmissionMemberConfirmationRepository();
fileObjectRepository = new FakeFileObjectRepository();
fileStorage = new FakeFileStorage();
FakeEnrollmentRepository enrollmentRepository = new FakeEnrollmentRepository();
enrollmentRepository = new FakeEnrollmentRepository();
enrollmentRepository.save(Enrollment.create(SECTION_ID, LEADER, Role.STUDENT, Status.ACTIVE));
enrollmentRepository.save(Enrollment.create(SECTION_ID, MEMBER, Role.STUDENT, Status.ACTIVE));
userRepository = new FakeUserRepository();
Expand Down Expand Up @@ -412,6 +413,56 @@ void assignPresentationOrder_ThenListedInOrder() {
assertThat(response.contents().get(1).teamName()).isEqualTo("우리팀");
}

@Test
@DisplayName("해당 분반의 활성 학생은 발표자료를 조회할 수 있다")
void getMilestonePresentations_AllowsActiveStudent() {
given(milestoneRepository.findById(MILESTONE_ID)).willReturn(Optional.of(presentationMilestone()));

assertThat(submissionFacade.getMilestonePresentations(MILESTONE_ID, MEMBER).contents()).isEmpty();
}

@Test
@DisplayName("해당 분반의 담당 교수는 발표자료를 조회할 수 있다")
void getMilestonePresentations_AllowsSectionProfessor() {
given(milestoneRepository.findById(MILESTONE_ID)).willReturn(Optional.of(presentationMilestone()));
given(sectionQueryService.isActiveSectionOwnedByProfessor(SECTION_ID, PROFESSOR)).willReturn(true);

assertThat(submissionFacade.getMilestonePresentations(MILESTONE_ID, PROFESSOR).contents()).isEmpty();
}

@Test
@DisplayName("다른 분반의 활성 학생은 발표자료를 조회할 수 없다")
void getMilestonePresentations_RejectsOtherSectionStudent() {
given(milestoneRepository.findById(MILESTONE_ID)).willReturn(Optional.of(presentationMilestone()));
enrollmentRepository.save(Enrollment.create(SECTION_ID + 1, NON_MEMBER, Role.STUDENT, Status.ACTIVE));

assertThatThrownBy(() -> submissionFacade.getMilestonePresentations(MILESTONE_ID, NON_MEMBER))
.isInstanceOf(AccessDeniedException.class);
}

@Test
@DisplayName("다른 분반의 담당 교수는 발표자료를 조회할 수 없다")
void getMilestonePresentations_RejectsOtherSectionProfessor() {
given(milestoneRepository.findById(MILESTONE_ID)).willReturn(Optional.of(presentationMilestone()));
given(sectionQueryService.isActiveSectionOwnedByProfessor(SECTION_ID + 1, PROFESSOR)).willReturn(true);

assertThatThrownBy(() -> submissionFacade.getMilestonePresentations(MILESTONE_ID, PROFESSOR))
.isInstanceOf(AccessDeniedException.class);
}

@Test
@DisplayName("비활성 학생과 조교는 발표자료를 조회할 수 없다")
void getMilestonePresentations_RejectsInactiveStudentAndAssistant() {
given(milestoneRepository.findById(MILESTONE_ID)).willReturn(Optional.of(presentationMilestone()));
enrollmentRepository.save(Enrollment.create(SECTION_ID, "withdrawn", Role.STUDENT, Status.WITHDRAWN));
enrollmentRepository.save(Enrollment.create(SECTION_ID, "assistant", Role.ASSISTANT, Status.ACTIVE));

assertThatThrownBy(() -> submissionFacade.getMilestonePresentations(MILESTONE_ID, "withdrawn"))
.isInstanceOf(AccessDeniedException.class);
assertThatThrownBy(() -> submissionFacade.getMilestonePresentations(MILESTONE_ID, "assistant"))
.isInstanceOf(AccessDeniedException.class);
}

@Test
@DisplayName("발표자료 조회 시 해당 팀의 제안서 정보와 제출된 산출물(PDF, 영상 링크)이 함께 반환된다")
void getMilestonePresentations_IncludesProjectAndArtifacts() throws Exception {
Expand Down
Loading