From f2ccf896c31d527b1a839c4ed04084c85fa5083e Mon Sep 17 00:00:00 2001 From: dietken1 Date: Sun, 18 May 2025 23:20:16 +0900 Subject: [PATCH] =?UTF-8?q?api=20response=20=EB=B0=8F=20swagger=EB=AC=B8?= =?UTF-8?q?=EC=84=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AdminAttendanceController.java | 107 ++++++++++++++++++ .../dto/response/AttendanceMarkResponse.java | 68 +++++++++++ .../pirocheck/config/SwaggerConfig.java | 24 ++++ 3 files changed, 199 insertions(+) create mode 100644 backend/pirocheck/src/main/java/backend/pirocheck/Attendance/controller/AdminAttendanceController.java create mode 100644 backend/pirocheck/src/main/java/backend/pirocheck/Attendance/dto/response/AttendanceMarkResponse.java create mode 100644 backend/pirocheck/src/main/java/backend/pirocheck/config/SwaggerConfig.java diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/controller/AdminAttendanceController.java b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/controller/AdminAttendanceController.java new file mode 100644 index 0000000..f811f53 --- /dev/null +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/controller/AdminAttendanceController.java @@ -0,0 +1,107 @@ +package backend.pirocheck.Attendance.controller; + +import backend.pirocheck.Attendance.dto.response.ApiResponse; +import backend.pirocheck.Attendance.dto.response.AttendanceCodeResponse; +import backend.pirocheck.Attendance.entity.AttendanceCode; +import backend.pirocheck.Attendance.service.AttendanceService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.Optional; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/admin/attendance") +@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)) + ), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "잘못된 요청") + }) + @PostMapping("/start") + public ApiResponse startAttendance() { + try { + AttendanceCode code = attendanceService.generateCodeAndCreateAttendances(); + return ApiResponse.success(AttendanceCodeResponse.from(code)); + } catch (IllegalStateException e) { + // 하루 최대 출석 체크 횟수를 초과한 경우 + return ApiResponse.error(e.getMessage()); + } catch (Exception e) { + return ApiResponse.error("출석 코드 생성 중 오류가 발생했습니다: " + e.getMessage()); + } + } + + // 현재 활성화된 출석코드 조회 + @Operation(summary = "현재 활성화된 출석 코드 조회", description = "현재 활성화된 출석 코드 정보를 조회합니다.") + @ApiResponses({ + @io.swagger.v3.oas.annotations.responses.ApiResponse( + responseCode = "200", + description = "조회 성공", + content = @Content(schema = @Schema(implementation = AttendanceCodeResponse.class)) + ), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "활성화된 출석 코드 없음") + }) + @GetMapping("/active-code") + public ApiResponse getActiveCode() { + Optional codeOpt = attendanceService.getActiveAttendanceCode(); + + if (codeOpt.isEmpty()) { + return ApiResponse.error("현재 활성화된 출석코드가 없습니다"); + } + + return ApiResponse.success(AttendanceCodeResponse.from(codeOpt.get())); + } + + // 출석체크 종료 (코드 직접 전달) + @Operation(summary = "특정 출석 코드 만료", description = "특정 출석 코드를 만료 처리합니다.") + @ApiResponses({ + @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 expireAttendance( + @Parameter(description = "만료할 출석 코드", required = true) + @RequestParam String code) { + String result = attendanceService.exprireAttendanceCode(code); + + if (result.equals("출석 코드가 성공적으로 만료되었습니다")) { + return ApiResponse.success(result, null); + } else { + return ApiResponse.error(result); + } + } + + // 출석체크 종료 (가장 최근 활성화된 코드 자동 만료) + @Operation(summary = "최근 활성화된 출석 코드 만료", description = "가장 최근 활성화된 출석 코드를 자동으로 만료 처리합니다.") + @ApiResponses({ + @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 expireLatestAttendance() { + String result = attendanceService.expireLatestAttendanceCode(); + + if (result.equals("출석 코드가 성공적으로 만료되었습니다")) { + return ApiResponse.success(result, null); + } else { + return ApiResponse.error(result); + } + } +} \ No newline at end of file diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/dto/response/AttendanceMarkResponse.java b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/dto/response/AttendanceMarkResponse.java new file mode 100644 index 0000000..73ee0d7 --- /dev/null +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Attendance/dto/response/AttendanceMarkResponse.java @@ -0,0 +1,68 @@ +package backend.pirocheck.Attendance.dto.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "출석 체크 응답") +public class AttendanceMarkResponse { + @Schema(description = "응답 메시지", example = "출석이 성공적으로 처리되었습니다") + private String message; + + @Schema(description = "상태 코드 (SUCCESS, ALREADY_MARKED, INVALID_CODE, NO_ACTIVE_SESSION, CODE_EXPIRED, ERROR)", example = "SUCCESS") + private String statusCode; + + // 출석 성공 + public static AttendanceMarkResponse success() { + return AttendanceMarkResponse.builder() + .statusCode("SUCCESS") + .message("출석이 성공적으로 처리되었습니다") + .build(); + } + + // 이미 출석 완료 + public static AttendanceMarkResponse alreadyMarked() { + return AttendanceMarkResponse.builder() + .statusCode("ALREADY_MARKED") + .message("이미 출석처리가 완료되었습니다") + .build(); + } + + // 출석체크 진행중 아님 + public static AttendanceMarkResponse noActiveSession() { + return AttendanceMarkResponse.builder() + .statusCode("NO_ACTIVE_SESSION") + .message("출석 코드가 존재하지 않습니다. 현재 출석 체크가 진행중이 아닙니다") + .build(); + } + + // 잘못된 출석 코드 입력 + public static AttendanceMarkResponse invalidCode() { + return AttendanceMarkResponse.builder() + .statusCode("INVALID_CODE") + .message("잘못된 출석 코드입니다. 다시 확인해주세요") + .build(); + } + + // 출석 코드 만료 + public static AttendanceMarkResponse codeExpired() { + return AttendanceMarkResponse.builder() + .statusCode("CODE_EXPIRED") + .message("출석 코드가 만료되었습니다") + .build(); + } + + // 기타 오류 + public static AttendanceMarkResponse error(String message) { + return AttendanceMarkResponse.builder() + .statusCode("ERROR") + .message(message) + .build(); + } +} \ No newline at end of file diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/config/SwaggerConfig.java b/backend/pirocheck/src/main/java/backend/pirocheck/config/SwaggerConfig.java new file mode 100644 index 0000000..aa87446 --- /dev/null +++ b/backend/pirocheck/src/main/java/backend/pirocheck/config/SwaggerConfig.java @@ -0,0 +1,24 @@ +package backend.pirocheck.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.servers.Server; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + + @Bean + public OpenAPI openAPI() { + return new OpenAPI() + .info(new Info() + .title("PiroCheck API") + .description("피로그래밍 출석체크 시스템 API 문서") + .version("v1.0.0") + .license(new License().name("MIT").url("https://opensource.org/licenses/MIT"))) + .addServersItem(new Server().url("/").description("Default Server URL")); + } +} \ No newline at end of file