Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat : 학기와 이수구분으로 강의 찾기 #1184

Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
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.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import in.koreatech.koin.domain.graduation.dto.CourseTypeLectureResponse;
import in.koreatech.koin.global.auth.Auth;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
Expand Down Expand Up @@ -49,4 +51,22 @@ ResponseEntity<String> uploadStudentGradeExcelFile(
@RequestParam(value = "file") MultipartFile file,
@Auth(permit = {STUDENT}) Integer userId
);

@ApiResponses(
value = {
@ApiResponse(responseCode = "200"),
@ApiResponse(responseCode = "401", content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "403", content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true)))
}
)
@Operation(summary = "학기에 따른 이수구분 강의 출력")
@SecurityRequirement(name = "Jwt Authentication")
@GetMapping("/graduation/course-type")
ResponseEntity<CourseTypeLectureResponse> getCourseTypeLecture(
@RequestParam(name = "year") Integer year,
@RequestParam(name = "term") String term,
@RequestParam(name = "name") String courseTypeName,
@Auth(permit = {STUDENT}) Integer userId
);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package in.koreatech.koin.domain.graduation.controller;

import java.io.IOException;

import static in.koreatech.koin.domain.user.model.UserType.STUDENT;

import org.springframework.http.ResponseEntity;
Expand All @@ -10,7 +11,7 @@
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import in.koreatech.koin.domain.graduation.dto.GraduationCourseCalculationResponse;
import in.koreatech.koin.domain.graduation.dto.CourseTypeLectureResponse;
import in.koreatech.koin.domain.graduation.service.GraduationService;
import in.koreatech.koin.domain.user.model.UserType;
import in.koreatech.koin.global.auth.Auth;
Expand All @@ -24,8 +25,7 @@ public class GraduationController implements GraduationApi {

@PostMapping("/graduation/agree")
public ResponseEntity<Void> createStudentCourseCalculation(
@Auth(permit = {STUDENT}) Integer userId)
{
@Auth(permit = {STUDENT}) Integer userId) {
graduationService.createStudentCourseCalculation(userId);
return ResponseEntity.ok().build();
}
Expand All @@ -43,10 +43,23 @@ public ResponseEntity<String> uploadStudentGradeExcelFile(
}
}

@GetMapping("/graduation/course-type")
public ResponseEntity<CourseTypeLectureResponse> getCourseTypeLecture(
@RequestParam(name = "year") Integer year,
@RequestParam(name = "term") String term,
@RequestParam(name = "name") String courseTypeName,
@Auth(permit = {STUDENT}) Integer userId
) {
CourseTypeLectureResponse response = graduationService.getLectureByCourseType(year, term, courseTypeName);
return ResponseEntity.ok(response);
}

