Skip to content

Commit 123e8b0

Browse files
authored
Feature/KD-49 GraduationUser 승인 API, 나의 정보 조회 API 구현 (#293)
* feat: 졸업 대상자 일괄 승인 API 구현 * fix: 졸업 대상자 페이징 조회 시 제출 상태도 반환하도록 수정 * feat: 나의 졸업 상태 확인 API 구현 * fix: 졸업대상자의 이메일, 졸업 방식 신청 API graduationUserId 제거 * fix: 엑셀 파일 단계, 상태 추가 * fix: 엑셀 파일 단계, 상태 추가 * fix: updateThesis 서비스에서 저장이 되지 않는 오류 수정 * fix: updateThesis 서비스에서 저장이 되지 않는 오류 수정 * fix: 코드래빗 리뷰 반영 * test: GraduationUser 테스트 코드 작성 * fix: 테스트 코드의 FilePathProperties로 인한 오류 수정 * feat: 논문 파일 제출 API의 request에서 제출 타입을 제출하지 않도록 재변경 * test: 테스트 코드 작성 * refactor: Transactional 어노테이션을 Facade단에서 Service단으로 이동 * refactor: import 와일드카드 제거 * refactor: GraduationUserStatusResponse 주석 작성
1 parent 2251400 commit 123e8b0

File tree

53 files changed

+1160
-131
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1160
-131
lines changed

aics-admin/src/main/java/kgu/developers/admin/graduationUser/application/GraduationUserAdminFacade.java

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,46 @@
11
package kgu.developers.admin.graduationUser.application;
22

33
import kgu.developers.admin.graduationUser.presentation.dto.GraduationUserExcelFileDto;
4+
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserBatchApproveRequest;
45
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserBatchCreateRequest;
56
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserBatchDeleteRequest;
67
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserCreateRequest;
8+
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserBatchApproveResponse;
79
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserBatchCreateResponse;
810
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserBatchDeleteResponse;
911
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserDetailResponse;
1012
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserPersistResponse;
13+
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserStatusResponse;
1114
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserSummaryPageResponse;
15+
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserSummaryResponse;
1216
import kgu.developers.common.response.PaginatedListResponse;
17+
import kgu.developers.domain.certificate.application.command.CertificateCommandService;
18+
import kgu.developers.domain.certificate.application.query.CertificateQueryService;
1319
import kgu.developers.domain.graduationUser.application.command.GraduationUserCommandService;
1420
import kgu.developers.domain.graduationUser.application.query.GraduationUserQueryService;
1521
import kgu.developers.domain.graduationUser.domain.GraduationType;
1622
import kgu.developers.domain.graduationUser.domain.GraduationUser;
23+
import kgu.developers.domain.thesis.application.command.ThesisCommandService;
24+
import kgu.developers.domain.thesis.application.query.ThesisQueryService;
1725
import lombok.RequiredArgsConstructor;
1826
import org.springframework.data.domain.Pageable;
1927
import org.springframework.stereotype.Component;
20-
import org.springframework.transaction.annotation.Transactional;
2128

2229
import java.time.LocalDateTime;
2330
import java.time.format.DateTimeFormatter;
31+
import java.util.ArrayList;
2432
import java.util.List;
2533

2634
@Component
27-
@Transactional
2835
@RequiredArgsConstructor
2936
public class GraduationUserAdminFacade {
3037

3138
private final GraduationUserCommandService graduationUserCommandService;
3239
private final GraduationUserQueryService graduationUserQueryService;
40+
private final ThesisCommandService thesisCommandService;
41+
private final ThesisQueryService thesisQueryService;
42+
private final CertificateCommandService certificateCommandService;
43+
private final CertificateQueryService certificateQueryService;
3344

3445
public GraduationUserPersistResponse createGraduationUser(GraduationUserCreateRequest request) {
3546
Long id = graduationUserCommandService.createGraduationUser(request.studentId(), request.name(), request.advisorProfessor(), request.capstoneCompletion(), request.department(), request.graduationDate());
@@ -54,7 +65,61 @@ public GraduationUserBatchCreateResponse createGraduationUsers(GraduationUserBat
5465

5566
public GraduationUserSummaryPageResponse getGraduationUsersByNameAndGraduationType(Pageable pageable, String name, GraduationType graduationType) {
5667
PaginatedListResponse<GraduationUser> response = graduationUserQueryService.getGraduationUsersByNameAndGraduationType(pageable,name,graduationType);
57-
return GraduationUserSummaryPageResponse.of(response.contents(), response.pageable());
68+
69+
List<GraduationUserSummaryResponse> graduationUserSummaryResponses = response.contents().stream()
70+
.map(this::createSummaryResponse)
71+
.toList();
72+
73+
return GraduationUserSummaryPageResponse.of(graduationUserSummaryResponses, response.pageable());
74+
}
75+
76+
private GraduationUserSummaryResponse createSummaryResponse(GraduationUser user) {
77+
GraduationUserStatusResponse status = buildSubmissionStatus(user);
78+
return GraduationUserSummaryResponse.of(user, status);
79+
}
80+
81+
private GraduationUserStatusResponse buildSubmissionStatus(GraduationUser user) {
82+
if (user.getGraduationType() == null) {
83+
return null;
84+
}
85+
86+
return switch (user.getGraduationType()) {
87+
case CERTIFICATE -> buildCertificateStatus(user.getCertificateId());
88+
case THESIS -> buildThesisStatus(user.getMidThesisId(), user.getFinalThesisId());
89+
};
90+
}
91+
92+
private GraduationUserStatusResponse.Certificate buildCertificateStatus(Long certificateId) {
93+
boolean submitted = certificateId != null;
94+
boolean approval = false;
95+
if(submitted) {
96+
approval = certificateQueryService.isApproved(certificateId);
97+
}
98+
99+
return new GraduationUserStatusResponse.Certificate("CERTIFICATE", submitted, approval);
100+
}
101+
102+
private GraduationUserStatusResponse.Thesis buildThesisStatus(Long middleThesisId, Long finalThesisId) {
103+
104+
boolean midThesisSubmitted = middleThesisId != null;
105+
boolean midThesisapproval = false;
106+
if(midThesisSubmitted) {
107+
midThesisapproval = thesisQueryService.isApproved(middleThesisId);
108+
}
109+
110+
GraduationUserStatusResponse.Thesis.Middle midStatus =
111+
new GraduationUserStatusResponse.Thesis.Middle(midThesisSubmitted,midThesisapproval);
112+
113+
boolean finalThesisSubmitted = finalThesisId != null;
114+
boolean finalThesisapproval = false;
115+
if(finalThesisSubmitted) {
116+
finalThesisapproval = thesisQueryService.isApproved(finalThesisId);
117+
}
118+
119+
GraduationUserStatusResponse.Thesis.Final finalStatus =
120+
new GraduationUserStatusResponse.Thesis.Final(finalThesisSubmitted,finalThesisapproval);
121+
122+
return new GraduationUserStatusResponse.Thesis("THESIS", midStatus, finalStatus);
58123
}
59124

60125
public void deleteGraduationUser(Long id) {
@@ -88,4 +153,36 @@ public GraduationUserExcelFileDto getGraduateUsersExcelByGraduationType(Graduati
88153

89154
return GraduationUserExcelFileDto.from(content, filename);
90155
}
156+
157+
public GraduationUserBatchApproveResponse approveGraduationUsers(GraduationUserBatchApproveRequest request) {
158+
List<GraduationUser> users = request.ids().stream()
159+
.map(graduationUserQueryService::getById)
160+
.toList();
161+
162+
List<Long> approvedUserIds = new ArrayList<>();
163+
164+
for(GraduationUser user: users) {
165+
if(user.getGraduationType() == GraduationType.CERTIFICATE) {
166+
if(user.getCertificateId() == null) continue;
167+
boolean approved = certificateCommandService.approve(user.getCertificateId());
168+
if(approved) approvedUserIds.add(user.getId());
169+
} else if(user.getGraduationType() == GraduationType.THESIS) {
170+
boolean midThesisapproved = false;
171+
boolean finalThesisapproved = false;
172+
173+
if(user.getMidThesisId() != null) {
174+
midThesisapproved = thesisCommandService.approve(user.getMidThesisId());
175+
}
176+
177+
if(user.getFinalThesisId() != null) {
178+
finalThesisapproved = thesisCommandService.approve(user.getFinalThesisId());
179+
}
180+
181+
if(midThesisapproved || finalThesisapproved)
182+
approvedUserIds.add(user.getId());
183+
}
184+
}
185+
186+
return GraduationUserBatchApproveResponse.from(approvedUserIds);
187+
}
91188
}

aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/GraduationUserAdminController.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99
import jakarta.validation.Valid;
1010
import jakarta.validation.constraints.Positive;
1111
import jakarta.validation.constraints.PositiveOrZero;
12+
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserBatchApproveRequest;
1213
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserBatchCreateRequest;
1314
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserBatchDeleteRequest;
1415
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserCreateRequest;
16+
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserBatchApproveResponse;
1517
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserBatchCreateResponse;
1618
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserBatchDeleteResponse;
1719
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserDetailResponse;
1820
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserPersistResponse;
1921
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserSummaryPageResponse;
20-
import kgu.developers.admin.lab.presentation.response.LabPersistResponse;
2122
import kgu.developers.domain.graduationUser.domain.GraduationType;
2223
import org.springframework.core.io.Resource;
2324
import org.springframework.http.ResponseEntity;
@@ -135,4 +136,16 @@ ResponseEntity<GraduationUserBatchDeleteResponse> deleteGraduationUsers(
135136
required = true
136137
) @Valid @RequestBody GraduationUserBatchDeleteRequest request
137138
);
139+
140+
@Operation(summary = "졸업 대상자 일괄 승인 API", description = """
141+
- Description : 이 API는 선택한 여러 졸업 대상자의 제출을 일괄 승인합니다.
142+
- Assignee : 장영후
143+
""")
144+
@ApiResponse(responseCode = "200")
145+
ResponseEntity<GraduationUserBatchApproveResponse> approveGraduationUsers(
146+
@Parameter(
147+
description = "승인할 졸업 대상자 ID 목록",
148+
required = true
149+
) @Valid @RequestBody GraduationUserBatchApproveRequest request
150+
);
138151
}

aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/GraduationUserAdminControllerImpl.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
import jakarta.validation.constraints.PositiveOrZero;
66
import kgu.developers.admin.graduationUser.application.GraduationUserAdminFacade;
77
import kgu.developers.admin.graduationUser.presentation.dto.GraduationUserExcelFileDto;
8+
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserBatchApproveRequest;
89
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserBatchCreateRequest;
910
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserBatchDeleteRequest;
1011
import kgu.developers.admin.graduationUser.presentation.request.GraduationUserCreateRequest;
12+
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserBatchApproveResponse;
1113
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserBatchCreateResponse;
1214
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserBatchDeleteResponse;
1315
import kgu.developers.admin.graduationUser.presentation.response.GraduationUserDetailResponse;
@@ -24,6 +26,7 @@
2426
import org.springframework.security.access.prepost.PreAuthorize;
2527
import org.springframework.web.bind.annotation.DeleteMapping;
2628
import org.springframework.web.bind.annotation.GetMapping;
29+
import org.springframework.web.bind.annotation.PatchMapping;
2730
import org.springframework.web.bind.annotation.PathVariable;
2831
import org.springframework.web.bind.annotation.PostMapping;
2932
import org.springframework.web.bind.annotation.RequestBody;
@@ -107,9 +110,18 @@ public ResponseEntity<Void> deleteGraduationUser(
107110
@Override
108111
@DeleteMapping("/batch")
109112
public ResponseEntity<GraduationUserBatchDeleteResponse> deleteGraduationUsers(
110-
GraduationUserBatchDeleteRequest request
113+
@Valid @RequestBody GraduationUserBatchDeleteRequest request
111114
) {
112115
GraduationUserBatchDeleteResponse response = graduationUserAdminFacade.deleteGraduationUsers(request);
113116
return ResponseEntity.ok(response);
114117
}
118+
119+
@Override
120+
@PatchMapping("/batch/approve")
121+
public ResponseEntity<GraduationUserBatchApproveResponse> approveGraduationUsers(
122+
@Valid @RequestBody GraduationUserBatchApproveRequest request
123+
) {
124+
GraduationUserBatchApproveResponse response = graduationUserAdminFacade.approveGraduationUsers(request);
125+
return ResponseEntity.ok(response);
126+
}
115127
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package kgu.developers.admin.graduationUser.presentation.request;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import jakarta.validation.constraints.NotEmpty;
5+
import jakarta.validation.constraints.Positive;
6+
import lombok.Builder;
7+
8+
import java.util.List;
9+
10+
@Builder
11+
public record GraduationUserBatchApproveRequest(
12+
@Schema(description = "승인할 졸업 대상자 ID 목록", example = "[1, 2, 3]")
13+
@NotEmpty(message = "승인할 대상자를 최소 1명 이상 선택해야 합니다.")
14+
List<@Positive(message = "ID는 양수여야 합니다.") Long> ids
15+
) {
16+
}

aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/request/GraduationUserBatchDeleteRequest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package kgu.developers.admin.graduationUser.presentation.request;
22

3-
43
import io.swagger.v3.oas.annotations.media.Schema;
54
import jakarta.validation.constraints.NotEmpty;
65
import jakarta.validation.constraints.Positive;
@@ -14,5 +13,4 @@ public record GraduationUserBatchDeleteRequest(
1413
@NotEmpty(message = "삭제할 대상자를 최소 1명 이상 선택해야 합니다.")
1514
List<@Positive(message = "ID는 양수여야 합니다.") Long> ids
1615
) {
17-
1816
}

aics-admin/src/main/java/kgu/developers/admin/graduationUser/presentation/request/GraduationUserCreateRequest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ public record GraduationUserCreateRequest(
2323
String name,
2424

2525
@Schema(description = "담당교수 이름", example = "김교수", requiredMode = Schema.RequiredMode.REQUIRED)
26-
@NotBlank
2726
@Size(max = 10)
2827
String advisorProfessor,
2928

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package kgu.developers.admin.graduationUser.presentation.response;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.Builder;
5+
6+
import java.util.List;
7+
8+
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
9+
10+
@Builder
11+
public record GraduationUserBatchApproveResponse(
12+
@Schema(description = "승인에 성공한 졸업 대상자 ID 목록", example = "[1, 2, 3, 4, 5]", requiredMode = REQUIRED)
13+
List<Long> approvedIds
14+
) {
15+
public static GraduationUserBatchApproveResponse from(List<Long> approvedUserIds) {
16+
return GraduationUserBatchApproveResponse.builder()
17+
.approvedIds(approvedUserIds)
18+
.build();
19+
}
20+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package kgu.developers.admin.graduationUser.presentation.response;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
5+
/**
6+
* 졸업 대상자 상태 응답 인터페이스
7+
* 다른 클래스에서 대상자 상태 응답을 추가로 구현하는 것을 방지하고자 sealed 키워드를 사용하였습니다.
8+
* 만약 졸업 방식이 추가된다면 해당 클래스에서 추가로 구현하여 작성해주세요.
9+
*/
10+
public sealed interface GraduationUserStatusResponse
11+
permits GraduationUserStatusResponse.Certificate,
12+
GraduationUserStatusResponse.Thesis {
13+
14+
@Schema(description = "자격증 제출 상태")
15+
record Certificate(
16+
@Schema(description = "졸업 타입", example = "CERTIFICATE")
17+
String type,
18+
19+
@Schema(description = "파일 제출 여부", example = "true")
20+
boolean submitted,
21+
22+
@Schema(description = "승인 여부", example = "false")
23+
boolean approval
24+
) implements GraduationUserStatusResponse {
25+
}
26+
27+
@Schema(description = "논문 제출 상태")
28+
record Thesis(
29+
@Schema(description = "졸업 타입", example = "THESIS")
30+
String type,
31+
32+
@Schema(description = "중간 논문 상태")
33+
Middle midThesis,
34+
35+
@Schema(description = "최종 논문 상태")
36+
Final finalThesis
37+
) implements GraduationUserStatusResponse {
38+
39+
@Schema(description = "중간 논문 제출 상태")
40+
public record Middle(
41+
@Schema(description = "파일 제출 여부", example = "true")
42+
boolean submitted,
43+
44+
@Schema(description = "승인 여부", example = "true")
45+
boolean approval
46+
) {}
47+
48+
@Schema(description = "최종 논문 제출 상태")
49+
public record Final(
50+
@Schema(description = "파일 제출 여부", example = "false")
51+
boolean submitted,
52+
53+
@Schema(description = "승인 여부", example = "false")
54+
boolean approval
55+
) {}
56+
}
57+
}

0 commit comments

Comments
 (0)