Skip to content

Commit 2f9db8c

Browse files
authored
Merge pull request #173 from pirogramming/main
[fix]: 수강생 디테일 페이지 -> 과제확인 페이지 api 넘김 로직 수정
2 parents d2f99c4 + 4db9b4e commit 2f9db8c

File tree

4 files changed

+226
-91
lines changed

4 files changed

+226
-91
lines changed

backend/pirocheck/src/main/java/backend/pirocheck/Attendance/controller/AdminAttendanceController.java

Lines changed: 112 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -23,135 +23,180 @@
2323

2424
@RestController
2525
@RequiredArgsConstructor
26-
@RequestMapping("/api/admin/attendance")
26+
@RequestMapping("/api")
2727
@Tag(name = "관리자 출석관리", description = "관리자용 출석 관리 API")
2828
public class AdminAttendanceController {
2929

3030
private final AttendanceService attendanceService;
3131

3232
// 출석체크 시작
3333
@Operation(summary = "출석 체크 시작", description = "새로운 출석 코드를 생성하고 출석 체크를 시작합니다.")
34-
@ApiResponses({
35-
@io.swagger.v3.oas.annotations.responses.ApiResponse(
36-
responseCode = "200",
37-
description = "출석 코드 생성 성공",
38-
content = @Content(schema = @Schema(implementation = AttendanceCodeResponse.class))
39-
),
34+
@ApiResponses(value = {
35+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "출석 코드 생성 성공"),
4036
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청")
4137
})
42-
@PostMapping("/start")
43-
public ApiResponse<AttendanceCodeResponse> startAttendance() {
38+
@PostMapping("/admin/attendance/start")
39+
public AttendanceCodeResponse startAttendance() {
4440
try {
4541
AttendanceCode code = attendanceService.generateCodeAndCreateAttendances();
46-
return ApiResponse.success(AttendanceCodeResponse.from(code));
42+
return AttendanceCodeResponse.from(code);
4743
} catch (IllegalStateException e) {
4844
// 하루 최대 출석 체크 횟수를 초과한 경우
49-
return ApiResponse.error(e.getMessage());
45+
throw new IllegalStateException(e.getMessage());
5046
} catch (Exception e) {
51-
return ApiResponse.error("출석 코드 생성 중 오류가 발생했습니다: " + e.getMessage());
47+
throw new RuntimeException("출석 코드 생성 중 오류가 발생했습니다: " + e.getMessage());
5248
}
5349
}
5450

5551
// 현재 활성화된 출석코드 조회
5652
@Operation(summary = "현재 활성화된 출석 코드 조회", description = "현재 활성화된 출석 코드 정보를 조회합니다.")
57-
@ApiResponses({
58-
@io.swagger.v3.oas.annotations.responses.ApiResponse(
59-
responseCode = "200",
60-
description = "조회 성공",
61-
content = @Content(schema = @Schema(implementation = AttendanceCodeResponse.class))
62-
),
53+
@ApiResponses(value = {
54+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"),
6355
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "활성화된 출석 코드 없음")
6456
})
65-
@GetMapping("/active-code")
66-
public ApiResponse<AttendanceCodeResponse> getActiveCode() {
57+
@GetMapping("/admin/attendance/active-code")
58+
public AttendanceCodeResponse getActiveCode() {
6759
Optional<AttendanceCode> codeOpt = attendanceService.getActiveAttendanceCode();
6860

6961
if (codeOpt.isEmpty()) {
70-
return ApiResponse.error("현재 활성화된 출석코드가 없습니다");
62+
throw new RuntimeException("현재 활성화된 출석코드가 없습니다");
7163
}
7264

73-
return ApiResponse.success(AttendanceCodeResponse.from(codeOpt.get()));
65+
return AttendanceCodeResponse.from(codeOpt.get());
7466
}
7567

7668
// 출석체크 종료 (코드 직접 전달)
7769
@Operation(summary = "특정 출석 코드 만료", description = "특정 출석 코드를 만료 처리합니다.")
78-
@ApiResponses({
70+
@ApiResponses(value = {
7971
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "만료 처리 성공"),
8072
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청"),
8173
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "출석 코드를 찾을 수 없음")
8274
})
83-
@PutMapping("/expire")
84-
public ApiResponse<Void> expireAttendance(
85-
@Parameter(description = "만료할 출석 코드", required = true)
75+
@PutMapping("/admin/attendance/expire")
76+
public String expireAttendance(
77+
@Parameter(description = "만료할 출석 코드", example = "1234")
8678
@RequestParam String code) {
87-
String result = attendanceService.expireAttendanceCode(code);
88-
89-
if (result.equals("출석 코드가 성공적으로 만료되었습니다")) {
90-
return ApiResponse.success(result, null);
91-
} else {
92-
return ApiResponse.error(result);
93-
}
79+
return attendanceService.expireAttendanceCode(code);
9480
}
9581

9682
// 출석체크 종료 (가장 최근 활성화된 코드 자동 만료)
9783
@Operation(summary = "최근 활성화된 출석 코드 만료", description = "가장 최근 활성화된 출석 코드를 자동으로 만료 처리합니다.")
98-
@ApiResponses({
84+
@ApiResponses(value = {
9985
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "만료 처리 성공"),
10086
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "활성화된 출석 코드가 없음")
10187
})
102-
@PutMapping("/expire-latest")
103-
public ApiResponse<Void> expireLatestAttendance() {
104-
String result = attendanceService.expireLatestAttendanceCode();
105-
106-
if (result.equals("출석 코드가 성공적으로 만료되었습니다")) {
107-
return ApiResponse.success(result, null);
108-
} else {
109-
return ApiResponse.error(result);
110-
}
88+
@PutMapping("/admin/attendance/expire-latest")
89+
public String expireLatestAttendance() {
90+
return attendanceService.expireLatestAttendanceCode();
11191
}
11292

11393
// 출석 상태 변경 (관리자 전용)
11494
@Operation(summary = "출석 상태 변경", description = "관리자가 특정 사용자의 출석 상태를 변경합니다.")
115-
@ApiResponses({
95+
@ApiResponses(value = {
11696
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "출석 상태 변경 성공"),
11797
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청"),
11898
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "출석 기록을 찾을 수 없음")
11999
})
120-
@PutMapping("/status")
121-
public ApiResponse<Void> updateAttendanceStatus(
122-
@io.swagger.v3.oas.annotations.parameters.RequestBody(
123-
description = "출석 상태 변경 요청",
124-
required = true,
125-
content = @Content(schema = @Schema(implementation = UpdateAttendanceStatusReq.class))
126-
)
100+
@PutMapping("/admin/users/{userId}/attendance/{attendanceId}/status")
101+
public boolean updateAttendanceStatus(
102+
@Parameter(description = "사용자 ID", example = "1")
103+
@PathVariable Long userId,
104+
@Parameter(description = "출석 ID", example = "1")
105+
@PathVariable Long attendanceId,
127106
@RequestBody UpdateAttendanceStatusReq req) {
128107

129-
boolean result = attendanceService.updateAttendanceStatus(
130-
req.getAttendanceId(),
131-
req.isStatus()
132-
);
108+
// userId 파라미터 검증은 여기서 할 수 있음 (필요 시)
109+
return attendanceService.updateAttendanceStatus(attendanceId, req.isStatus());
110+
}
111+
112+
// 출석 기록 삭제 (관리자 전용)
113+
@Operation(summary = "출석 기록 삭제", description = "관리자가 특정 사용자의 출석 기록을 삭제합니다.")
114+
@ApiResponses(value = {
115+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "출석 기록 삭제 성공"),
116+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청"),
117+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "출석 기록을 찾을 수 없음")
118+
})
119+
@DeleteMapping("/admin/users/{userId}/attendance/{attendanceId}")
120+
public boolean deleteAttendance(
121+
@Parameter(description = "사용자 ID", example = "1")
122+
@PathVariable Long userId,
123+
@Parameter(description = "출석 ID", example = "1")
124+
@PathVariable Long attendanceId) {
133125

134-
if (result) {
135-
return ApiResponse.success("출석 상태가 성공적으로 변경되었습니다", null);
136-
} else {
137-
return ApiResponse.error("출석 상태 변경에 실패했습니다. 출석 기록을 찾을 수 없습니다.");
138-
}
126+
// userId 파라미터 검증은 여기서 할 수 있음 (필요 시)
127+
return attendanceService.deleteAttendance(attendanceId);
139128
}
140129

141130
// 특정 날짜와 차수에 대한 모든 학생의 출석 현황 조회
142131
@Operation(summary = "특정 날짜와 차수의 출석 현황 조회", description = "특정 날짜와 차수에 대한 모든 학생의 출석 현황을 조회합니다.")
143-
@ApiResponses({
132+
@ApiResponses(value = {
144133
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"),
145134
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청")
146135
})
147-
@GetMapping("/list")
148-
public ApiResponse<List<UserAttendanceStatusRes>> getAllAttendanceByDateAndOrder(
149-
@Parameter(description = "조회할 날짜 (YYYY-MM-DD)", required = true)
136+
@GetMapping("/admin/attendance/list")
137+
public List<UserAttendanceStatusRes> getAllAttendanceByDateAndOrder(
138+
@Parameter(description = "조회할 날짜 (YYYY-MM-DD)", example = "2023-08-01")
139+
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
140+
@Parameter(description = "조회할 차수", example = "1")
141+
@RequestParam int order) {
142+
return attendanceService.findAllByDateAndOrder(date, order);
143+
}
144+
145+
// 특정 사용자의 특정 날짜와 차수 출석 기록 조회
146+
@Operation(summary = "특정 사용자의 특정 날짜와 차수 출석 조회", description = "특정 사용자의 특정 날짜와 차수 출석 기록을 조회합니다.")
147+
@ApiResponses(value = {
148+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"),
149+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청"),
150+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "출석 기록을 찾을 수 없음")
151+
})
152+
@GetMapping("/admin/users/{userId}/attendance")
153+
public UserAttendanceStatusRes getUserAttendanceByDateAndOrder(
154+
@Parameter(description = "사용자 ID", example = "1")
155+
@PathVariable Long userId,
156+
@Parameter(description = "조회할 날짜 (YYYY-MM-DD)", example = "2023-08-01")
150157
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
151-
@Parameter(description = "조회할 차수", required = true)
158+
@Parameter(description = "조회할 차수", example = "1")
152159
@RequestParam int order) {
160+
return attendanceService.findByUserIdAndDateAndOrder(userId, date, order);
161+
}
162+
163+
// 특정 출석 ID로 출석 기록 조회
164+
@Operation(summary = "특정 출석 기록 조회", description = "특정 학생의 특정 출석 기록을 ID로 조회합니다.")
165+
@ApiResponses(value = {
166+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"),
167+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "출석 기록을 찾을 수 없음")
168+
})
169+
@GetMapping("/admin/users/{userId}/attendance/{attendanceId}")
170+
public UserAttendanceStatusRes getAttendanceById(
171+
@Parameter(description = "사용자 ID", example = "1")
172+
@PathVariable Long userId,
173+
@Parameter(description = "출석 ID", example = "1")
174+
@PathVariable Long attendanceId) {
153175

154-
List<UserAttendanceStatusRes> attendances = attendanceService.findAllByDateAndOrder(date, order);
155-
return ApiResponse.success(attendances);
176+
UserAttendanceStatusRes attendance = attendanceService.findById(attendanceId);
177+
178+
if (attendance == null) {
179+
throw new RuntimeException("출석 기록을 찾을 수 없습니다");
180+
}
181+
182+
// 요청된 userId와 조회된 출석 기록의 userId가 일치하는지 확인
183+
if (!attendance.getUserId().equals(userId)) {
184+
throw new RuntimeException("요청된 사용자 ID와 출석 기록의 사용자 ID가 일치하지 않습니다");
185+
}
186+
187+
return attendance;
188+
}
189+
190+
// 학생용 출석 현황 조회
191+
@Operation(summary = "학생별 출석 현황 조회", description = "특정 학생의 출석 현황을 조회합니다.")
192+
@ApiResponses(value = {
193+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"),
194+
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청")
195+
})
196+
@GetMapping("/attendance/{userId}")
197+
public List<UserAttendanceStatusRes> getUserAttendances(
198+
@Parameter(description = "사용자 ID", example = "1")
199+
@PathVariable Long userId) {
200+
return attendanceService.findAllByUserId(userId);
156201
}
157202
}

backend/pirocheck/src/main/java/backend/pirocheck/Attendance/dto/request/UpdateAttendanceStatusReq.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212
@AllArgsConstructor
1313
@Schema(description = "출석 상태 수정 요청")
1414
public class UpdateAttendanceStatusReq {
15-
@Schema(description = "출석 기록 ID", example = "1")
16-
private Long attendanceId;
17-
1815
@Schema(description = "변경할 출석 상태", example = "true")
1916
private boolean status;
2017
}

backend/pirocheck/src/main/java/backend/pirocheck/Attendance/service/AttendanceService.java

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,82 @@ public List<UserAttendanceStatusRes> findAllByDateAndOrder(LocalDate date, int o
247247
.sorted(Comparator.comparing(UserAttendanceStatusRes::getUsername))
248248
.toList();
249249
}
250+
251+
// 특정 학생의 모든 출석 현황 조회
252+
public List<UserAttendanceStatusRes> findAllByUserId(Long userId) {
253+
// 해당 사용자의 모든 출석 기록 조회
254+
List<Attendance> attendances = attendanceRepository.findByUserId(userId);
255+
256+
// DTO 변환
257+
return attendances.stream()
258+
.map(attendance -> {
259+
User user = attendance.getUser();
260+
return UserAttendanceStatusRes.builder()
261+
.userId(user.getId())
262+
.username(user.getName())
263+
.date(attendance.getDate())
264+
.order(attendance.getOrder())
265+
.status(attendance.isStatus())
266+
.attendanceId(attendance.getId())
267+
.build();
268+
})
269+
.sorted(Comparator.comparing(UserAttendanceStatusRes::getDate).reversed()
270+
.thenComparing(UserAttendanceStatusRes::getOrder))
271+
.toList();
272+
}
273+
274+
// 특정 사용자의 특정 출석 기록 삭제
275+
@Transactional
276+
public boolean deleteAttendance(Long attendanceId) {
277+
Optional<Attendance> attendanceOpt = attendanceRepository.findById(attendanceId);
278+
279+
if (attendanceOpt.isEmpty()) {
280+
return false;
281+
}
282+
283+
attendanceRepository.delete(attendanceOpt.get());
284+
return true;
285+
}
286+
287+
// 특정 사용자의 특정 날짜와 차수 출석 기록 조회
288+
public UserAttendanceStatusRes findByUserIdAndDateAndOrder(Long userId, LocalDate date, int order) {
289+
Optional<Attendance> attendanceOpt = attendanceRepository.findByUserIdAndDateAndOrder(userId, date, order);
290+
291+
if (attendanceOpt.isEmpty()) {
292+
return null;
293+
}
294+
295+
Attendance attendance = attendanceOpt.get();
296+
User user = attendance.getUser();
297+
298+
return UserAttendanceStatusRes.builder()
299+
.userId(user.getId())
300+
.username(user.getName())
301+
.date(attendance.getDate())
302+
.order(attendance.getOrder())
303+
.status(attendance.isStatus())
304+
.attendanceId(attendance.getId())
305+
.build();
306+
}
307+
308+
// 특정 출석 ID로 출석 기록 조회
309+
public UserAttendanceStatusRes findById(Long attendanceId) {
310+
Optional<Attendance> attendanceOpt = attendanceRepository.findById(attendanceId);
311+
312+
if (attendanceOpt.isEmpty()) {
313+
return null;
314+
}
315+
316+
Attendance attendance = attendanceOpt.get();
317+
User user = attendance.getUser();
318+
319+
return UserAttendanceStatusRes.builder()
320+
.userId(user.getId())
321+
.username(user.getName())
322+
.date(attendance.getDate())
323+
.order(attendance.getOrder())
324+
.status(attendance.isStatus())
325+
.attendanceId(attendance.getId())
326+
.build();
327+
}
250328
}

0 commit comments

Comments
 (0)