/*
@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,21 @@
package in.koreatech.koin.domain.graduation.dto;

import java.util.List;

import in.koreatech.koin.domain.timetable.model.Lecture;
import io.swagger.v3.oas.annotations.media.Schema;

public record CourseTypeLectureResponse(
@Schema(description = "학기", example = "20192")
String semester,

@Schema(description = "이수구분 충족강의")
List<LecturePortionResponse> lectures
) {
public static CourseTypeLectureResponse of(String semester, List<Lecture> lectures) {
List<LecturePortionResponse> lectureList = lectures.stream()
.map(LecturePortionResponse::from)
.toList();
return new CourseTypeLectureResponse(semester, lectureList);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package in.koreatech.koin.domain.graduation.dto;

import in.koreatech.koin.domain.timetable.model.Lecture;

public record LecturePortionResponse
Soundbar91 marked this conversation as resolved.
Show resolved Hide resolved
(
Integer id,
String code,
String name,
String grades,
String department
) {
public static LecturePortionResponse from(Lecture lecture) {
return new LecturePortionResponse(
lecture.getId(),
lecture.getCode(),
lecture.getName(),
lecture.getGrades(),
lecture.getDepartment()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,18 @@ public interface CatalogRepository extends Repository<Catalog, Integer> {

Optional<Catalog> findByDepartmentAndCode(Department department, String code);

// 이거 오류나요..
// List<Catalog> findByLectureNameAndYearAndDepartment(String lectureName, String studentYear, Department department);

Optional<List<Catalog>> findAllByCourseTypeId(Integer courseTypeId);

default Catalog getByDepartmentAndCode(Department department, String code) {
return findByDepartmentAndCode(department, code)
.orElseThrow(() -> CatalogNotFoundException.withDetail("department: " + department + ", code: " + code));
}

List<Catalog> findByLectureNameAndYearAndDepartment(String lectureName, String studentYear, Department department);
default List<Catalog> getAllByCourseTypeId(Integer courseTypeId) {
return findAllByCourseTypeId(courseTypeId)
.orElseThrow(() -> CatalogNotFoundException.withDetail("course_type_id" + courseTypeId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,9 @@ default CourseType getCourseTypeById(Integer id) {
return findById(id)
.orElseThrow(() -> CourseTypeNotFoundException.withDetail("course_type_id: " + id));
}

default CourseType getByName(String name) {
return findByName(name)
.orElseThrow(() -> CourseTypeNotFoundException.withDetail("course_type_name: " + name));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

public interface DetectGraduationCalculationRepository extends Repository<DetectGraduationCalculation, Integer> {

Optional<DetectGraduationCalculation> findByUserId(Integer userId);

void save(DetectGraduationCalculation detectGraduationCalculation);

Optional<DetectGraduationCalculation> findByUserId(Integer userId);
}

Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

public interface StudentCourseCalculationRepository extends Repository<StudentCourseCalculation, Integer> {

Optional<StudentCourseCalculation> findByUserId(Integer userId);

void deleteAllByUserId(Integer userId);

void save(StudentCourseCalculation studentCourseCalculation);

Optional<StudentCourseCalculation> findByUserId(Integer userId);

StudentCourseCalculation findByUserIdAndStandardGraduationRequirementsId(Integer userId, Integer id);

void delete(StudentCourseCalculation existingCalculation);

void deleteAllByUserId(Integer userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -16,6 +15,7 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import in.koreatech.koin.domain.graduation.dto.CourseTypeLectureResponse;
import in.koreatech.koin.domain.graduation.dto.GraduationCourseCalculationResponse;
import in.koreatech.koin.domain.graduation.model.Catalog;
import in.koreatech.koin.domain.graduation.model.DetectGraduationCalculation;
Expand All @@ -30,7 +30,7 @@
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.student.util.StudentUtil;
import in.koreatech.koin.domain.timetableV2.exception.NotFoundSemesterAndCourseTypeException;
import in.koreatech.koin.domain.timetableV2.model.TimetableLecture;
import in.koreatech.koin.domain.timetableV2.repository.TimetableFrameRepositoryV2;

Expand All @@ -45,6 +45,9 @@
import in.koreatech.koin.domain.timetableV2.repository.LectureRepositoryV2;
import in.koreatech.koin.domain.timetableV2.repository.SemesterRepositoryV2;
import in.koreatech.koin.domain.timetableV2.repository.TimetableLectureRepositoryV2;
import in.koreatech.koin.domain.timetableV3.model.Term;
import in.koreatech.koin.domain.timetableV3.repository.SemesterRepositoryV3;
import in.koreatech.koin.domain.timetableV3.service.SemesterServiceV3;
import in.koreatech.koin.domain.user.model.User;
import in.koreatech.koin.domain.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
Expand All @@ -64,12 +67,14 @@ public class GraduationService {
private final SemesterRepositoryV2 semesterRepositoryV2;
private final LectureRepositoryV2 lectureRepositoryV2;
private final TimetableLectureRepositoryV2 timetableLectureRepositoryV2;
private final SemesterRepositoryV3 semesterRepositoryV3;
private final CatalogRepository catalogRepository;

private static final String MIDDLE_TOTAL = "소 계";
private static final String TOTAL = "합 계";
private static final String RETAKE = "Y";
private static final String UNSATISFACTORY = "U";
private final SemesterServiceV3 semesterServiceV3;

@Transactional
public void createStudentCourseCalculation(Integer userId) {
Expand Down Expand Up @@ -103,6 +108,7 @@ public void resetStudentCourseCalculation(Student student, Department newDepartm
});
}

/*
@Transactional
public GraduationCourseCalculationResponse getGraduationCourseCalculationResponse(Integer userId) {
DetectGraduationCalculation detectGraduationCalculation = detectGraduationCalculationRepository.findByUserId(userId)
Expand Down Expand Up @@ -135,6 +141,7 @@ public GraduationCourseCalculationResponse getGraduationCourseCalculationRespons

return GraduationCourseCalculationResponse.of(courseTypes);
}
*/

