diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyDetailController.java b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyDetailController.java index f122077f8..c153140b1 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyDetailController.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyDetailController.java @@ -3,6 +3,7 @@ import com.gdschongik.gdsc.domain.study.application.StudentStudyDetailService; import com.gdschongik.gdsc.domain.study.dto.response.AssignmentDashboardResponse; import com.gdschongik.gdsc.domain.study.dto.response.StudyStudentSessionResponse; +import com.gdschongik.gdsc.domain.study.dto.response.StudyTodoResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import java.util.List; @@ -29,6 +30,13 @@ public ResponseEntity getSubmittableAssignments( return ResponseEntity.ok(response); } + @Operation(summary = "내 할일 리스트 조회", description = "해당 스터디의 내 할일 리스트를 조회합니다") + @GetMapping("/todo") + public ResponseEntity> getStudyTodoList(@RequestParam(name = "studyId") Long studyId) { + List response = studentStudyDetailService.getStudyTodoList(studyId); + return ResponseEntity.ok(response); + } + // TODO 스터디 세션 워딩을 커리큘럼으로 변경해야함 @Operation(summary = "스터디 커리큘럼 조회", description = "해당 스터디의 커리큘럼들을 조회합니다.") @GetMapping("/sessions") diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyDetailService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyDetailService.java index 70c73a9e2..652b397fc 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyDetailService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyDetailService.java @@ -12,10 +12,13 @@ import com.gdschongik.gdsc.domain.study.dto.response.AssignmentDashboardResponse; import com.gdschongik.gdsc.domain.study.dto.response.AssignmentSubmittableDto; import com.gdschongik.gdsc.domain.study.dto.response.StudyStudentSessionResponse; +import com.gdschongik.gdsc.domain.study.dto.response.StudyTodoResponse; import com.gdschongik.gdsc.global.exception.CustomException; import com.gdschongik.gdsc.global.exception.ErrorCode; import com.gdschongik.gdsc.global.util.MemberUtil; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -54,6 +57,31 @@ studyDetail, getSubmittedAssignment(assignmentHistories, studyDetail))) } @Transactional(readOnly = true) + public List getStudyTodoList(Long studyId) { + Member member = memberUtil.getCurrentMember(); + final List studyDetails = studyDetailRepository.findAllByStudyIdOrderByWeekAsc(studyId); + final List assignmentHistories = + assignmentHistoryRepository.findAssignmentHistoriesByStudentAndStudy(member, studyId); + final List attendances = attendanceRepository.findByMemberAndStudyId(member, studyId); + + LocalDate now = LocalDate.now(); + List response = new ArrayList<>(); + // 출석체크 정보 (개설 상태이고, 오늘이 출석체크날짜인 것) + studyDetails.stream() + .filter(studyDetail -> studyDetail.getSession().isOpen() + && studyDetail.getAttendanceDay().equals(now)) + .forEach(studyDetail -> response.add(StudyTodoResponse.createAttendanceType( + studyDetail, now, isAttended(attendances, studyDetail)))); + + // 과제 정보 (오늘이 과제 제출 기간에 포함된 과제 정보) + studyDetails.stream() + .filter(studyDetail -> studyDetail.getAssignment().isOpen() + && studyDetail.getAssignment().isDeadlineRemaining()) + .forEach(studyDetail -> response.add(StudyTodoResponse.createAssignmentType( + studyDetail, getSubmittedAssignment(assignmentHistories, studyDetail)))); + return response; + } + public List getStudySessions(Long studyId) { Member member = memberUtil.getCurrentMember(); final List studyDetails = studyDetailRepository.findAllByStudyIdOrderByWeekAsc(studyId); diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetail.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetail.java index fd857f50c..be1a4a174 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetail.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyDetail.java @@ -8,6 +8,7 @@ import com.gdschongik.gdsc.domain.study.domain.vo.Session; import com.gdschongik.gdsc.global.exception.CustomException; import jakarta.persistence.*; +import java.time.DayOfWeek; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; @@ -97,10 +98,25 @@ public boolean isAssignmentDeadlineRemaining() { // 스터디 시작일자 + 현재 주차 * 7 + (스터디 요일 - 스터디 기간 시작 요일) public LocalDate getAttendanceDay() { - return study.getStartDate() - .plusDays(week * 7 - + study.getDayOfWeek().getValue() - - study.getStartDate().getDayOfWeek().getValue()); + // 스터디 시작일자 + LocalDate startDate = study.getStartDate(); + + // 스터디 요일 + DayOfWeek studyDayOfWeek = study.getDayOfWeek(); + + // 스터디 기간 시작 요일 + DayOfWeek startDayOfWeek = startDate.getDayOfWeek(); + + // 스터디 요일이 스터디 기간 시작 요일보다 앞서면, 다음 주로 넘어가게 처리 + Long daysDifference = Long.valueOf(studyDayOfWeek.getValue() - startDayOfWeek.getValue()); + if (daysDifference < 0) { + daysDifference += 7; + } + + // 현재 주차에 따른 일수 계산 + Long daysToAdd = (week - 1) * 7 + daysDifference; + + return startDate.plusDays(daysToAdd); } public void updateSession( diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/vo/Session.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/vo/Session.java index 1b26ff63b..07a2282c0 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/domain/vo/Session.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/vo/Session.java @@ -55,4 +55,9 @@ public static Session generateSession( .status(status) .build(); } + + // 데이터 전달 로직 + public boolean isOpen() { + return status == StudyStatus.OPEN; + } } diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/dto/response/StudyTodoResponse.java b/src/main/java/com/gdschongik/gdsc/domain/study/dto/response/StudyTodoResponse.java new file mode 100644 index 000000000..7399b6181 --- /dev/null +++ b/src/main/java/com/gdschongik/gdsc/domain/study/dto/response/StudyTodoResponse.java @@ -0,0 +1,53 @@ +package com.gdschongik.gdsc.domain.study.dto.response; + +import static com.gdschongik.gdsc.domain.study.dto.response.StudyTodoResponse.StudyTodoType.ASSIGNMENT; +import static com.gdschongik.gdsc.domain.study.dto.response.StudyTodoResponse.StudyTodoType.ATTENDANCE; + +import com.gdschongik.gdsc.domain.study.domain.AssignmentHistory; +import com.gdschongik.gdsc.domain.study.domain.StudyDetail; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDate; +import java.time.LocalDateTime; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +public record StudyTodoResponse( + Long studyDetailId, + @Schema(description = "현 주차수") Long week, + @Schema(description = "할일 타입") StudyTodoType todoType, + @Schema(description = "마감 시각") LocalDateTime deadLine, + @Schema(description = "출석 상태 (출석타입일 때만 사용)") AttendanceStatusResponse attendanceStatus, + @Schema(description = "과제 제목 (과제타입일 때만 사용)") String assignmentTitle, + @Schema(description = "과제 제출 상태 (과제타입일 때만 사용)") AssignmentSubmissionStatusResponse assignmentSubmissionStatus) { + + public static StudyTodoResponse createAttendanceType(StudyDetail studyDetail, LocalDate now, boolean isAttended) { + return new StudyTodoResponse( + studyDetail.getId(), + studyDetail.getWeek(), + ATTENDANCE, + studyDetail.getAttendanceDay().atTime(23, 59, 59), + AttendanceStatusResponse.of(studyDetail, now, isAttended), + null, + null); + } + + public static StudyTodoResponse createAssignmentType(StudyDetail studyDetail, AssignmentHistory assignmentHistory) { + return new StudyTodoResponse( + studyDetail.getId(), + studyDetail.getWeek(), + ASSIGNMENT, + studyDetail.getAssignment().getDeadline(), + null, + studyDetail.getAssignment().getTitle(), + AssignmentSubmissionStatusResponse.from(assignmentHistory)); + } + + @Getter + @RequiredArgsConstructor + public enum StudyTodoType { + ATTENDANCE("출석"), + ASSIGNMENT("과제"); + + private final String value; + } +}