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 @@ -23,135 +23,180 @@

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/admin/attendance")
@RequestMapping("/api")
@Tag(name = "관리자 출석관리", description = "관리자용 출석 관리 API")
public class AdminAttendanceController {

private final AttendanceService attendanceService;

// 출석체크 시작
@Operation(summary = "출석 체크 시작", description = "새로운 출석 코드를 생성하고 출석 체크를 시작합니다.")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(
responseCode = "200",
description = "출석 코드 생성 성공",
content = @Content(schema = @Schema(implementation = AttendanceCodeResponse.class))
),
@ApiResponses(value = {
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "출석 코드 생성 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청")
})
@PostMapping("/start")
public ApiResponse<AttendanceCodeResponse> startAttendance() {
@PostMapping("/admin/attendance/start")
public AttendanceCodeResponse startAttendance() {
try {
AttendanceCode code = attendanceService.generateCodeAndCreateAttendances();
return ApiResponse.success(AttendanceCodeResponse.from(code));
return AttendanceCodeResponse.from(code);
} catch (IllegalStateException e) {
// 하루 최대 출석 체크 횟수를 초과한 경우
return ApiResponse.error(e.getMessage());
throw new IllegalStateException(e.getMessage());
} catch (Exception e) {
return ApiResponse.error("출석 코드 생성 중 오류가 발생했습니다: " + e.getMessage());
throw new RuntimeException("출석 코드 생성 중 오류가 발생했습니다: " + e.getMessage());
}
}

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

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

return ApiResponse.success(AttendanceCodeResponse.from(codeOpt.get()));
return AttendanceCodeResponse.from(codeOpt.get());
}

