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
@@ -1,7 +1,9 @@
package backend.pirocheck.Attendance.controller;

import backend.pirocheck.Attendance.dto.request.UpdateAttendanceStatusReq;
import backend.pirocheck.Attendance.dto.response.ApiResponse;
import backend.pirocheck.Attendance.dto.response.AttendanceCodeResponse;
import backend.pirocheck.Attendance.dto.response.UserAttendanceStatusRes;
import backend.pirocheck.Attendance.entity.AttendanceCode;
import backend.pirocheck.Attendance.service.AttendanceService;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -12,8 +14,11 @@
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

@RestController
Expand Down Expand Up @@ -79,7 +84,7 @@ public ApiResponse<AttendanceCodeResponse> getActiveCode() {
public ApiResponse<Void> expireAttendance(
@Parameter(description = "만료할 출석 코드", required = true)
@RequestParam String code) {
String result = attendanceService.exprireAttendanceCode(code);
String result = attendanceService.expireAttendanceCode(code);

if (result.equals("출석 코드가 성공적으로 만료되었습니다")) {
return ApiResponse.success(result, null);
Expand All @@ -104,4 +109,49 @@ public ApiResponse<Void> expireLatestAttendance() {
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 = "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))
)
@RequestBody UpdateAttendanceStatusReq req) {

boolean result = attendanceService.updateAttendanceStatus(
req.getAttendanceId(),
req.isStatus()
);

if (result) {
return ApiResponse.success("출석 상태가 성공적으로 변경되었습니다", null);
} else {
return ApiResponse.error("출석 상태 변경에 실패했습니다. 출석 기록을 찾을 수 없습니다.");
}
}

// 특정 날짜와 차수에 대한 모든 학생의 출석 현황 조회
@Operation(summary = "특정 날짜와 차수의 출석 현황 조회", description = "특정 날짜와 차수에 대한 모든 학생의 출석 현황을 조회합니다.")
@ApiResponses({
@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)
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date,
@Parameter(description = "조회할 차수", required = true)
@RequestParam int order) {

List<UserAttendanceStatusRes> attendances = attendanceService.findAllByDateAndOrder(date, order);
return ApiResponse.success(attendances);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package backend.pirocheck.Attendance.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@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
@@ -0,0 +1,34 @@
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;

import java.time.LocalDate;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "사용자 출석 상태 응답")
public class UserAttendanceStatusRes {
@Schema(description = "출석 기록 ID", example = "1")
private Long attendanceId;

@Schema(description = "사용자 ID", example = "1")
private Long userId;

@Schema(description = "사용자 이름", example = "홍길동")
private String username;

@Schema(description = "출석 날짜", example = "2023-10-20")
private LocalDate date;

@Schema(description = "출석 차수", example = "1")
private int order;

@Schema(description = "출석 상태", example = "true")
private boolean status;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ public interface AttendanceRepository extends JpaRepository<Attendance, Long> {

// 출석 실패
int countByUserAndStatusFalse(User user);

// 특정 날짜와 차수에 대한 모든 출석 기록 조회
List<Attendance> findByDateAndOrder(LocalDate date, int order);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import backend.pirocheck.Attendance.dto.response.AttendanceMarkResponse;
import backend.pirocheck.Attendance.dto.response.AttendanceSlotRes;
import backend.pirocheck.Attendance.dto.response.AttendanceStatusRes;
import backend.pirocheck.Attendance.dto.response.UserAttendanceStatusRes;
import backend.pirocheck.Attendance.entity.Attendance;
import backend.pirocheck.Attendance.entity.AttendanceCode;
import backend.pirocheck.Attendance.repository.AttendanceCodeRepository;
Expand Down Expand Up @@ -104,7 +105,7 @@ public String expireLatestAttendanceCode() {

// 출석코드 만료처리 함수
@Transactional
public String exprireAttendanceCode(String code) {
public String expireAttendanceCode(String code) {
Optional<AttendanceCode> codeOpt = attendanceCodeRepository.findByCodeAndDate(code, LocalDate.now());

if (codeOpt.isEmpty()) {
Expand Down Expand Up @@ -208,4 +209,42 @@ public List<AttendanceSlotRes> findByUserIdAndDate(Long userId, LocalDate date)
.sorted(Comparator.comparingInt(AttendanceSlotRes::getOrder))
.toList();
}

// 관리자가 유저의 출석 상태를 변경하는 함수
@Transactional
public boolean updateAttendanceStatus(Long attendanceId, boolean status) {
Optional<Attendance> attendanceOpt = attendanceRepository.findById(attendanceId);

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

// 출석 상태 변경
Attendance attendance = attendanceOpt.get();
attendance.setStatus(status);
attendanceRepository.save(attendance);
return true;
}

// 특정 날짜와 차수의 모든 학생 출석 현황 조회
public List<UserAttendanceStatusRes> findAllByDateAndOrder(LocalDate date, int order) {
// 해당 날짜와 차수에 대한 모든 출석 기록 조회
List<Attendance> attendances = attendanceRepository.findByDateAndOrder(date, order);

// 사용자별로 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()) // 출석 기록 ID 추가
.build();
})
.sorted(Comparator.comparing(UserAttendanceStatusRes::getUsername))
.toList();
}
}