From d16d54d32d862918997a20297ca088fcc9c4eb31 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Wed, 31 Jul 2024 16:45:08 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat:=20=EA=B4=80=EB=A6=AC=EC=9E=90?= =?UTF-8?q?=EA=B0=80=20=EC=B6=9C=EC=84=9D=EB=B6=80=EB=A5=BC=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=98=A4=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: 관리자가 출석부를 가져오는 기능 구현 --- .../controller/AttendanceAdminController.java | 44 +++++++ .../AttendanceMemberController.java | 13 +++ .../dto/AttendanceInfoResponse.java | 21 ++++ .../dto/AttendanceRecordResponse.java | 54 +++++++++ .../dto/UpdateAttendanceRequest.java | 22 ++++ .../api/session/dto/AddSessionRequest.java | 17 +++ .../csquiz/common/config/SecurityConfig.java | 1 + .../cotato/csquiz/common/error/ErrorCode.java | 3 +- .../domain/attendance/entity/Attendance.java | 21 ++++ .../attendance/entity/AttendanceRecord.java | 5 + .../attendance/enums/AttendanceStatus.java | 14 +++ .../AttendanceRecordRepository.java | 13 +++ .../repository/AttendanceRepository.java | 12 ++ .../service/AttendanceAdminService.java | 108 ++++++++++++++++++ .../service/AttendanceMemberService.java | 13 +++ .../domain/generation/entity/Session.java | 9 +- .../repository/SessionRepository.java | 2 + .../generation/service/SessionService.java | 7 ++ 18 files changed, 375 insertions(+), 4 deletions(-) create mode 100644 src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceAdminController.java create mode 100644 src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceMemberController.java create mode 100644 src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceInfoResponse.java create mode 100644 src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java create mode 100644 src/main/java/org/cotato/csquiz/api/attendance/dto/UpdateAttendanceRequest.java create mode 100644 src/main/java/org/cotato/csquiz/domain/attendance/enums/AttendanceStatus.java create mode 100644 src/main/java/org/cotato/csquiz/domain/attendance/repository/AttendanceRecordRepository.java create mode 100644 src/main/java/org/cotato/csquiz/domain/attendance/repository/AttendanceRepository.java create mode 100644 src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java create mode 100644 src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceMemberService.java diff --git a/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceAdminController.java b/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceAdminController.java new file mode 100644 index 00000000..9b7461b7 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceAdminController.java @@ -0,0 +1,44 @@ +package org.cotato.csquiz.api.attendance.controller; + +import io.swagger.v3.oas.annotations.Operation; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.cotato.csquiz.api.attendance.dto.AttendanceRecordResponse; +import org.cotato.csquiz.api.attendance.dto.UpdateAttendanceRequest; +import org.cotato.csquiz.domain.attendance.service.AttendanceAdminService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/v2/api/attendance/admin") +public class AttendanceAdminController { + + private final AttendanceAdminService attendanceAdminService; + + @Operation(summary = "출석 정보 변경 API") + @PatchMapping("/update") + public ResponseEntity updateAttendance(@RequestBody @Valid UpdateAttendanceRequest request) { + attendanceAdminService.updateAttendance(request); + return ResponseEntity.noContent().build(); + } + + @Operation(summary = "회원 출결사항 조회 API") + @GetMapping("/records") + public ResponseEntity> findAttendanceRecords( + @RequestParam(name = "generationId") Long generationId, + @RequestParam(name = "month", required = false) @Min(1) @Max(12) Integer month + ) { + return ResponseEntity.ok().body(attendanceAdminService.findAttendanceRecords(generationId, month)); + } +} diff --git a/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceMemberController.java b/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceMemberController.java new file mode 100644 index 00000000..b7d98ae6 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceMemberController.java @@ -0,0 +1,13 @@ +package org.cotato.csquiz.api.attendance.controller; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/v2/api/attendance/member") +public class AttendanceMemberController { +} diff --git a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceInfoResponse.java b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceInfoResponse.java new file mode 100644 index 00000000..03ec9286 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceInfoResponse.java @@ -0,0 +1,21 @@ +package org.cotato.csquiz.api.attendance.dto; + +import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; +import org.cotato.csquiz.domain.attendance.enums.AttendanceStatus; +import org.cotato.csquiz.domain.attendance.enums.AttendanceType; + +public record AttendanceInfoResponse( + Long attendanceId, + Long attendanceRecordId, + AttendanceType attendanceType, + AttendanceStatus attendanceStatus +) { + public static AttendanceInfoResponse from(AttendanceRecord attendanceRecord) { + return new AttendanceInfoResponse( + attendanceRecord.getAttendance().getId(), + attendanceRecord.getId(), + attendanceRecord.getAttendanceType(), + attendanceRecord.getAttendanceStatus() + ); + } +} diff --git a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java new file mode 100644 index 00000000..30806620 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java @@ -0,0 +1,54 @@ +package org.cotato.csquiz.api.attendance.dto; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.cotato.csquiz.api.admin.dto.MemberInfoResponse; +import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; +import org.cotato.csquiz.domain.attendance.enums.AttendanceStatus; +import org.cotato.csquiz.domain.attendance.enums.AttendanceType; + + +public record AttendanceRecordResponse( + MemberInfoResponse memberInfo, + List attendanceInfos, + AttendanceStatistic statistic +) { + public static AttendanceRecordResponse of(MemberInfoResponse memberInfo, List attendanceRecords, + Integer totalAttendance) { + return new AttendanceRecordResponse( + memberInfo, + attendanceRecords.stream() + .map(AttendanceInfoResponse::from) + .toList(), + AttendanceStatistic.from(attendanceRecords, totalAttendance) + ); + } + + public record AttendanceStatistic( + Integer onLine, + Integer offLine, + Integer late, + Integer absent + ) { + public static AttendanceStatistic from(List attendanceRecords, Integer totalAttendance) { + Map> countByStatus = attendanceRecords.stream() + .collect(Collectors.groupingBy(AttendanceRecord::getAttendanceStatus)); + List presentRecords = countByStatus.getOrDefault(AttendanceStatus.PRESENT, List.of()); + + int onlineCount = (int) presentRecords.stream() + .filter(record -> AttendanceType.ONLINE == record.getAttendanceType()) + .count(); + int offLineCount = (int) presentRecords.stream() + .filter(record -> AttendanceType.OFFLINE == record.getAttendanceType()) + .count(); + + return new AttendanceStatistic( + onlineCount, + offLineCount, + countByStatus.getOrDefault(AttendanceStatus.LATE, List.of()).size(), + totalAttendance - attendanceRecords.size() + ); + } + } +} diff --git a/src/main/java/org/cotato/csquiz/api/attendance/dto/UpdateAttendanceRequest.java b/src/main/java/org/cotato/csquiz/api/attendance/dto/UpdateAttendanceRequest.java new file mode 100644 index 00000000..f06c220f --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/attendance/dto/UpdateAttendanceRequest.java @@ -0,0 +1,22 @@ +package org.cotato.csquiz.api.attendance.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.NotNull; +import java.time.LocalTime; +import org.cotato.csquiz.domain.attendance.embedded.Location; + +public record UpdateAttendanceRequest( + Long attendanceId, + Location location, + + @NotNull + AttendanceDeadLine attendanceDeadLine +) { + public record AttendanceDeadLine( + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss") + LocalTime startTime, + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss") + LocalTime endTime + ) { + } +} diff --git a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java index efcaff72..f46be7a3 100644 --- a/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java +++ b/src/main/java/org/cotato/csquiz/api/session/dto/AddSessionRequest.java @@ -1,6 +1,10 @@ package org.cotato.csquiz.api.session.dto; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.time.LocalDate; +import java.time.LocalTime; import java.util.List; +import org.cotato.csquiz.domain.attendance.embedded.Location; import org.cotato.csquiz.domain.generation.enums.CSEducation; import org.cotato.csquiz.domain.generation.enums.DevTalk; import org.cotato.csquiz.domain.generation.enums.ItIssue; @@ -16,9 +20,22 @@ public record AddSessionRequest( String title, @NotNull String description, + Location location, + String placeName, + @NotNull + LocalDate sessionDate, + @NotNull + AttendanceDeadLine attendanceDeadLine, ItIssue itIssue, Networking networking, CSEducation csEducation, DevTalk devTalk ) { + public record AttendanceDeadLine( + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss") + LocalTime startTime, + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss") + LocalTime endTime + ){ + } } diff --git a/src/main/java/org/cotato/csquiz/common/config/SecurityConfig.java b/src/main/java/org/cotato/csquiz/common/config/SecurityConfig.java index 17cf48d7..cb1c2926 100644 --- a/src/main/java/org/cotato/csquiz/common/config/SecurityConfig.java +++ b/src/main/java/org/cotato/csquiz/common/config/SecurityConfig.java @@ -78,6 +78,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers("/v1/api/session/cs-on").hasAnyRole("EDUCATION", "ADMIN") .requestMatchers(new AntPathRequestMatcher("/v1/api/session", "GET")).authenticated() .requestMatchers("/v1/api/session/**").hasAnyRole("ADMIN") + .requestMatchers("/v2/api/attendance/admin/**").hasAnyRole("ADMIN") .requestMatchers(new AntPathRequestMatcher("/v1/api/socket/token", "POST")) .hasAnyRole("MEMBER", "EDUCATION", "ADMIN") .requestMatchers("/v1/api/socket/**").hasAnyRole("EDUCATION", "ADMIN") diff --git a/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java b/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java index 35b41c99..47687a5b 100644 --- a/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java +++ b/src/main/java/org/cotato/csquiz/common/error/ErrorCode.java @@ -43,7 +43,8 @@ public enum ErrorCode { // 기수 운영 (세션 -> 출석) INVALID_DATE(HttpStatus.BAD_REQUEST, "G-101", "시작날짜가 끝 날짜보다 뒤입니다"), GENERATION_NUMBER_DUPLICATED(HttpStatus.CONFLICT, "G-201", "같은 숫자의 기수가 있습니다"), - + SESSION_DATE_NOT_FOUND(HttpStatus.NOT_FOUND, "G-202", "세션 날짜가 존재하지 않습니다"), + SESSION_DEADLINE_INVALID(HttpStatus.BAD_REQUEST, "G-102", "시작 시간과 끝 시간을 입력해주세요"), // 교육 도메인 REGRADE_FAIL(HttpStatus.BAD_REQUEST, "E-201", "재채점 할 기록이 없습니다."), EDUCATION_DUPLICATED(HttpStatus.CONFLICT, "E-301", "이미 교육이 존재합니다"), diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/entity/Attendance.java b/src/main/java/org/cotato/csquiz/domain/attendance/entity/Attendance.java index 6dadae33..44141dcf 100644 --- a/src/main/java/org/cotato/csquiz/domain/attendance/entity/Attendance.java +++ b/src/main/java/org/cotato/csquiz/domain/attendance/entity/Attendance.java @@ -5,12 +5,16 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import java.time.LocalDate; import java.time.LocalDateTime; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.cotato.csquiz.api.attendance.dto.UpdateAttendanceRequest.AttendanceDeadLine; import org.cotato.csquiz.common.entity.BaseTimeEntity; import org.cotato.csquiz.domain.attendance.embedded.Location; +import org.cotato.csquiz.domain.generation.entity.Session; @Entity @Getter @@ -32,4 +36,21 @@ public class Attendance extends BaseTimeEntity { @Column(name = "session_id", nullable = false, unique = true) private Long sessionId; + + @Builder + public Attendance(LocalDateTime startTime, LocalDateTime endTime, Location location, Session session) { + this.startTime = startTime; + this.endTime = endTime; + this.location = location; + this.sessionId = session.getId(); + } + + public void updateLocation(Location location) { + this.location = location; + } + + public void updateDeadLine(LocalDate sessionDate, AttendanceDeadLine deadLine) { + this.startTime = LocalDateTime.of(sessionDate, deadLine.startTime()); + this.endTime = LocalDateTime.of(sessionDate, deadLine.endTime()); + } } diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/entity/AttendanceRecord.java b/src/main/java/org/cotato/csquiz/domain/attendance/entity/AttendanceRecord.java index f6473084..6304edda 100644 --- a/src/main/java/org/cotato/csquiz/domain/attendance/entity/AttendanceRecord.java +++ b/src/main/java/org/cotato/csquiz/domain/attendance/entity/AttendanceRecord.java @@ -15,6 +15,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import org.cotato.csquiz.common.entity.BaseTimeEntity; +import org.cotato.csquiz.domain.attendance.enums.AttendanceStatus; import org.cotato.csquiz.domain.attendance.enums.AttendanceType; @Table(name = "attendance_record") @@ -32,6 +33,10 @@ public class AttendanceRecord extends BaseTimeEntity { @Enumerated(EnumType.STRING) private AttendanceType attendanceType; + @Column(name = "attendance_status", nullable = false) + @Enumerated(EnumType.STRING) + private AttendanceStatus attendanceStatus; + @Column(name = "location_accuracy") private Double locationAccuracy; diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/enums/AttendanceStatus.java b/src/main/java/org/cotato/csquiz/domain/attendance/enums/AttendanceStatus.java new file mode 100644 index 00000000..60c7afe2 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/attendance/enums/AttendanceStatus.java @@ -0,0 +1,14 @@ +package org.cotato.csquiz.domain.attendance.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum AttendanceStatus { + PRESENT("출석"), + LATE("지각"), + ; + + private final String description; +} diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/repository/AttendanceRecordRepository.java b/src/main/java/org/cotato/csquiz/domain/attendance/repository/AttendanceRecordRepository.java new file mode 100644 index 00000000..c9cfc874 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/attendance/repository/AttendanceRecordRepository.java @@ -0,0 +1,13 @@ +package org.cotato.csquiz.domain.attendance.repository; + +import java.util.List; +import org.cotato.csquiz.domain.attendance.entity.Attendance; +import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface AttendanceRecordRepository extends JpaRepository { + @Query("select a from AttendanceRecord a where a.attendance in :attendances") + List findAllByAttendanceIdsInQuery(@Param("attendances") List attendances); +} diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/repository/AttendanceRepository.java b/src/main/java/org/cotato/csquiz/domain/attendance/repository/AttendanceRepository.java new file mode 100644 index 00000000..63882a31 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/attendance/repository/AttendanceRepository.java @@ -0,0 +1,12 @@ +package org.cotato.csquiz.domain.attendance.repository; + +import java.util.List; +import org.cotato.csquiz.domain.attendance.entity.Attendance; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface AttendanceRepository extends JpaRepository { + @Query("select a from Attendance a where a.sessionId in :sessionIds") + List findAllBySessionIdsInQuery(@Param("sessionIds") List sessionIds); +} diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java new file mode 100644 index 00000000..3b1a0cf4 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java @@ -0,0 +1,108 @@ +package org.cotato.csquiz.domain.attendance.service; + + +import jakarta.persistence.EntityNotFoundException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.cotato.csquiz.api.admin.dto.MemberInfoResponse; +import org.cotato.csquiz.api.attendance.dto.AttendanceRecordResponse; +import org.cotato.csquiz.api.attendance.dto.UpdateAttendanceRequest; +import org.cotato.csquiz.api.session.dto.AddSessionRequest.AttendanceDeadLine; +import org.cotato.csquiz.common.error.ErrorCode; +import org.cotato.csquiz.common.error.exception.AppException; +import org.cotato.csquiz.domain.attendance.embedded.Location; +import org.cotato.csquiz.domain.attendance.entity.Attendance; +import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; +import org.cotato.csquiz.domain.attendance.repository.AttendanceRecordRepository; +import org.cotato.csquiz.domain.attendance.repository.AttendanceRepository; +import org.cotato.csquiz.domain.auth.service.MemberService; +import org.cotato.csquiz.domain.generation.entity.Session; +import org.cotato.csquiz.domain.generation.repository.SessionRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Slf4j +public class AttendanceAdminService { + + private final AttendanceRepository attendanceRepository; + private final AttendanceRecordRepository attendanceRecordRepository; + private final SessionRepository sessionRepository; + private final MemberService memberService; + + @Transactional + public void addAttendance(Session session, LocalDate localDate, Location location, + AttendanceDeadLine attendanceDeadLine) { + + if (checkAttendanceTimeValid(attendanceDeadLine.startTime(), attendanceDeadLine.endTime())) { + throw new AppException(ErrorCode.SESSION_DEADLINE_INVALID); + } + + Attendance attendance = Attendance.builder() + .session(session) + .location(location) + .startTime(LocalDateTime.of(localDate, attendanceDeadLine.startTime())) + .endTime(LocalDateTime.of(localDate, attendanceDeadLine.endTime())) + .build(); + + attendanceRepository.save(attendance); + } + + + @Transactional + public void updateAttendance(UpdateAttendanceRequest request) { + Attendance attendance = attendanceRepository.findById(request.attendanceId()) + .orElseThrow(() -> new EntityNotFoundException("해당 출석 정보가 존재하지 않습니다")); + Session attendanceSession = sessionRepository.findById(attendance.getSessionId()) + .orElseThrow(() -> new EntityNotFoundException("출석과 연결된 세션을 찾을 수 없습니다")); + + if (attendanceSession.getSessionDate() == null) { + throw new AppException(ErrorCode.SESSION_DATE_NOT_FOUND); + } + + if (checkAttendanceTimeValid(request.attendanceDeadLine().startTime(), request.attendanceDeadLine().endTime())) { + throw new AppException(ErrorCode.SESSION_DEADLINE_INVALID); + } + + attendance.updateDeadLine(attendanceSession.getSessionDate(), request.attendanceDeadLine()); + attendance.updateLocation(request.location()); + } + + public List findAttendanceRecords(Long generationId, Integer month) { + List sessions = sessionRepository.findAllByGenerationId(generationId); + if (month != null) { + sessions = sessions.stream() + .filter(session -> session.getSessionDate().getMonthValue() == month) + .toList(); + } + List sessionIds = sessions.stream() + .map(Session::getId) + .toList(); + + List attendances = attendanceRepository.findAllBySessionIdsInQuery(sessionIds).stream() + .toList(); + + Map> recordsByMemberId = attendanceRecordRepository.findAllByAttendanceIdsInQuery( + attendances).stream() + .collect(Collectors.groupingBy(AttendanceRecord::getMemberId)); + + return recordsByMemberId.entrySet().stream() + .map(entry -> { + MemberInfoResponse memberInfo = memberService.findMemberInfo(entry.getKey()); + return AttendanceRecordResponse.of(memberInfo, entry.getValue(), attendances.size()); + }) + .toList(); + } + + private boolean checkAttendanceTimeValid(LocalTime startTime, LocalTime endTime) { + return endTime == null || startTime == null; + } +} diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceMemberService.java b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceMemberService.java new file mode 100644 index 00000000..4703aec9 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceMemberService.java @@ -0,0 +1,13 @@ +package org.cotato.csquiz.domain.attendance.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Slf4j +public class AttendanceMemberService { +} diff --git a/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java b/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java index 1ee951a8..a463f8a6 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/entity/Session.java @@ -46,7 +46,7 @@ public class Session extends BaseTimeEntity { @AttributeOverrides({ @AttributeOverride(name = "itIssue", - column = @Column(name = "session_it_issue")), + column = @Column(name = "session_it_issue")), @AttributeOverride(name = "networking", column = @Column(name = "session_networking")), @AttributeOverride(name = "csEducation", @@ -63,10 +63,13 @@ public class Session extends BaseTimeEntity { private String placeName; @Builder - public Session(Integer number, String title, String description, Generation generation, SessionContents sessionContents) { + public Session(Integer number, String title, String description, String placeName, LocalDate sessionDate, + Generation generation, SessionContents sessionContents) { this.number = number; this.title = title; this.description = description; + this.placeName = placeName; + this.sessionDate = sessionDate; this.generation = generation; this.sessionContents = sessionContents; } @@ -83,7 +86,7 @@ public void updateSessionContents(SessionContents sessionContents) { this.sessionContents = sessionContents; } - public void updateSessionTitle(String title){ + public void updateSessionTitle(String title) { this.title = title; } } diff --git a/src/main/java/org/cotato/csquiz/domain/generation/repository/SessionRepository.java b/src/main/java/org/cotato/csquiz/domain/generation/repository/SessionRepository.java index 2ded44e4..cca0ea83 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/repository/SessionRepository.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/repository/SessionRepository.java @@ -9,5 +9,7 @@ public interface SessionRepository extends JpaRepository { List findAllByGeneration(Generation generation); + List findAllByGenerationId(Long generationId); + List findAllByGenerationAndSessionContentsCsEducation(Generation generation, CSEducation csEducation); } diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index 8fc3d2e9..e25bf489 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -25,6 +25,8 @@ import org.cotato.csquiz.common.entity.S3Info; import org.cotato.csquiz.common.error.ErrorCode; import org.cotato.csquiz.common.error.exception.AppException; +import org.cotato.csquiz.domain.attendance.entity.Attendance; +import org.cotato.csquiz.domain.attendance.service.AttendanceAdminService; import org.cotato.csquiz.domain.education.entity.Education; import org.cotato.csquiz.domain.education.service.EducationService; import org.cotato.csquiz.domain.generation.embedded.SessionContents; @@ -51,6 +53,7 @@ public class SessionService { private final SessionRepository sessionRepository; private final GenerationRepository generationRepository; private final SessionImageRepository sessionImageRepository; + private final AttendanceAdminService attendanceAdminService; private final EducationService educationService; private final S3Uploader s3Uploader; @@ -67,6 +70,8 @@ public AddSessionResponse addSession(AddSessionRequest request) throws ImageExce .description(request.description()) .generation(findGeneration) .title(request.title()) + .placeName(request.placeName()) + .sessionDate(request.sessionDate()) .sessionContents(SessionContents.builder() .csEducation(request.csEducation()) .devTalk(request.devTalk()) @@ -98,6 +103,8 @@ public AddSessionResponse addSession(AddSessionRequest request) throws ImageExce log.info("세션 이미지 생성 완료"); } + attendanceAdminService.addAttendance(session, request.sessionDate() ,request.location(), request.attendanceDeadLine()); + return AddSessionResponse.from(savedSession); } From d2a74ad1e1f1dc9b7ce2e567d94655e1cd7af3ae Mon Sep 17 00:00:00 2001 From: gikhoon Date: Thu, 1 Aug 2024 16:34:57 +0900 Subject: [PATCH 2/8] =?UTF-8?q?refactor:=20=EC=B6=9C=EC=84=9D=20=EC=BB=A8?= =?UTF-8?q?=ED=8A=B8=EB=A1=A4=EB=9F=AC=20API=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - member, admin으로 나누지 않고 하나로 통합 - security 설정 변경 - Controller 파일명 변경 refactor: 출석 컨트롤러 API명 변경 --- ...minController.java => AttendanceController.java} | 6 +++--- .../controller/AttendanceMemberController.java | 13 ------------- .../cotato/csquiz/common/config/SecurityConfig.java | 3 ++- 3 files changed, 5 insertions(+), 17 deletions(-) rename src/main/java/org/cotato/csquiz/api/attendance/controller/{AttendanceAdminController.java => AttendanceController.java} (94%) delete mode 100644 src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceMemberController.java diff --git a/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceAdminController.java b/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceController.java similarity index 94% rename from src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceAdminController.java rename to src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceController.java index 9b7461b7..87bdc004 100644 --- a/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceAdminController.java +++ b/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceController.java @@ -21,13 +21,13 @@ @Slf4j @RestController @RequiredArgsConstructor -@RequestMapping("/v2/api/attendance/admin") -public class AttendanceAdminController { +@RequestMapping("/v2/api/attendance") +public class AttendanceController { private final AttendanceAdminService attendanceAdminService; @Operation(summary = "출석 정보 변경 API") - @PatchMapping("/update") + @PatchMapping() public ResponseEntity updateAttendance(@RequestBody @Valid UpdateAttendanceRequest request) { attendanceAdminService.updateAttendance(request); return ResponseEntity.noContent().build(); diff --git a/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceMemberController.java b/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceMemberController.java deleted file mode 100644 index b7d98ae6..00000000 --- a/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceMemberController.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.cotato.csquiz.api.attendance.controller; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@Slf4j -@RestController -@RequiredArgsConstructor -@RequestMapping("/v2/api/attendance/member") -public class AttendanceMemberController { -} diff --git a/src/main/java/org/cotato/csquiz/common/config/SecurityConfig.java b/src/main/java/org/cotato/csquiz/common/config/SecurityConfig.java index cb1c2926..a473d026 100644 --- a/src/main/java/org/cotato/csquiz/common/config/SecurityConfig.java +++ b/src/main/java/org/cotato/csquiz/common/config/SecurityConfig.java @@ -78,7 +78,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers("/v1/api/session/cs-on").hasAnyRole("EDUCATION", "ADMIN") .requestMatchers(new AntPathRequestMatcher("/v1/api/session", "GET")).authenticated() .requestMatchers("/v1/api/session/**").hasAnyRole("ADMIN") - .requestMatchers("/v2/api/attendance/admin/**").hasAnyRole("ADMIN") + .requestMatchers("/v2/api/attendance/records").hasAnyRole("ADMIN") + .requestMatchers("/v2/api/attendance").hasAnyRole("ADMIN") .requestMatchers(new AntPathRequestMatcher("/v1/api/socket/token", "POST")) .hasAnyRole("MEMBER", "EDUCATION", "ADMIN") .requestMatchers("/v1/api/socket/**").hasAnyRole("EDUCATION", "ADMIN") From b95449407b4bde0853365683e2fc49f1a16602b6 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Thu, 1 Aug 2024 17:31:02 +0900 Subject: [PATCH 3/8] =?UTF-8?q?refactor:=20=EC=B6=9C=EC=84=9D=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20=EB=8B=A4=EB=A5=B8=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AdminService로 부터 출석기록 정보가 사용되는 부분을 RecordService로 분리 --- .../service/AttendanceAdminService.java | 20 +--------- .../service/AttendanceRecordService.java | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java index 3b1a0cf4..8affe004 100644 --- a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java +++ b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java @@ -6,11 +6,8 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.cotato.csquiz.api.admin.dto.MemberInfoResponse; import org.cotato.csquiz.api.attendance.dto.AttendanceRecordResponse; import org.cotato.csquiz.api.attendance.dto.UpdateAttendanceRequest; import org.cotato.csquiz.api.session.dto.AddSessionRequest.AttendanceDeadLine; @@ -18,10 +15,7 @@ import org.cotato.csquiz.common.error.exception.AppException; import org.cotato.csquiz.domain.attendance.embedded.Location; import org.cotato.csquiz.domain.attendance.entity.Attendance; -import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; -import org.cotato.csquiz.domain.attendance.repository.AttendanceRecordRepository; import org.cotato.csquiz.domain.attendance.repository.AttendanceRepository; -import org.cotato.csquiz.domain.auth.service.MemberService; import org.cotato.csquiz.domain.generation.entity.Session; import org.cotato.csquiz.domain.generation.repository.SessionRepository; import org.springframework.stereotype.Service; @@ -34,9 +28,8 @@ public class AttendanceAdminService { private final AttendanceRepository attendanceRepository; - private final AttendanceRecordRepository attendanceRecordRepository; + private final AttendanceRecordService attendanceRecordService; private final SessionRepository sessionRepository; - private final MemberService memberService; @Transactional public void addAttendance(Session session, LocalDate localDate, Location location, @@ -90,16 +83,7 @@ public List findAttendanceRecords(Long generationId, I List attendances = attendanceRepository.findAllBySessionIdsInQuery(sessionIds).stream() .toList(); - Map> recordsByMemberId = attendanceRecordRepository.findAllByAttendanceIdsInQuery( - attendances).stream() - .collect(Collectors.groupingBy(AttendanceRecord::getMemberId)); - - return recordsByMemberId.entrySet().stream() - .map(entry -> { - MemberInfoResponse memberInfo = memberService.findMemberInfo(entry.getKey()); - return AttendanceRecordResponse.of(memberInfo, entry.getValue(), attendances.size()); - }) - .toList(); + return attendanceRecordService.generateAttendanceResponses(attendances); } private boolean checkAttendanceTimeValid(LocalTime startTime, LocalTime endTime) { diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java new file mode 100644 index 00000000..f40be402 --- /dev/null +++ b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java @@ -0,0 +1,38 @@ +package org.cotato.csquiz.domain.attendance.service; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.cotato.csquiz.api.admin.dto.MemberInfoResponse; +import org.cotato.csquiz.api.attendance.dto.AttendanceRecordResponse; +import org.cotato.csquiz.domain.attendance.entity.Attendance; +import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; +import org.cotato.csquiz.domain.attendance.repository.AttendanceRecordRepository; +import org.cotato.csquiz.domain.auth.service.MemberService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Slf4j +public class AttendanceRecordService { + + private final AttendanceRecordRepository attendanceRecordRepository; + private final MemberService memberService; + + public List generateAttendanceResponses(List attendances){ + Map> recordsByMemberId = attendanceRecordRepository.findAllByAttendanceIdsInQuery( + attendances).stream() + .collect(Collectors.groupingBy(AttendanceRecord::getMemberId)); + + return recordsByMemberId.entrySet().stream() + .map(entry -> { + MemberInfoResponse memberInfo = memberService.findMemberInfo(entry.getKey()); + return AttendanceRecordResponse.of(memberInfo, entry.getValue(), attendances.size()); + }) + .toList(); + } +} From e2d12d26612381c39dbb1d9d488de7bb234ae201 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Thu, 1 Aug 2024 23:39:28 +0900 Subject: [PATCH 4/8] =?UTF-8?q?feat:=20=EC=B6=9C=EC=84=9D=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=EC=97=90=20=ED=95=B4=EB=8B=B9=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=EB=A9=A4=EB=B2=84=20=EC=A0=95=EB=B3=B4=20=EB=B0=9B=EB=8A=94=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 멤버 하나씩 정보를 만드는 방식에서 활동 중인 회원 목록을 가져와 Map으로 만들게 변경 feat: 출석 목록에 해당하는 멤버 정보 받는 방식 변경 - 기존 멤버 하나씩 정보를 만드는 방식에서 활동 중인 회원 목록을 가져와 Map으로 만들게 변경 --- .../dto/AttendanceRecordResponse.java | 23 +++++++++++++++---- .../service/AttendanceRecordService.java | 18 +++++++++++---- .../csquiz/domain/auth/enums/MemberRole.java | 6 +++++ .../domain/auth/service/MemberService.java | 7 ++++++ 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java index 30806620..933b4b5c 100644 --- a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java +++ b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java @@ -3,21 +3,22 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import org.cotato.csquiz.api.admin.dto.MemberInfoResponse; import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; import org.cotato.csquiz.domain.attendance.enums.AttendanceStatus; import org.cotato.csquiz.domain.attendance.enums.AttendanceType; +import org.cotato.csquiz.domain.auth.entity.Member; +import org.cotato.csquiz.domain.auth.enums.MemberRole; public record AttendanceRecordResponse( - MemberInfoResponse memberInfo, + AttendanceMemberInfo memberInfo, List attendanceInfos, AttendanceStatistic statistic ) { - public static AttendanceRecordResponse of(MemberInfoResponse memberInfo, List attendanceRecords, + public static AttendanceRecordResponse of(Member member, List attendanceRecords, Integer totalAttendance) { return new AttendanceRecordResponse( - memberInfo, + AttendanceMemberInfo.from(member), attendanceRecords.stream() .map(AttendanceInfoResponse::from) .toList(), @@ -25,6 +26,20 @@ public static AttendanceRecordResponse of(MemberInfoResponse memberInfo, List generateAttendanceResponses(List attendances){ + public List generateAttendanceResponses(List attendances) { Map> recordsByMemberId = attendanceRecordRepository.findAllByAttendanceIdsInQuery( attendances).stream() .collect(Collectors.groupingBy(AttendanceRecord::getMemberId)); + Map memberMap = memberService.findActiveMember().stream() + .collect(Collectors.toMap(Member::getId, member -> member)); + return recordsByMemberId.entrySet().stream() .map(entry -> { - MemberInfoResponse memberInfo = memberService.findMemberInfo(entry.getKey()); - return AttendanceRecordResponse.of(memberInfo, entry.getValue(), attendances.size()); + Member member = memberMap.get(entry.getKey()); + if (member == null) { + return null; + } + return AttendanceRecordResponse.of(member, entry.getValue(), + attendances.size()); }) + .filter(Objects::nonNull) .toList(); + } } diff --git a/src/main/java/org/cotato/csquiz/domain/auth/enums/MemberRole.java b/src/main/java/org/cotato/csquiz/domain/auth/enums/MemberRole.java index cef0d65e..b08d2aa0 100644 --- a/src/main/java/org/cotato/csquiz/domain/auth/enums/MemberRole.java +++ b/src/main/java/org/cotato/csquiz/domain/auth/enums/MemberRole.java @@ -1,5 +1,7 @@ package org.cotato.csquiz.domain.auth.enums; +import java.util.ArrayList; +import java.util.List; import org.cotato.csquiz.common.error.exception.AppException; import org.cotato.csquiz.common.error.ErrorCode; import java.util.Arrays; @@ -27,4 +29,8 @@ public static MemberRole fromKey(final String key) { .findFirst() .orElseThrow(() -> new AppException(ErrorCode.ENUM_NOT_RESOLVED)); } + + public static List activeMemberRoles() { + return List.of(ADMIN, EDUCATION, MEMBER); + } } diff --git a/src/main/java/org/cotato/csquiz/domain/auth/service/MemberService.java b/src/main/java/org/cotato/csquiz/domain/auth/service/MemberService.java index 0c1ad3aa..b097d985 100644 --- a/src/main/java/org/cotato/csquiz/domain/auth/service/MemberService.java +++ b/src/main/java/org/cotato/csquiz/domain/auth/service/MemberService.java @@ -1,6 +1,8 @@ package org.cotato.csquiz.domain.auth.service; import jakarta.persistence.EntityNotFoundException; +import java.util.ArrayList; +import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.cotato.csquiz.api.admin.dto.MemberInfoResponse; @@ -13,6 +15,7 @@ import org.cotato.csquiz.common.error.exception.AppException; import org.cotato.csquiz.common.error.exception.ImageException; import org.cotato.csquiz.domain.auth.entity.Member; +import org.cotato.csquiz.domain.auth.enums.MemberRole; import org.cotato.csquiz.domain.auth.repository.MemberRepository; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; @@ -125,4 +128,8 @@ public MemberInfo getMemberInfo(Long memberId) { .orElseThrow(() -> new EntityNotFoundException("해당 멤버를 찾을 수 없습니다.")); return MemberInfo.of(findMember, findBackFourNumber(findMember)); } + + public List findActiveMember() { + return memberRepository.findAllByRoleInQuery(MemberRole.activeMemberRoles()); + } } From fb02f4c06c462924fddd58f243d27c6ca5b513ba Mon Sep 17 00:00:00 2001 From: gikhoon Date: Fri, 2 Aug 2024 03:41:05 +0900 Subject: [PATCH 5/8] =?UTF-8?q?feat:=20=EC=B6=9C=EC=84=9D=EC=97=90=20?= =?UTF-8?q?=ED=95=B4=EB=8B=B9=ED=95=98=EB=8A=94=20=EC=B6=9C=EC=84=9D=20?= =?UTF-8?q?=EA=B8=B0=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/AttendanceController.java | 18 ++++++-- .../dto/AttendanceInfoResponse.java | 21 ---------- .../dto/AttendanceRecordResponse.java | 41 ++----------------- .../attendance/dto/AttendanceStatistic.java | 35 ++++++++++++++++ .../service/AttendanceAdminService.java | 10 ++++- .../service/AttendanceRecordService.java | 4 ++ .../domain/auth/service/MemberService.java | 5 +-- 7 files changed, 66 insertions(+), 68 deletions(-) delete mode 100644 src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceInfoResponse.java create mode 100644 src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceStatistic.java diff --git a/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceController.java b/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceController.java index 87bdc004..fb0780d6 100644 --- a/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceController.java +++ b/src/main/java/org/cotato/csquiz/api/attendance/controller/AttendanceController.java @@ -11,8 +11,10 @@ import org.cotato.csquiz.api.attendance.dto.UpdateAttendanceRequest; import org.cotato.csquiz.domain.attendance.service.AttendanceAdminService; import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -20,25 +22,33 @@ @Slf4j @RestController +@Validated @RequiredArgsConstructor -@RequestMapping("/v2/api/attendance") +@RequestMapping("/v2/api/attendances") public class AttendanceController { private final AttendanceAdminService attendanceAdminService; @Operation(summary = "출석 정보 변경 API") - @PatchMapping() + @PatchMapping public ResponseEntity updateAttendance(@RequestBody @Valid UpdateAttendanceRequest request) { attendanceAdminService.updateAttendance(request); return ResponseEntity.noContent().build(); } - @Operation(summary = "회원 출결사항 조회 API") + @Operation(summary = "회원 출결사항 기간 단위 조회 API") @GetMapping("/records") public ResponseEntity> findAttendanceRecords( @RequestParam(name = "generationId") Long generationId, - @RequestParam(name = "month", required = false) @Min(1) @Max(12) Integer month + @RequestParam(name = "month", required = false) @Min(value = 1, message = "달은 1 이상이어야 합니다.") @Max(value = 12, message = "달은 12 이하이어야 합니다") Integer month ) { return ResponseEntity.ok().body(attendanceAdminService.findAttendanceRecords(generationId, month)); } + + @Operation(summary = "회원 출결사항 출석 단위 조회 API") + @GetMapping("/{attendance-id}/records") + public ResponseEntity> findAttendanceRecordsByAttendance( + @PathVariable("attendance-id") Long attendanceId) { + return ResponseEntity.ok().body(attendanceAdminService.findAttendanceRecordsByAttendance(attendanceId)); + } } diff --git a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceInfoResponse.java b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceInfoResponse.java deleted file mode 100644 index 03ec9286..00000000 --- a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceInfoResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.cotato.csquiz.api.attendance.dto; - -import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; -import org.cotato.csquiz.domain.attendance.enums.AttendanceStatus; -import org.cotato.csquiz.domain.attendance.enums.AttendanceType; - -public record AttendanceInfoResponse( - Long attendanceId, - Long attendanceRecordId, - AttendanceType attendanceType, - AttendanceStatus attendanceStatus -) { - public static AttendanceInfoResponse from(AttendanceRecord attendanceRecord) { - return new AttendanceInfoResponse( - attendanceRecord.getAttendance().getId(), - attendanceRecord.getId(), - attendanceRecord.getAttendanceType(), - attendanceRecord.getAttendanceStatus() - ); - } -} diff --git a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java index 933b4b5c..7a6a439b 100644 --- a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java +++ b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java @@ -1,27 +1,19 @@ package org.cotato.csquiz.api.attendance.dto; import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; -import org.cotato.csquiz.domain.attendance.enums.AttendanceStatus; -import org.cotato.csquiz.domain.attendance.enums.AttendanceType; import org.cotato.csquiz.domain.auth.entity.Member; -import org.cotato.csquiz.domain.auth.enums.MemberRole; +import org.cotato.csquiz.domain.auth.enums.MemberPosition; public record AttendanceRecordResponse( AttendanceMemberInfo memberInfo, - List attendanceInfos, AttendanceStatistic statistic ) { public static AttendanceRecordResponse of(Member member, List attendanceRecords, Integer totalAttendance) { return new AttendanceRecordResponse( AttendanceMemberInfo.from(member), - attendanceRecords.stream() - .map(AttendanceInfoResponse::from) - .toList(), AttendanceStatistic.from(attendanceRecords, totalAttendance) ); } @@ -29,40 +21,13 @@ public static AttendanceRecordResponse of(Member member, List public record AttendanceMemberInfo( Long memberId, String memberName, - MemberRole role + MemberPosition position ){ static AttendanceMemberInfo from(Member member) { return new AttendanceMemberInfo( member.getId(), member.getName(), - member.getRole() - ); - } - } - - public record AttendanceStatistic( - Integer onLine, - Integer offLine, - Integer late, - Integer absent - ) { - public static AttendanceStatistic from(List attendanceRecords, Integer totalAttendance) { - Map> countByStatus = attendanceRecords.stream() - .collect(Collectors.groupingBy(AttendanceRecord::getAttendanceStatus)); - List presentRecords = countByStatus.getOrDefault(AttendanceStatus.PRESENT, List.of()); - - int onlineCount = (int) presentRecords.stream() - .filter(record -> AttendanceType.ONLINE == record.getAttendanceType()) - .count(); - int offLineCount = (int) presentRecords.stream() - .filter(record -> AttendanceType.OFFLINE == record.getAttendanceType()) - .count(); - - return new AttendanceStatistic( - onlineCount, - offLineCount, - countByStatus.getOrDefault(AttendanceStatus.LATE, List.of()).size(), - totalAttendance - attendanceRecords.size() + member.getPosition() ); } } diff --git a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceStatistic.java b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceStatistic.java new file mode 100644 index 00000000..5d78559d --- /dev/null +++ b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceStatistic.java @@ -0,0 +1,35 @@ +package org.cotato.csquiz.api.attendance.dto; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; +import org.cotato.csquiz.domain.attendance.enums.AttendanceStatus; +import org.cotato.csquiz.domain.attendance.enums.AttendanceType; + +public record AttendanceStatistic( + Integer onLine, + Integer offLine, + Integer late, + Integer absent +) { + public static AttendanceStatistic from(List attendanceRecords, Integer totalAttendance) { + Map> countByStatus = attendanceRecords.stream() + .collect(Collectors.groupingBy(AttendanceRecord::getAttendanceStatus)); + List presentRecords = countByStatus.getOrDefault(AttendanceStatus.PRESENT, List.of()); + + int onlineCount = (int) presentRecords.stream() + .filter(record -> AttendanceType.ONLINE == record.getAttendanceType()) + .count(); + int offLineCount = (int) presentRecords.stream() + .filter(record -> AttendanceType.OFFLINE == record.getAttendanceType()) + .count(); + + return new AttendanceStatistic( + onlineCount, + offLineCount, + countByStatus.getOrDefault(AttendanceStatus.LATE, List.of()).size(), + totalAttendance - attendanceRecords.size() + ); + } +} diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java index 8affe004..99490417 100644 --- a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java +++ b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java @@ -80,12 +80,18 @@ public List findAttendanceRecords(Long generationId, I .map(Session::getId) .toList(); - List attendances = attendanceRepository.findAllBySessionIdsInQuery(sessionIds).stream() - .toList(); + List attendances = attendanceRepository.findAllBySessionIdsInQuery(sessionIds); return attendanceRecordService.generateAttendanceResponses(attendances); } + public List findAttendanceRecordsByAttendance(Long attendanceId){ + Attendance attendance = attendanceRepository.findById(attendanceId) + .orElseThrow(() -> new EntityNotFoundException("해당 출석이 존재하지 않습니다")); + + return attendanceRecordService.generateAttendanceResponses(attendance); + } + private boolean checkAttendanceTimeValid(LocalTime startTime, LocalTime endTime) { return endTime == null || startTime == null; } diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java index aeb74067..222257a1 100644 --- a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java +++ b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java @@ -24,6 +24,10 @@ public class AttendanceRecordService { private final AttendanceRecordRepository attendanceRecordRepository; private final MemberService memberService; + public List generateAttendanceResponses(Attendance attendance) { + return generateAttendanceResponses(List.of(attendance)); + } + public List generateAttendanceResponses(List attendances) { Map> recordsByMemberId = attendanceRecordRepository.findAllByAttendanceIdsInQuery( attendances).stream() diff --git a/src/main/java/org/cotato/csquiz/domain/auth/service/MemberService.java b/src/main/java/org/cotato/csquiz/domain/auth/service/MemberService.java index b097d985..7c4d0fa2 100644 --- a/src/main/java/org/cotato/csquiz/domain/auth/service/MemberService.java +++ b/src/main/java/org/cotato/csquiz/domain/auth/service/MemberService.java @@ -1,7 +1,6 @@ package org.cotato.csquiz.domain.auth.service; import jakarta.persistence.EntityNotFoundException; -import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -15,7 +14,7 @@ import org.cotato.csquiz.common.error.exception.AppException; import org.cotato.csquiz.common.error.exception.ImageException; import org.cotato.csquiz.domain.auth.entity.Member; -import org.cotato.csquiz.domain.auth.enums.MemberRole; +import org.cotato.csquiz.domain.auth.enums.MemberRoleGroup; import org.cotato.csquiz.domain.auth.repository.MemberRepository; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; @@ -130,6 +129,6 @@ public MemberInfo getMemberInfo(Long memberId) { } public List findActiveMember() { - return memberRepository.findAllByRoleInQuery(MemberRole.activeMemberRoles()); + return memberRepository.findAllByRoleInQuery(MemberRoleGroup.ACTIVE_MEMBERS.getRoles()); } } From c102cc0edb38cdbe9148eb6ed04b72133188ef89 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Fri, 2 Aug 2024 16:16:26 +0900 Subject: [PATCH 6/8] =?UTF-8?q?feat:=20=EC=B6=9C=EC=84=9D=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/AttendanceRecordResponse.java | 7 ++---- .../attendance/dto/AttendanceStatistic.java | 2 +- .../service/AttendanceRecordService.java | 23 ++++++++----------- 3 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java index 7a6a439b..c5ee83f7 100644 --- a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java +++ b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceRecordResponse.java @@ -1,7 +1,5 @@ package org.cotato.csquiz.api.attendance.dto; -import java.util.List; -import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; import org.cotato.csquiz.domain.auth.entity.Member; import org.cotato.csquiz.domain.auth.enums.MemberPosition; @@ -10,11 +8,10 @@ public record AttendanceRecordResponse( AttendanceMemberInfo memberInfo, AttendanceStatistic statistic ) { - public static AttendanceRecordResponse of(Member member, List attendanceRecords, - Integer totalAttendance) { + public static AttendanceRecordResponse of(Member member, AttendanceStatistic attendanceStatistic) { return new AttendanceRecordResponse( AttendanceMemberInfo.from(member), - AttendanceStatistic.from(attendanceRecords, totalAttendance) + attendanceStatistic ); } diff --git a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceStatistic.java b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceStatistic.java index 5d78559d..822b91c5 100644 --- a/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceStatistic.java +++ b/src/main/java/org/cotato/csquiz/api/attendance/dto/AttendanceStatistic.java @@ -13,7 +13,7 @@ public record AttendanceStatistic( Integer late, Integer absent ) { - public static AttendanceStatistic from(List attendanceRecords, Integer totalAttendance) { + public static AttendanceStatistic of(List attendanceRecords, Integer totalAttendance) { Map> countByStatus = attendanceRecords.stream() .collect(Collectors.groupingBy(AttendanceRecord::getAttendanceStatus)); List presentRecords = countByStatus.getOrDefault(AttendanceStatus.PRESENT, List.of()); diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java index 222257a1..3444bb82 100644 --- a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java +++ b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java @@ -2,11 +2,11 @@ import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.cotato.csquiz.api.attendance.dto.AttendanceRecordResponse; +import org.cotato.csquiz.api.attendance.dto.AttendanceStatistic; import org.cotato.csquiz.domain.attendance.entity.Attendance; import org.cotato.csquiz.domain.attendance.entity.AttendanceRecord; import org.cotato.csquiz.domain.attendance.repository.AttendanceRecordRepository; @@ -29,24 +29,19 @@ public List generateAttendanceResponses(Attendance att } public List generateAttendanceResponses(List attendances) { - Map> recordsByMemberId = attendanceRecordRepository.findAllByAttendanceIdsInQuery( - attendances).stream() + List records = attendanceRecordRepository.findAllByAttendanceIdsInQuery( + attendances); + + Map> recordsByMemberId = records.stream() .collect(Collectors.groupingBy(AttendanceRecord::getMemberId)); Map memberMap = memberService.findActiveMember().stream() .collect(Collectors.toMap(Member::getId, member -> member)); - return recordsByMemberId.entrySet().stream() - .map(entry -> { - Member member = memberMap.get(entry.getKey()); - if (member == null) { - return null; - } - return AttendanceRecordResponse.of(member, entry.getValue(), - attendances.size()); - }) - .filter(Objects::nonNull) + return recordsByMemberId.keySet().stream() + .filter(memberMap::containsKey) + .map(memberId -> AttendanceRecordResponse.of(memberMap.get(memberId), + AttendanceStatistic.of(recordsByMemberId.get(memberId), attendances.size()))) .toList(); - } } From ec7d59de800091d34f28ab07c159b914ed27eb96 Mon Sep 17 00:00:00 2001 From: gikhoon Date: Fri, 2 Aug 2024 16:42:34 +0900 Subject: [PATCH 7/8] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=A9=94=EC=86=8C=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../attendance/service/AttendanceAdminService.java | 2 +- .../attendance/service/AttendanceRecordService.java | 4 ---- .../cotato/csquiz/domain/auth/enums/MemberRole.java | 10 ++-------- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java index 99490417..74d71939 100644 --- a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java +++ b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java @@ -89,7 +89,7 @@ public List findAttendanceRecordsByAttendance(Long att Attendance attendance = attendanceRepository.findById(attendanceId) .orElseThrow(() -> new EntityNotFoundException("해당 출석이 존재하지 않습니다")); - return attendanceRecordService.generateAttendanceResponses(attendance); + return attendanceRecordService.generateAttendanceResponses(List.of(attendance)); } private boolean checkAttendanceTimeValid(LocalTime startTime, LocalTime endTime) { diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java index 3444bb82..af8688fc 100644 --- a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java +++ b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceRecordService.java @@ -24,10 +24,6 @@ public class AttendanceRecordService { private final AttendanceRecordRepository attendanceRecordRepository; private final MemberService memberService; - public List generateAttendanceResponses(Attendance attendance) { - return generateAttendanceResponses(List.of(attendance)); - } - public List generateAttendanceResponses(List attendances) { List records = attendanceRecordRepository.findAllByAttendanceIdsInQuery( attendances); diff --git a/src/main/java/org/cotato/csquiz/domain/auth/enums/MemberRole.java b/src/main/java/org/cotato/csquiz/domain/auth/enums/MemberRole.java index b08d2aa0..f7da7193 100644 --- a/src/main/java/org/cotato/csquiz/domain/auth/enums/MemberRole.java +++ b/src/main/java/org/cotato/csquiz/domain/auth/enums/MemberRole.java @@ -1,11 +1,9 @@ package org.cotato.csquiz.domain.auth.enums; -import java.util.ArrayList; -import java.util.List; -import org.cotato.csquiz.common.error.exception.AppException; -import org.cotato.csquiz.common.error.ErrorCode; import java.util.Arrays; import lombok.Getter; +import org.cotato.csquiz.common.error.ErrorCode; +import org.cotato.csquiz.common.error.exception.AppException; @Getter public enum MemberRole { @@ -29,8 +27,4 @@ public static MemberRole fromKey(final String key) { .findFirst() .orElseThrow(() -> new AppException(ErrorCode.ENUM_NOT_RESOLVED)); } - - public static List activeMemberRoles() { - return List.of(ADMIN, EDUCATION, MEMBER); - } } From ae74a321ef448713f4c75e00517659e2f4c442b1 Mon Sep 17 00:00:00 2001 From: youth Date: Fri, 2 Aug 2024 17:34:37 +0900 Subject: [PATCH 8/8] =?UTF-8?q?fix:=20merge=20=EA=B3=BC=EC=A0=95=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EB=B0=9C=EC=83=9D=ED=95=9C=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=95=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/attendance/entity/Attendance.java | 2 -- .../service/AttendanceAdminService.java | 7 ++++--- .../generation/service/SessionService.java | 17 ++++++++--------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/entity/Attendance.java b/src/main/java/org/cotato/csquiz/domain/attendance/entity/Attendance.java index d32d9ae0..9bade91f 100644 --- a/src/main/java/org/cotato/csquiz/domain/attendance/entity/Attendance.java +++ b/src/main/java/org/cotato/csquiz/domain/attendance/entity/Attendance.java @@ -5,13 +5,11 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import java.time.LocalDate; import java.time.LocalDateTime; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import org.cotato.csquiz.api.attendance.dto.UpdateAttendanceRequest.AttendanceDeadLine; import org.cotato.csquiz.common.entity.BaseTimeEntity; import org.cotato.csquiz.domain.attendance.embedded.Location; import org.cotato.csquiz.domain.generation.entity.Session; diff --git a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java index 257249b3..b7ab4f8b 100644 --- a/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java +++ b/src/main/java/org/cotato/csquiz/domain/attendance/service/AttendanceAdminService.java @@ -32,8 +32,7 @@ public class AttendanceAdminService { private final SessionRepository sessionRepository; @Transactional - public void addAttendance(Session session, LocalDate localDate, Location location, - AttendanceDeadLine attendanceDeadLine) { + public void addAttendance(Session session, Location location, AttendanceDeadLineDto attendanceDeadLine) { Attendance attendance = Attendance.builder() .session(session) @@ -57,7 +56,9 @@ public void updateAttendance(UpdateAttendanceRequest request) { throw new AppException(ErrorCode.SESSION_DATE_NOT_FOUND); } - attendance.updateDeadLine(attendanceSession.getSessionDate(), request.attendanceDeadLine()); + attendance.updateDeadLine(LocalDateTime.of(attendanceSession.getSessionDate(), request.attendanceDeadLine() + .startTime()), LocalDateTime.of(attendanceSession.getSessionDate(), request.attendanceDeadLine() + .endTime())); attendance.updateLocation(request.location()); } diff --git a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java index 0a819d74..33f30f25 100644 --- a/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java +++ b/src/main/java/org/cotato/csquiz/domain/generation/service/SessionService.java @@ -11,31 +11,30 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.cotato.csquiz.api.session.dto.AddSessionImageResponse; -import org.cotato.csquiz.api.session.dto.DeleteSessionImageRequest; -import org.cotato.csquiz.api.session.dto.UpdateSessionImageOrderInfoRequest; -import org.cotato.csquiz.api.session.dto.UpdateSessionImageOrderRequest; import org.cotato.csquiz.api.session.dto.AddSessionImageRequest; +import org.cotato.csquiz.api.session.dto.AddSessionImageResponse; import org.cotato.csquiz.api.session.dto.AddSessionRequest; import org.cotato.csquiz.api.session.dto.AddSessionResponse; import org.cotato.csquiz.api.session.dto.CsEducationOnSessionNumberResponse; +import org.cotato.csquiz.api.session.dto.DeleteSessionImageRequest; import org.cotato.csquiz.api.session.dto.SessionListResponse; +import org.cotato.csquiz.api.session.dto.UpdateSessionImageOrderInfoRequest; +import org.cotato.csquiz.api.session.dto.UpdateSessionImageOrderRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionNumberRequest; import org.cotato.csquiz.api.session.dto.UpdateSessionRequest; +import org.cotato.csquiz.common.S3.S3Uploader; import org.cotato.csquiz.common.entity.S3Info; import org.cotato.csquiz.common.error.ErrorCode; import org.cotato.csquiz.common.error.exception.AppException; -import org.cotato.csquiz.domain.attendance.entity.Attendance; +import org.cotato.csquiz.common.error.exception.ImageException; import org.cotato.csquiz.domain.attendance.service.AttendanceAdminService; import org.cotato.csquiz.domain.education.entity.Education; import org.cotato.csquiz.domain.education.service.EducationService; import org.cotato.csquiz.domain.generation.embedded.SessionContents; -import org.cotato.csquiz.domain.generation.entity.SessionImage; -import org.cotato.csquiz.domain.generation.enums.CSEducation; import org.cotato.csquiz.domain.generation.entity.Generation; import org.cotato.csquiz.domain.generation.entity.Session; -import org.cotato.csquiz.common.error.exception.ImageException; -import org.cotato.csquiz.common.S3.S3Uploader; +import org.cotato.csquiz.domain.generation.entity.SessionImage; +import org.cotato.csquiz.domain.generation.enums.CSEducation; import org.cotato.csquiz.domain.generation.repository.GenerationRepository; import org.cotato.csquiz.domain.generation.repository.SessionImageRepository; import org.cotato.csquiz.domain.generation.repository.SessionRepository;