Skip to content

Commit

Permalink
Merge branch 'develop' into feature/784-get-my-complete-study-history
Browse files Browse the repository at this point in the history
  • Loading branch information
kckc0608 committed Oct 10, 2024
2 parents 6d41063 + b707e4c commit 65c64c4
Show file tree
Hide file tree
Showing 18 changed files with 278 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

Expand All @@ -35,10 +37,10 @@ public ResponseEntity<List<StudyResponse>> getStudiesInCharge() {
return ResponseEntity.ok(response);
}

@Operation(summary = "스터디 수강생 명단 조회", description = "해당 스터디의 수강생 명단을 조회합니다")
@Operation(summary = "스터디 수강생 관리", description = "해당 스터디의 수강생을 관리합니다")
@GetMapping("/{studyId}/students")
public ResponseEntity<List<StudyStudentResponse>> getStudyStudents(@PathVariable Long studyId) {
List<StudyStudentResponse> response = mentorStudyService.getStudyStudents(studyId);
public ResponseEntity<Page<StudyStudentResponse>> getStudyStudents(@PathVariable Long studyId, Pageable pageable) {
Page<StudyStudentResponse> response = mentorStudyService.getStudyStudents(studyId, pageable);
return ResponseEntity.ok(response);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package com.gdschongik.gdsc.domain.study.application;

import static com.gdschongik.gdsc.global.exception.ErrorCode.STUDY_NOT_FOUND;
import static com.gdschongik.gdsc.global.exception.ErrorCode.*;
import static java.util.stream.Collectors.*;

import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.dao.AssignmentHistoryRepository;
import com.gdschongik.gdsc.domain.study.dao.AttendanceRepository;
import com.gdschongik.gdsc.domain.study.dao.StudyAchievementRepository;
import com.gdschongik.gdsc.domain.study.dao.StudyAnnouncementRepository;
import com.gdschongik.gdsc.domain.study.dao.StudyDetailRepository;
import com.gdschongik.gdsc.domain.study.dao.StudyHistoryRepository;
Expand All @@ -17,14 +21,19 @@
import com.gdschongik.gdsc.domain.study.dto.request.StudyUpdateRequest;
import com.gdschongik.gdsc.domain.study.dto.response.StudyResponse;
import com.gdschongik.gdsc.domain.study.dto.response.StudyStudentResponse;
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.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -34,12 +43,15 @@
public class MentorStudyService {

private final MemberUtil memberUtil;
private final StudyValidator studyValidator;
private final StudyDetailValidator studyDetailValidator;
private final StudyRepository studyRepository;
private final StudyAnnouncementRepository studyAnnouncementRepository;
private final StudyHistoryRepository studyHistoryRepository;
private final StudyValidator studyValidator;
private final StudyDetailRepository studyDetailRepository;
private final StudyDetailValidator studyDetailValidator;
private final StudyAchievementRepository studyAchievementRepository;
private final AttendanceRepository attendanceRepository;
private final AssignmentHistoryRepository assignmentHistoryRepository;

@Transactional(readOnly = true)
public List<StudyResponse> getStudiesInCharge() {
Expand All @@ -49,15 +61,67 @@ public List<StudyResponse> getStudiesInCharge() {
}

@Transactional(readOnly = true)
public List<StudyStudentResponse> getStudyStudents(Long studyId) {
public Page<StudyStudentResponse> getStudyStudents(Long studyId, Pageable pageable) {
Member currentMember = memberUtil.getCurrentMember();
Study study =
studyRepository.findById(studyId).orElseThrow(() -> new CustomException(ErrorCode.STUDY_NOT_FOUND));

Study study = studyRepository.findById(studyId).orElseThrow(() -> new CustomException(STUDY_NOT_FOUND));
studyValidator.validateStudyMentor(currentMember, study);
List<StudyHistory> studyHistories = studyHistoryRepository.findByStudyId(studyId);

return studyHistories.stream().map(StudyStudentResponse::from).toList();
List<StudyDetail> studyDetails = studyDetailRepository.findAllByStudyId(studyId);
Page<StudyHistory> studyHistories = studyHistoryRepository.findByStudyId(studyId, pageable);
List<Long> studentIds = studyHistories.getContent().stream()
.map(studyHistory -> studyHistory.getStudent().getId())
.toList();
List<StudyAchievement> studyAchievements =
studyAchievementRepository.findByStudyIdAndMemberIds(studyId, studentIds);
List<Attendance> attendances = attendanceRepository.findByStudyIdAndMemberIds(studyId, studentIds);
List<AssignmentHistory> assignmentHistories =
assignmentHistoryRepository.findByStudyIdAndMemberIds(studyId, studentIds);

// StudyAchievement, Attendance, AssignmentHistory에 대해 Member의 id를 key로 하는 Map 생성
Map<Long, List<StudyAchievement>> studyAchievementMap = studyAchievements.stream()
.collect(groupingBy(
studyAchievement -> studyAchievement.getStudent().getId()));
Map<Long, List<Attendance>> attendanceMap = attendances.stream()
.collect(groupingBy(attendance -> attendance.getStudent().getId()));
Map<Long, List<AssignmentHistory>> assignmentHistoryMap = assignmentHistories.stream()
.collect(groupingBy(
assignmentHistory -> assignmentHistory.getMember().getId()));

List<StudyStudentResponse> response = new ArrayList<>();
studyHistories.getContent().forEach(studyHistory -> {
List<StudyAchievement> currentStudyAchievements =
studyAchievementMap.getOrDefault(studyHistory.getStudent().getId(), new ArrayList<>());
List<Attendance> currentAttendances =
attendanceMap.getOrDefault(studyHistory.getStudent().getId(), new ArrayList<>());
List<AssignmentHistory> currentAssignmentHistories =
assignmentHistoryMap.getOrDefault(studyHistory.getStudent().getId(), new ArrayList<>());

List<StudyTodoResponse> studyTodos = new ArrayList<>();
studyDetails.forEach(studyDetail -> {
studyTodos.add(StudyTodoResponse.createAttendanceType(
studyDetail, LocalDate.now(), isAttended(currentAttendances, studyDetail)));
studyTodos.add(StudyTodoResponse.createAssignmentType(
studyDetail, getSubmittedAssignment(currentAssignmentHistories, studyDetail)));
});

response.add(StudyStudentResponse.of(studyHistory, currentStudyAchievements, studyTodos));
});

return new PageImpl<>(response, pageable, studyHistories.getTotalElements());
}

private boolean isAttended(List<Attendance> attendances, StudyDetail studyDetail) {
return attendances.stream()
.anyMatch(attendance -> attendance.getStudyDetail().getId().equals(studyDetail.getId()));
}

private AssignmentHistory getSubmittedAssignment(
List<AssignmentHistory> assignmentHistories, StudyDetail studyDetail) {
return assignmentHistories.stream()
.filter(assignmentHistory ->
assignmentHistory.getStudyDetail().getId().equals(studyDetail.getId()))
.findFirst()
.orElse(null);
}

@Transactional
Expand Down Expand Up @@ -109,12 +173,12 @@ public void updateStudy(Long studyId, StudyUpdateRequest request) {

List<StudyDetail> studyDetails = studyDetailRepository.findAllByStudyIdOrderByWeekAsc(studyId);
// StudyDetail ID를 추출하여 Set으로 저장
Set<Long> studyDetailIds = studyDetails.stream().map(StudyDetail::getId).collect(Collectors.toSet());
Set<Long> studyDetailIds = studyDetails.stream().map(StudyDetail::getId).collect(toSet());

// 요청된 StudyCurriculumCreateRequest의 StudyDetail ID를 추출하여 Set으로 저장
Set<Long> requestIds = request.studyCurriculums().stream()
.map(StudyCurriculumCreateRequest::studyDetailId)
.collect(Collectors.toSet());
.collect(toSet());

studyDetailValidator.validateUpdateStudyDetail(studyDetailIds, requestIds);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ public interface AssignmentHistoryCustomRepository {

List<AssignmentHistory> findAssignmentHistoriesByStudentAndStudyId(Member member, Long studyId);

List<AssignmentHistory> findByStudyIdAndMemberIds(Long studyId, List<Long> memberIds);

void deleteByStudyIdAndMemberId(Long studyId, Long memberId);
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
package com.gdschongik.gdsc.domain.study.dao;

import static com.gdschongik.gdsc.domain.study.domain.AssignmentSubmissionStatus.*;
import static com.gdschongik.gdsc.domain.study.domain.QAssignmentHistory.*;
import static com.gdschongik.gdsc.domain.study.domain.QStudyDetail.studyDetail;

import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.domain.AssignmentHistory;
import com.gdschongik.gdsc.domain.study.domain.Study;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class AssignmentHistoryCustomRepositoryImpl implements AssignmentHistoryCustomRepository {
public class AssignmentHistoryCustomRepositoryImpl
implements AssignmentHistoryCustomRepository, AssignmentHistoryQueryMethod {

private final JPAQueryFactory queryFactory;

Expand All @@ -28,18 +27,6 @@ public boolean existsSubmittedAssignmentByMemberAndStudy(Member member, Study st
return fetchOne != null;
}

private BooleanExpression eqMember(Member member) {
return member == null ? null : assignmentHistory.member.eq(member);
}

private BooleanExpression eqStudy(Study study) {
return study == null ? null : assignmentHistory.studyDetail.study.eq(study);
}

private BooleanExpression isSubmitted() {
return assignmentHistory.submissionStatus.in(FAILURE, SUCCESS);
}

@Override
public List<AssignmentHistory> findAssignmentHistoriesByStudentAndStudyId(Member currentMember, Long studyId) {
return queryFactory
Expand All @@ -50,10 +37,6 @@ public List<AssignmentHistory> findAssignmentHistoriesByStudentAndStudyId(Member
.fetch();
}

private BooleanExpression eqStudyId(Long studyId) {
return studyId != null ? studyDetail.study.id.eq(studyId) : null;
}

@Override
public void deleteByStudyIdAndMemberId(Long studyId, Long memberId) {
queryFactory
Expand All @@ -62,7 +45,13 @@ public void deleteByStudyIdAndMemberId(Long studyId, Long memberId) {
.execute();
}

private BooleanExpression eqMemberId(Long memberId) {
return memberId != null ? assignmentHistory.member.id.eq(memberId) : null;
@Override
public List<AssignmentHistory> findByStudyIdAndMemberIds(Long studyId, List<Long> memberIds) {
return queryFactory
.selectFrom(assignmentHistory)
.innerJoin(assignmentHistory.studyDetail, studyDetail)
.fetchJoin()
.where(assignmentHistory.member.id.in(memberIds), eqStudyId(studyId))
.fetch();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.gdschongik.gdsc.domain.study.dao;

import static com.gdschongik.gdsc.domain.study.domain.AssignmentSubmissionStatus.*;
import static com.gdschongik.gdsc.domain.study.domain.QAssignmentHistory.*;
import static com.gdschongik.gdsc.domain.study.domain.QStudyDetail.*;

import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.domain.Study;
import com.querydsl.core.types.dsl.BooleanExpression;

public interface AssignmentHistoryQueryMethod {
default BooleanExpression eqMember(Member member) {
return member == null ? null : assignmentHistory.member.eq(member);
}

default BooleanExpression eqStudy(Study study) {
return study == null ? null : assignmentHistory.studyDetail.study.eq(study);
}

default BooleanExpression isSubmitted() {
return assignmentHistory.submissionStatus.in(FAILURE, SUCCESS);
}

default BooleanExpression eqStudyId(Long studyId) {
return studyId != null ? studyDetail.study.id.eq(studyId) : null;
}

default BooleanExpression eqMemberId(Long memberId) {
return memberId != null ? assignmentHistory.member.id.eq(memberId) : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@

public interface AssignmentHistoryRepository
extends JpaRepository<AssignmentHistory, Long>, AssignmentHistoryCustomRepository {
public Optional<AssignmentHistory> findByMemberAndStudyDetail(Member member, StudyDetail studyDetail);
Optional<AssignmentHistory> findByMemberAndStudyDetail(Member member, StudyDetail studyDetail);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,7 @@
public interface AttendanceCustomRepository {
List<Attendance> findByMemberAndStudyId(Member member, Long studyId);

List<Attendance> findByStudyIdAndMemberIds(Long studyId, List<Long> memberIds);

void deleteByStudyIdAndMemberId(Long studyId, Long memberId);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.gdschongik.gdsc.domain.study.dao;

import static com.gdschongik.gdsc.domain.member.domain.QMember.member;
import static com.gdschongik.gdsc.domain.study.domain.QAttendance.attendance;
import static com.gdschongik.gdsc.domain.study.domain.QStudyDetail.studyDetail;

Expand All @@ -26,6 +25,16 @@ public List<Attendance> findByMemberAndStudyId(Member member, Long studyId) {
.fetch();
}

@Override
public List<Attendance> findByStudyIdAndMemberIds(Long studyId, List<Long> memberIds) {
return queryFactory
.selectFrom(attendance)
.innerJoin(attendance.studyDetail, studyDetail)
.fetchJoin()
.where(attendance.student.id.in(memberIds), eqStudyId(studyId))
.fetch();
}

private BooleanExpression eqMemberId(Long memberId) {
return memberId != null ? attendance.student.id.eq(memberId) : null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.gdschongik.gdsc.domain.study.dao;

import com.gdschongik.gdsc.domain.study.domain.StudyAchievement;
import java.util.List;

public interface StudyAchievementCustomRepository {
List<StudyAchievement> findByStudyIdAndMemberIds(Long studyId, List<Long> memberIds);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.gdschongik.gdsc.domain.study.dao;

import static com.gdschongik.gdsc.domain.study.domain.QStudyAchievement.*;

import com.gdschongik.gdsc.domain.study.domain.StudyAchievement;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class StudyAchievementCustomRepositoryImpl implements StudyAchievementCustomRepository {

private final JPAQueryFactory queryFactory;

@Override
public List<StudyAchievement> findByStudyIdAndMemberIds(Long studyId, List<Long> memberIds) {
return queryFactory
.selectFrom(studyAchievement)
.where(eqStudyId(studyId), studyAchievement.student.id.in(memberIds))
.fetch();
}

private BooleanExpression eqStudyId(Long studyId) {
return studyId != null ? studyAchievement.study.id.eq(studyId) : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudyAchievementRepository extends JpaRepository<StudyAchievement, Long> {
public interface StudyAchievementRepository
extends JpaRepository<StudyAchievement, Long>, StudyAchievementCustomRepository {

List<StudyAchievement> findAllByStudent(Member student);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@
import com.gdschongik.gdsc.domain.study.domain.StudyHistory;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudyHistoryRepository extends JpaRepository<StudyHistory, Long> {

List<StudyHistory> findByStudyId(Long studyId);

List<StudyHistory> findAllByStudent(Member member);

Optional<StudyHistory> findByStudentAndStudy(Member member, Study study);

boolean existsByStudentAndStudy(Member member, Study study);

Optional<StudyHistory> findByStudentAndStudyId(Member member, Long studyId);

Page<StudyHistory> findByStudyId(Long studyId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,8 @@ public static Curriculum generateCurriculum(
public boolean isOpen() {
return status == StudyStatus.OPEN;
}

public boolean isCancelled() {
return status == StudyStatus.CANCELLED;
}
}
Loading

0 comments on commit 65c64c4

Please sign in to comment.