@Transactional
public void readStudentGradeExcelFile(MultipartFile file, Integer userId) throws IOException {
Expand All @@ -158,7 +165,7 @@ public void readStudentGradeExcelFile(MultipartFile file, Integer userId) throws
}

String semester = getKoinSemester(data.semester(), data.year());
CourseType courseType = courseTypeRepository.findByName(data.courseType()).orElse(null);
CourseType courseType = mappingCourseType(data.courseType());
Lecture lecture = lectureRepositoryV2.findBySemesterAndCodeAndLectureClass(semester,
data.code(), data.lectureClass()).orElse(null);

Expand Down Expand Up @@ -229,8 +236,8 @@ private void checkFiletype(MultipartFile file) {

private boolean skipRow(GradeExcelData gradeExcelData) {
return gradeExcelData.classTitle().equals(MIDDLE_TOTAL) ||
gradeExcelData.retakeStatus().equals(RETAKE) ||
gradeExcelData.grade().equals(UNSATISFACTORY);
gradeExcelData.retakeStatus().equals(RETAKE) ||
gradeExcelData.grade().equals(UNSATISFACTORY);
}

private String getKoinSemester(String semester, String year) {
Expand All @@ -248,6 +255,16 @@ private void validateStudentField(Object field, String message) {
}
}

public CourseType mappingCourseType(String courseTypeName) {
if ("전필".equals(courseTypeName)) {
return courseTypeRepository.getByName("학과(전공)필수");
} else if ("전선".equals(courseTypeName)) {
return courseTypeRepository.getByName("학과(전공)선택");
} else {
return courseTypeRepository.findByName(courseTypeName).orElse(null);
}
}

private void initializeStudentCourseCalculation(Student student, Department department) {
// 학번에 맞는 이수요건 정보 조회
List<StandardGraduationRequirements> requirementsList =
Expand Down Expand Up @@ -278,6 +295,7 @@ private Student getValidatedStudent(Integer userId) {
return student;
}

/*
private List<Catalog> getCatalogListForStudent(Student student, String studentYear) {
List<TimetableLecture> timetableLectures = timetableFrameRepositoryV2.getAllByUserId(student.getId()).stream()
.flatMap(frame -> frame.getTimetableLectures().stream())
Expand All @@ -297,6 +315,7 @@ private List<Catalog> getCatalogListForStudent(Student student, String studentYe
});
return catalogList;
}
*/

private Map<Integer, Integer> calculateCourseTypeCredits(List<Catalog> catalogList) {
Map<Integer, Integer> courseTypeCreditsMap = new HashMap<>();
Expand Down Expand Up @@ -361,4 +380,19 @@ private int updateStudentCourseCalculation(Integer userId, Student student,

return completedGrades;
}

public CourseTypeLectureResponse getLectureByCourseType(Integer year, String term, String courseTypeName) {
CourseType courseType = courseTypeRepository.getByName(courseTypeName);
List<Catalog> catalogs = catalogRepository.getAllByCourseTypeId(courseType.getId());
List<String> codes = catalogs.stream().map(Catalog::getCode).toList();

Term parsedTerm = Term.fromDescription(term);
Semester foundSemester = semesterRepositoryV3.getByYearAndTerm(year, parsedTerm);
String semester = foundSemester.getSemester();

List<Lecture> lectures = lectureRepositoryV2.findAllByCodesAndSemester(codes, semester)
.orElseThrow(() -> new NotFoundSemesterAndCourseTypeException("학기나 이수구분을 찾을 수 없습니다."));

return CourseTypeLectureResponse.of(semester, lectures);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package in.koreatech.koin.domain.timetableV2.exception;

import in.koreatech.koin.global.exception.DataNotFoundException;

public class NotFoundSemesterAndCourseTypeException extends DataNotFoundException {
private static final String DEFAULT_MESSAGE = "학기나 이수구분을 찾을 수 없습니다.";

public NotFoundSemesterAndCourseTypeException(String message) {
super(message);
}

public NotFoundSemesterAndCourseTypeException(String message, String detail) {
super(message, detail);
}

public static NotFoundSemesterAndCourseTypeException withDetail(String detail) {
return new NotFoundSemesterAndCourseTypeException(DEFAULT_MESSAGE, detail);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import java.util.List;
import java.util.Optional;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;

import in.koreatech.koin.domain.timetable.exception.LectureNotFoundException;
import in.koreatech.koin.domain.timetable.exception.SemesterNotFoundException;
import in.koreatech.koin.domain.timetable.model.Lecture;
import in.koreatech.koin.domain.timetable.model.Semester;
import io.lettuce.core.dynamic.annotation.Param;

public interface LectureRepositoryV2 extends Repository<Lecture, Integer> {

Expand All @@ -20,6 +21,9 @@ public interface LectureRepositoryV2 extends Repository<Lecture, Integer> {

Optional<Lecture> findBySemesterAndCodeAndLectureClass(String semesterDate, String code, String classLecture);

@Query("SELECT l FROM Lecture l WHERE l.code IN :codes AND l.semester = :semesterDate")
Optional<List<Lecture>> findAllByCodesAndSemester(@Param("codes") List<String> codes, @Param("semesterDate") String semesterDate);
Soundbar91 marked this conversation as resolved.
Show resolved Hide resolved

default Lecture getBySemesterAndCodeAndLectureClass(String semesterDate, String code, String classLecture) {
return findBySemesterAndCodeAndLectureClass(semesterDate, code, classLecture)
.orElseThrow(() -> SemesterNotFoundException.withDetail(
Expand All @@ -30,4 +34,5 @@ default Lecture getLectureById(Integer id) {
return findById(id)
.orElseThrow(() -> LectureNotFoundException.withDetail("lecture_id: " + id));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public GroupedOpenApi userApi() {
"in.koreatech.koin.domain.student",
"in.koreatech.koin.domain.timetable",
"in.koreatech.koin.domain.timetableV2",
"in.koreatech.koin.domain.timetableV3"
"in.koreatech.koin.domain.timetableV3",
"in.koreatech.koin.domain.graduation"
Soundbar91 marked this conversation as resolved.
Show resolved Hide resolved
};

return createGroupedOpenApi("4. User API", packagesPath);
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/db/migration/V116__add_catalog.sql
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ CREATE TABLE if not exists `koin`.`catalog`
FOREIGN KEY (`course_type_id`) REFERENCES `course_type` (`id`),
FOREIGN KEY (`department_id`) REFERENCES `department` (`id`),
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP comment '생성 일자',
updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '수정 일자',
updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP comment '수정 일자'
Soundbar91 marked this conversation as resolved.
Show resolved Hide resolved
);
Loading
Loading