// 출석체크 종료 (코드 직접 전달)
@Operation(summary = "특정 출석 코드 만료", description = "특정 출석 코드를 만료 처리합니다.")
@ApiResponses({
@ApiResponses(value = {
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "만료 처리 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "출석 코드를 찾을 수 없음")
})
@PutMapping("/expire")
public ApiResponse<Void> expireAttendance(
@Parameter(description = "만료할 출석 코드", required = true)
@PutMapping("/admin/attendance/expire")
public String expireAttendance(
@Parameter(description = "만료할 출석 코드", example = "1234")
@RequestParam String code) {
String result = attendanceService.expireAttendanceCode(code);

if (result.equals("출석 코드가 성공적으로 만료되었습니다")) {
return ApiResponse.success(result, null);
} else {
return ApiResponse.error(result);
}
return attendanceService.expireAttendanceCode(code);
}

// 출석체크 종료 (가장 최근 활성화된 코드 자동 만료)
@Operation(summary = "최근 활성화된 출석 코드 만료", description = "가장 최근 활성화된 출석 코드를 자동으로 만료 처리합니다.")
@ApiResponses({
@ApiResponses(value = {
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "만료 처리 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "활성화된 출석 코드가 없음")
})
@PutMapping("/expire-latest")
public ApiResponse<Void> expireLatestAttendance() {
String result = attendanceService.expireLatestAttendanceCode();

if (result.equals("출석 코드가 성공적으로 만료되었습니다")) {
return ApiResponse.success(result, null);
} else {
return ApiResponse.error(result);
}
@PutMapping("/admin/attendance/expire-latest")
public String expireLatestAttendance() {
return attendanceService.expireLatestAttendanceCode();
}

// 출석 상태 변경 (관리자 전용)
@Operation(summary = "출석 상태 변경", description = "관리자가 특정 사용자의 출석 상태를 변경합니다.")
@ApiResponses({
@ApiResponses(value = {
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "출석 상태 변경 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "출석 기록을 찾을 수 없음")
})
@PutMapping("/status")
public ApiResponse<Void> updateAttendanceStatus(
@io.swagger.v3.oas.annotations.parameters.RequestBody(
description = "출석 상태 변경 요청",
required = true,
content = @Content(schema = @Schema(implementation = UpdateAttendanceStatusReq.class))
)
@PutMapping("/admin/users/{userId}/attendance/{attendanceId}/status")
public boolean updateAttendanceStatus(
@Parameter(description = "사용자 ID", example = "1")
@PathVariable Long userId,
@Parameter(description = "출석 ID", example = "1")
@PathVariable Long attendanceId,
@RequestBody UpdateAttendanceStatusReq req) {

boolean result = attendanceService.updateAttendanceStatus(
req.getAttendanceId(),
req.isStatus()
);
// userId 파라미터 검증은 여기서 할 수 있음 (필요 시)
return attendanceService.updateAttendanceStatus(attendanceId, req.isStatus());
}

// 출석 기록 삭제 (관리자 전용)
@Operation(summary = "출석 기록 삭제", description = "관리자가 특정 사용자의 출석 기록을 삭제합니다.")
@ApiResponses(value = {
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "출석 기록 삭제 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "출석 기록을 찾을 수 없음")
})
@DeleteMapping("/admin/users/{userId}/attendance/{attendanceId}")
public boolean deleteAttendance(
@Parameter(description = "사용자 ID", example = "1")
@PathVariable Long userId,
@Parameter(description = "출석 ID", example = "1")
@PathVariable Long attendanceId) {

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

// 특정 날짜와 차수에 대한 모든 학생의 출석 현황 조회
@Operation(summary = "특정 날짜와 차수의 출석 현황 조회", description = "특정 날짜와 차수에 대한 모든 학생의 출석 현황을 조회합니다.")
@ApiResponses({
@ApiResponses(value = {
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청")
})
@GetMapping("/list")
public ApiResponse<List<UserAttendanceStatusRes>> getAllAttendanceByDateAndOrder(
@Parameter(description = "조회할 날짜 (YYYY-MM-DD)", required = true)
@GetMapping("/admin/attendance/list")
public List<UserAttendanceStatusRes> getAllAttendanceByDateAndOrder(
@Parameter(description = "조회할 날짜 (YYYY-MM-DD)", example = "2023-08-01")
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
@Parameter(description = "조회할 차수", example = "1")
@RequestParam int order) {
return attendanceService.findAllByDateAndOrder(date, order);
}

// 특정 사용자의 특정 날짜와 차수 출석 기록 조회
@Operation(summary = "특정 사용자의 특정 날짜와 차수 출석 조회", description = "특정 사용자의 특정 날짜와 차수 출석 기록을 조회합니다.")
@ApiResponses(value = {
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "출석 기록을 찾을 수 없음")
})
@GetMapping("/admin/users/{userId}/attendance")
public UserAttendanceStatusRes getUserAttendanceByDateAndOrder(
@Parameter(description = "사용자 ID", example = "1")
@PathVariable Long userId,
@Parameter(description = "조회할 날짜 (YYYY-MM-DD)", example = "2023-08-01")
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
@Parameter(description = "조회할 차수", required = true)
@Parameter(description = "조회할 차수", example = "1")
@RequestParam int order) {
return attendanceService.findByUserIdAndDateAndOrder(userId, date, order);
}

// 특정 출석 ID로 출석 기록 조회
@Operation(summary = "특정 출석 기록 조회", description = "특정 학생의 특정 출석 기록을 ID로 조회합니다.")
@ApiResponses(value = {
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "출석 기록을 찾을 수 없음")
})
@GetMapping("/admin/users/{userId}/attendance/{attendanceId}")
public UserAttendanceStatusRes getAttendanceById(
@Parameter(description = "사용자 ID", example = "1")
@PathVariable Long userId,
@Parameter(description = "출석 ID", example = "1")
@PathVariable Long attendanceId) {

List<UserAttendanceStatusRes> attendances = attendanceService.findAllByDateAndOrder(date, order);
return ApiResponse.success(attendances);
UserAttendanceStatusRes attendance = attendanceService.findById(attendanceId);

if (attendance == null) {
throw new RuntimeException("출석 기록을 찾을 수 없습니다");
}

// 요청된 userId와 조회된 출석 기록의 userId가 일치하는지 확인
if (!attendance.getUserId().equals(userId)) {
throw new RuntimeException("요청된 사용자 ID와 출석 기록의 사용자 ID가 일치하지 않습니다");
}

return attendance;
}

// 학생용 출석 현황 조회
@Operation(summary = "학생별 출석 현황 조회", description = "특정 학생의 출석 현황을 조회합니다.")
@ApiResponses(value = {
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "조회 성공"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청")
})
@GetMapping("/attendance/{userId}")
public List<UserAttendanceStatusRes> getUserAttendances(
@Parameter(description = "사용자 ID", example = "1")
@PathVariable Long userId) {
return attendanceService.findAllByUserId(userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
@AllArgsConstructor
@Schema(description = "출석 상태 수정 요청")
public class UpdateAttendanceStatusReq {
@Schema(description = "출석 기록 ID", example = "1")
private Long attendanceId;

@Schema(description = "변경할 출석 상태", example = "true")
private boolean status;
}
Original file line number Diff line number Diff line change
Expand Up @@ -247,4 +247,82 @@ public List<UserAttendanceStatusRes> findAllByDateAndOrder(LocalDate date, int o
.sorted(Comparator.comparing(UserAttendanceStatusRes::getUsername))
.toList();
}

// 특정 학생의 모든 출석 현황 조회
public List<UserAttendanceStatusRes> findAllByUserId(Long userId) {
// 해당 사용자의 모든 출석 기록 조회
List<Attendance> attendances = attendanceRepository.findByUserId(userId);

// DTO 변환
return attendances.stream()
.map(attendance -> {
User user = attendance.getUser();
return UserAttendanceStatusRes.builder()
.userId(user.getId())
.username(user.getName())
.date(attendance.getDate())
.order(attendance.getOrder())
.status(attendance.isStatus())
.attendanceId(attendance.getId())
.build();
})
.sorted(Comparator.comparing(UserAttendanceStatusRes::getDate).reversed()
.thenComparing(UserAttendanceStatusRes::getOrder))
.toList();
}

// 특정 사용자의 특정 출석 기록 삭제
@Transactional
public boolean deleteAttendance(Long attendanceId) {
Optional<Attendance> attendanceOpt = attendanceRepository.findById(attendanceId);

if (attendanceOpt.isEmpty()) {
return false;
}

attendanceRepository.delete(attendanceOpt.get());
return true;
}

// 특정 사용자의 특정 날짜와 차수 출석 기록 조회
public UserAttendanceStatusRes findByUserIdAndDateAndOrder(Long userId, LocalDate date, int order) {
Optional<Attendance> attendanceOpt = attendanceRepository.findByUserIdAndDateAndOrder(userId, date, order);

if (attendanceOpt.isEmpty()) {
return null;
}

Attendance attendance = attendanceOpt.get();
User user = attendance.getUser();

return UserAttendanceStatusRes.builder()
.userId(user.getId())
.username(user.getName())
.date(attendance.getDate())
.order(attendance.getOrder())
.status(attendance.isStatus())
.attendanceId(attendance.getId())
.build();
}

// 특정 출석 ID로 출석 기록 조회
public UserAttendanceStatusRes findById(Long attendanceId) {
Optional<Attendance> attendanceOpt = attendanceRepository.findById(attendanceId);

if (attendanceOpt.isEmpty()) {
return null;
}

Attendance attendance = attendanceOpt.get();
User user = attendance.getUser();

return UserAttendanceStatusRes.builder()
.userId(user.getId())
.username(user.getName())
.date(attendance.getDate())
.order(attendance.getOrder())
.status(attendance.isStatus())
.attendanceId(attendance.getId())
.build();
}
}