Skip to content

Commit

Permalink
feat: 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
seongjae6751 committed Dec 28, 2024
1 parent dea52f0 commit 9aa6ea4
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import static in.koreatech.koin.domain.user.model.UserType.STUDENT;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import in.koreatech.koin.domain.graduation.dto.GraduationCourseCalculationResponse;
import in.koreatech.koin.domain.graduation.service.GraduationService;
import in.koreatech.koin.global.auth.Auth;
import lombok.RequiredArgsConstructor;
Expand All @@ -23,4 +25,11 @@ public ResponseEntity<Void> createStudentCourseCalculation(
graduationService.createStudentCourseCalculation(userId);
return ResponseEntity.ok().build();
}

@GetMapping("/graduation/course/calculation")
public ResponseEntity<GraduationCourseCalculationResponse> getGraduationCourseCalculation(
@Auth(permit = {STUDENT}) Integer userId) {
GraduationCourseCalculationResponse response = graduationService.getGraduationCourseCalculationResponse(userId);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package in.koreatech.koin.domain.graduation.dto;

import java.util.List;

public record GraduationCourseCalculationResponse(
List<InnerCalculationResponse> courseTypes
) {

public static record InnerCalculationResponse(String courseType, int requiredGrades, int grades) {

public static InnerCalculationResponse of(String courseType, int requiredGrades, int grades) {
return new InnerCalculationResponse(courseType, requiredGrades, grades);
}
}

public static GraduationCourseCalculationResponse of (List<InnerCalculationResponse> courseTypes) {
return new GraduationCourseCalculationResponse(courseTypes);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package in.koreatech.koin.domain.graduation.repository;

import java.util.List;
import java.util.Optional;

import org.springframework.data.repository.Repository;
Expand All @@ -17,4 +18,6 @@ default Catalog getByYearAndDepartmentAndCode(String year, Department department
.orElseThrow(() -> CatalogNotFoundException.withDetail(
"year: " + year + ", department: " + department + ", code: " + code));
}

List<Catalog> findByLectureNameAndYearAndDepartment(String lectureName, String studentYear, Department department);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@
public interface StandardGraduationRequirementsRepository extends Repository<StandardGraduationRequirements, Integer> {

List<StandardGraduationRequirements> findAllByDepartmentAndYear(Department department, String year);

List<StandardGraduationRequirements> findByDepartmentIdAndCourseTypeIdAndYear(Integer id, Integer id1, String studentYear);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ public interface StudentCourseCalculationRepository extends JpaRepository<Studen
Optional<StudentCourseCalculation> findByUserId(Integer userId);

void deleteAllByUserId(Integer userId);

StudentCourseCalculation findByUserIdAndStandardGraduationRequirementsId(Integer userId, Integer id);
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
package in.koreatech.koin.domain.graduation.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import in.koreatech.koin.domain.graduation.dto.GraduationCourseCalculationResponse;
import in.koreatech.koin.domain.graduation.model.Catalog;
import in.koreatech.koin.domain.graduation.model.DetectGraduationCalculation;
import in.koreatech.koin.domain.graduation.model.StandardGraduationRequirements;
import in.koreatech.koin.domain.graduation.model.StudentCourseCalculation;
import in.koreatech.koin.domain.graduation.repository.CatalogRepository;
import in.koreatech.koin.domain.graduation.repository.DetectGraduationCalculationRepository;
import in.koreatech.koin.domain.graduation.repository.StandardGraduationRequirementsRepository;
import in.koreatech.koin.domain.graduation.repository.StudentCourseCalculationRepository;
import in.koreatech.koin.domain.student.exception.DepartmentNotFoundException;
import in.koreatech.koin.domain.student.model.Department;
import in.koreatech.koin.domain.student.model.Student;
import in.koreatech.koin.domain.student.repository.StudentRepository;
import in.koreatech.koin.domain.timetableV2.model.TimetableLecture;
import in.koreatech.koin.domain.timetableV2.repository.TimetableFrameRepositoryV2;
import lombok.RequiredArgsConstructor;

@Service
Expand All @@ -25,7 +34,9 @@ public class GraduationService {
private final StudentRepository studentRepository;
private final StudentCourseCalculationRepository studentCourseCalculationRepository;
private final StandardGraduationRequirementsRepository standardGraduationRequirementsRepository;
private final TimetableFrameRepositoryV2 timetableFrameRepositoryV2;
private final DetectGraduationCalculationRepository detectGraduationCalculationRepository;
private final CatalogRepository catalogRepository;

@Transactional
public void createStudentCourseCalculation(Integer userId) {
Expand Down Expand Up @@ -83,4 +94,130 @@ public void resetStudentCourseCalculation(Student student, Department newDepartm
detectGraduationCalculation.updatedIsChanged(true);
});
}

@Transactional
public GraduationCourseCalculationResponse getGraduationCourseCalculationResponse(Integer userId) {
// 학생 정보와 학과 검증
Student student = getValidatedStudent(userId);
String studentYear = student.getStudentNumber().substring(0, 4);

// 시간표와 대학 요람 데이터 가져오기
List<Catalog> catalogList = getCatalogListForStudent(student, studentYear);

// courseTypeId와 학점 맵핑
Map<Integer, Integer> courseTypeCreditsMap = calculateCourseTypeCredits(catalogList);

// GraduationRequirements 리스트 조회
List<StandardGraduationRequirements> graduationRequirements = getGraduationRequirements(catalogList, studentYear);

// 계산 로직 및 응답 생성
List<GraduationCourseCalculationResponse.InnerCalculationResponse> courseTypes = processGraduationCalculations(
userId, student, graduationRequirements, courseTypeCreditsMap
);

return GraduationCourseCalculationResponse.of(courseTypes);
}

private Student getValidatedStudent(Integer userId) {
Student student = studentRepository.getById(userId);

if (student.getDepartment() == null) {
DepartmentNotFoundException.withDetail("학과를 추가하세요.");
}
if (student.getStudentNumber() == null) {
DepartmentNotFoundException.withDetail("학번을 추가하세요.");
}
return student;
}

private List<Catalog> getCatalogListForStudent(Student student, String studentYear) {
List<TimetableLecture> timetableLectures = timetableFrameRepositoryV2.getAllByUserId(student.getId()).stream()
.flatMap(frame -> frame.getTimetableLectures().stream())
.toList();

List<Catalog> catalogList = new ArrayList<>();
timetableLectures.stream()
.map(timetableLecture -> timetableLecture.getLecture().getName())
.forEach(lectureName -> {
List<Catalog> catalogs = catalogRepository.findByLectureNameAndYearAndDepartment(
lectureName, studentYear, student.getDepartment());
catalogList.addAll(catalogs);
});
return catalogList;
}

private Map<Integer, Integer> calculateCourseTypeCredits(List<Catalog> catalogList) {
Map<Integer, Integer> courseTypeCreditsMap = new HashMap<>();
for (Catalog catalog : catalogList) {
int courseTypeId = catalog.getCourseType().getId();
courseTypeCreditsMap.put(courseTypeId, courseTypeCreditsMap.getOrDefault(courseTypeId, 0) + catalog.getCredit());
}
return courseTypeCreditsMap;
}

private List<StandardGraduationRequirements> getGraduationRequirements(List<Catalog> catalogList, String studentYear) {
return catalogList.stream()
.map(catalog -> standardGraduationRequirementsRepository.findByDepartmentIdAndCourseTypeIdAndYear(
catalog.getDepartment().getId(),
catalog.getCourseType().getId(),
studentYear
))
.filter(Objects::nonNull)
.flatMap(List::stream)
.distinct()
.toList();
}

private List<GraduationCourseCalculationResponse.InnerCalculationResponse> processGraduationCalculations(
Integer userId, Student student, List<StandardGraduationRequirements> graduationRequirements,
Map<Integer, Integer> courseTypeCreditsMap) {

List<GraduationCourseCalculationResponse.InnerCalculationResponse> courseTypes = new ArrayList<>();

for (StandardGraduationRequirements requirement : graduationRequirements) {
// 1. 학점 계산 및 저장
int completedGrades = updateStudentCourseCalculation(userId, student, requirement, courseTypeCreditsMap);

// 2. 응답 생성
GraduationCourseCalculationResponse.InnerCalculationResponse response = createCalculationResponse(requirement, completedGrades);
courseTypes.add(response);
}
return courseTypes;
}

private int updateStudentCourseCalculation(Integer userId, Student student, StandardGraduationRequirements requirement,
Map<Integer, Integer> courseTypeCreditsMap) {
if (requirement.getCourseType() == null) {
throw new IllegalStateException("CourseType이 null입니다.");
}

int completedGrades = courseTypeCreditsMap.getOrDefault(requirement.getCourseType().getId(), 0);

StudentCourseCalculation existingCalculation = studentCourseCalculationRepository
.findByUserIdAndStandardGraduationRequirementsId(userId, requirement.getId());

if (existingCalculation != null) {
completedGrades += existingCalculation.getCompletedGrades();
studentCourseCalculationRepository.delete(existingCalculation);
}

StudentCourseCalculation newCalculation = StudentCourseCalculation.builder()
.completedGrades(completedGrades)
.user(student.getUser())
.standardGraduationRequirements(requirement)
.build();
studentCourseCalculationRepository.save(newCalculation);

return completedGrades;
}

private GraduationCourseCalculationResponse.InnerCalculationResponse createCalculationResponse(
StandardGraduationRequirements requirement, int completedGrades) {

return GraduationCourseCalculationResponse.InnerCalculationResponse.of(
requirement.getCourseType().getName(),
requirement.getRequiredGrades(),
completedGrades
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

import in.koreatech.koin.domain.graduation.model.Catalog;
import in.koreatech.koin.domain.graduation.model.CourseType;
import in.koreatech.koin.domain.graduation.repository.CatalogRepository;
import in.koreatech.koin.domain.student.model.Student;
import in.koreatech.koin.domain.student.repository.StudentRepository;
import in.koreatech.koin.domain.timetable.model.Lecture;
import in.koreatech.koin.domain.timetableV2.dto.request.TimetableLectureCreateRequest;
import in.koreatech.koin.domain.timetableV2.model.TimetableFrame;
import in.koreatech.koin.domain.timetableV2.model.TimetableLecture;
import in.koreatech.koin.domain.graduation.repository.CatalogRepository;
import in.koreatech.koin.domain.timetableV2.repository.LectureRepositoryV2;
import in.koreatech.koin.domain.timetableV2.repository.TimetableLectureRepositoryV2;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package in.koreatech.koin.domain.timetableV2.repository;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

Expand Down Expand Up @@ -94,7 +95,12 @@ default TimetableFrame getByIdWithDeleted(Integer id) {

void deleteAllByUserAndSemester(User user, Semester semester);

List<TimetableFrame> findAllByUserId(Integer userId);
Optional<List<TimetableFrame>> findAllByUserId(Integer userId);

boolean existsByUserAndSemester(User user, Semester semester);

default List<TimetableFrame> getAllByUserId(Integer userId) {
return findAllByUserId(userId)
.orElseThrow(() -> TimetableFrameNotFoundException.withDetail("userId: " + userId));
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public Object getTimetablesFrame(Integer userId, String semesterRequest) {
}

public TimetableFramesResponse getAllTimetablesFrame(Integer userId) {
List<TimetableFrame> timetableFrames = timetableFrameRepositoryV2.findAllByUserId(userId);
List<TimetableFrame> timetableFrames = timetableFrameRepositoryV2.getAllByUserId(userId);
return TimetableFramesResponse.from(timetableFrames);
}

Expand Down

0 comments on commit 9aa6ea4

Please sign in to comment.