From 3a4522a027aeb0cd8cebb0429be04fb7a26966aa Mon Sep 17 00:00:00 2001 From: YunJaeHoon Date: Sun, 5 Jan 2025 20:40:12 +0900 Subject: [PATCH 1/4] =?UTF-8?q?FIX:=20=EA=B0=95=EC=9D=98=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EB=B0=8F=20=EC=9E=A5=EC=86=8C=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=EB=B6=84=EB=A6=AC=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?api=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Devkor_project/dto/CommentDto.java | 56 ++++++++--- .../example/Devkor_project/dto/CourseDto.java | 94 +++++++++++++++---- .../example/Devkor_project/entity/Course.java | 1 - .../repository/TimeLocationRepository.java | 10 +- .../Devkor_project/service/AdminService.java | 81 +++++++++++++++- .../Devkor_project/service/CourseService.java | 36 +++++-- .../Devkor_project/service/MyPageService.java | 7 +- 7 files changed, 239 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/example/Devkor_project/dto/CommentDto.java b/src/main/java/com/example/Devkor_project/dto/CommentDto.java index 7bce420..5bc9267 100644 --- a/src/main/java/com/example/Devkor_project/dto/CommentDto.java +++ b/src/main/java/com/example/Devkor_project/dto/CommentDto.java @@ -1,15 +1,13 @@ package com.example.Devkor_project.dto; -import com.example.Devkor_project.entity.Comment; -import com.example.Devkor_project.entity.CommentRating; -import com.example.Devkor_project.entity.Course; -import com.example.Devkor_project.entity.CourseRating; +import com.example.Devkor_project.entity.*; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.*; import java.time.LocalDate; +import java.util.List; public class CommentDto { @@ -268,7 +266,7 @@ public static class StartUpdate @Schema(description = "학점") private String credit; @Schema(description = "시간, 장소") - private String time_location; + private List time_locations; @NotNull(message = "COUNT_comments는 null일 수 없습니다.") @Schema(description = "강의평 개수") private int COUNT_comments; @@ -566,7 +564,7 @@ public static class MyPage @Schema(description = "학점") private String credit; @Schema(description = "시간, 장소") - private String time_location; + private List time_locations; @NotBlank(message = "[review] cannot be blank.") @Schema(description = "강의평 내용") @@ -629,10 +627,13 @@ public static class MyPage private boolean learn_t4_industry; } - public static CommentDto.StartUpdate entityToStartUpdate(Course course, - CourseRating courseRating, - com.example.Devkor_project.entity.Comment comment, - CommentRating commentRating) + public static CommentDto.StartUpdate entityToStartUpdate( + Course course, + CourseRating courseRating, + com.example.Devkor_project.entity.Comment comment, + CommentRating commentRating, + List timeLocations + ) { return StartUpdate.builder() .course_id(course.getCourse_id()) @@ -645,7 +646,18 @@ public static CommentDto.StartUpdate entityToStartUpdate(Course course, .name(course.getName()) .professor(course.getProfessor()) .credit(course.getCredit()) - .time_location(course.getTime_location()) + .time_locations( + timeLocations.stream().map( + timeLocation -> { + return CourseDto.TimeLocation.builder() + .day(timeLocation.getDay()) + .startPeriod(timeLocation.getStartPeriod()) + .endPeriod(timeLocation.getEndPeriod()) + .location(timeLocation.getLocation()) + .build(); + }) + .toList() + ) .COUNT_comments(course.getCOUNT_comments()) .AVG_rating(courseRating.getAVG_rating()) .AVG_r1_amount_of_studying(courseRating.getAVG_r1_amount_of_studying()) @@ -680,9 +692,12 @@ public static CommentDto.StartUpdate entityToStartUpdate(Course course, .build(); } - public static CommentDto.MyPage entityToMyPage(com.example.Devkor_project.entity.Comment comment, - Course course, - CommentRating commentRating) + public static CommentDto.MyPage entityToMyPage( + com.example.Devkor_project.entity.Comment comment, + Course course, + CommentRating commentRating, + List timeLocations + ) { return MyPage.builder() .comment_id(comment.getComment_id()) @@ -696,7 +711,18 @@ public static CommentDto.MyPage entityToMyPage(com.example.Devkor_project.entity .name(course.getName()) .professor(course.getProfessor()) .credit(course.getCredit()) - .time_location(course.getTime_location()) + .time_locations( + timeLocations.stream().map( + timeLocation -> { + return CourseDto.TimeLocation.builder() + .day(timeLocation.getDay()) + .startPeriod(timeLocation.getStartPeriod()) + .endPeriod(timeLocation.getEndPeriod()) + .location(timeLocation.getLocation()) + .build(); + }) + .toList() + ) .review(comment.getReview()) .likes(comment.getLikes()) .created_at(comment.getCreated_at()) diff --git a/src/main/java/com/example/Devkor_project/dto/CourseDto.java b/src/main/java/com/example/Devkor_project/dto/CourseDto.java index b8da0a7..3d8198a 100644 --- a/src/main/java/com/example/Devkor_project/dto/CourseDto.java +++ b/src/main/java/com/example/Devkor_project/dto/CourseDto.java @@ -2,6 +2,7 @@ import com.example.Devkor_project.entity.Course; import com.example.Devkor_project.entity.CourseRating; +import com.example.Devkor_project.entity.TimeLocation; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; @@ -49,7 +50,7 @@ public static class Basic @Schema(description = "학점") private String credit; @Schema(description = "시간, 장소") - private String time_location; + private List time_locations; @NotNull(message = "COUNT_comments는 null일 수 없습니다.") @Schema(description = "강의평 개수") private int COUNT_comments; @@ -138,7 +139,7 @@ public static class ExpiredBasic @Schema(description = "학점") private String credit; @Schema(description = "시간, 장소") - private String time_location; + private List time_locations; @NotNull(message = "COUNT_comments는 null일 수 없습니다.") @Schema(description = "강의평 개수") private int COUNT_comments; @@ -183,7 +184,7 @@ public static class Detail @Schema(description = "학점") private String credit; @Schema(description = "시간, 장소") - private String time_location; + private List time_locations; @NotNull(message = "COUNT_comments는 null일 수 없습니다.") @Schema(description = "강의평 개수") private int COUNT_comments; @@ -275,7 +276,7 @@ public static class ExpiredDetail @Schema(description = "학점") private String credit; @Schema(description = "시간, 장소") - private String time_location; + private List time_locations; @NotNull(message = "COUNT_comments는 null일 수 없습니다.") @Schema(description = "강의평 개수") private int COUNT_comments; @@ -324,7 +325,13 @@ public static class TimeLocation private String location; } - public static CourseDto.Basic entityToBasic(Course course, CourseRating courseRating, Boolean isBookmark) { + public static CourseDto.Basic entityToBasic( + Course course, + CourseRating courseRating, + List timeLocations, + Boolean isBookmark + ) + { return Basic.builder() .course_id(course.getCourse_id()) .course_code(course.getCourse_code()) @@ -336,7 +343,18 @@ public static CourseDto.Basic entityToBasic(Course course, CourseRating courseRa .name(course.getName()) .professor(course.getProfessor()) .credit(course.getCredit()) - .time_location(course.getTime_location()) + .time_locations( + timeLocations.stream().map( + timeLocation -> { + return CourseDto.TimeLocation.builder() + .day(timeLocation.getDay()) + .startPeriod(timeLocation.getStartPeriod()) + .endPeriod(timeLocation.getEndPeriod()) + .location(timeLocation.getLocation()) + .build(); + }) + .toList() + ) .COUNT_comments(course.getCOUNT_comments()) .isBookmark(isBookmark) .AVG_rating(courseRating.getAVG_rating()) @@ -356,7 +374,12 @@ public static CourseDto.Basic entityToBasic(Course course, CourseRating courseRa .build(); } - public static CourseDto.ExpiredBasic entityToExpiredBasic(Course course, Boolean isBookmark) { + public static CourseDto.ExpiredBasic entityToExpiredBasic( + Course course, + List timeLocations, + Boolean isBookmark + ) + { return ExpiredBasic.builder() .course_id(course.getCourse_id()) .course_code(course.getCourse_code()) @@ -368,16 +391,30 @@ public static CourseDto.ExpiredBasic entityToExpiredBasic(Course course, Boolean .name(course.getName()) .professor(course.getProfessor()) .credit(course.getCredit()) - .time_location(course.getTime_location()) + .time_locations( + timeLocations.stream().map( + timeLocation -> { + return CourseDto.TimeLocation.builder() + .day(timeLocation.getDay()) + .startPeriod(timeLocation.getStartPeriod()) + .endPeriod(timeLocation.getEndPeriod()) + .location(timeLocation.getLocation()) + .build(); + }) + .toList() + ) .COUNT_comments(course.getCOUNT_comments()) .isBookmark(isBookmark) .build(); } - public static CourseDto.Detail entityToDetail(Course course, - CourseRating courseRating, - List commentDtos, - Boolean isBookmark) + public static CourseDto.Detail entityToDetail( + Course course, + CourseRating courseRating, + List commentDtos, + List timeLocations, + Boolean isBookmark + ) { return Detail.builder() .course_id(course.getCourse_id()) @@ -390,7 +427,18 @@ public static CourseDto.Detail entityToDetail(Course course, .name(course.getName()) .professor(course.getProfessor()) .credit(course.getCredit()) - .time_location(course.getTime_location()) + .time_locations( + timeLocations.stream().map( + timeLocation -> { + return CourseDto.TimeLocation.builder() + .day(timeLocation.getDay()) + .startPeriod(timeLocation.getStartPeriod()) + .endPeriod(timeLocation.getEndPeriod()) + .location(timeLocation.getLocation()) + .build(); + }) + .toList() + ) .COUNT_comments(course.getCOUNT_comments()) .isBookmark(isBookmark) .AVG_rating(courseRating.getAVG_rating()) @@ -411,8 +459,11 @@ public static CourseDto.Detail entityToDetail(Course course, .build(); } - public static CourseDto.ExpiredDetail entityToExpiredDetail(Course course, - Boolean isBookmark) + public static CourseDto.ExpiredDetail entityToExpiredDetail( + Course course, + List timeLocations, + Boolean isBookmark + ) { return ExpiredDetail.builder() .course_id(course.getCourse_id()) @@ -425,7 +476,18 @@ public static CourseDto.ExpiredDetail entityToExpiredDetail(Course course, .name(course.getName()) .professor(course.getProfessor()) .credit(course.getCredit()) - .time_location(course.getTime_location()) + .time_locations( + timeLocations.stream().map( + timeLocation -> { + return CourseDto.TimeLocation.builder() + .day(timeLocation.getDay()) + .startPeriod(timeLocation.getStartPeriod()) + .endPeriod(timeLocation.getEndPeriod()) + .location(timeLocation.getLocation()) + .build(); + }) + .toList() + ) .COUNT_comments(course.getCOUNT_comments()) .isBookmark(isBookmark) .build(); diff --git a/src/main/java/com/example/Devkor_project/entity/Course.java b/src/main/java/com/example/Devkor_project/entity/Course.java index dd730ef..73f1e81 100644 --- a/src/main/java/com/example/Devkor_project/entity/Course.java +++ b/src/main/java/com/example/Devkor_project/entity/Course.java @@ -35,6 +35,5 @@ public class Course @Column(nullable = false) private String year; @Column(nullable = false) private String semester; @Column private String credit; - @Column private String time_location; @Column(nullable = false) private int COUNT_comments; } diff --git a/src/main/java/com/example/Devkor_project/repository/TimeLocationRepository.java b/src/main/java/com/example/Devkor_project/repository/TimeLocationRepository.java index 3c3e04d..4440ad2 100644 --- a/src/main/java/com/example/Devkor_project/repository/TimeLocationRepository.java +++ b/src/main/java/com/example/Devkor_project/repository/TimeLocationRepository.java @@ -1,7 +1,15 @@ package com.example.Devkor_project.repository; +import com.example.Devkor_project.entity.Course; import com.example.Devkor_project.entity.TimeLocation; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; -public interface TimeLocationRepository extends JpaRepository { +import java.util.List; + +public interface TimeLocationRepository extends JpaRepository +{ + @Query(value = "SELECT * FROM time_location WHERE course_id = :course_id", nativeQuery = true) + List findByCourseId(Long course_id); } diff --git a/src/main/java/com/example/Devkor_project/service/AdminService.java b/src/main/java/com/example/Devkor_project/service/AdminService.java index d6a1975..b466b0e 100644 --- a/src/main/java/com/example/Devkor_project/service/AdminService.java +++ b/src/main/java/com/example/Devkor_project/service/AdminService.java @@ -182,11 +182,25 @@ public CourseDto.CheckSynchronization checkCourseSynchronization(CrawlingDto.Syn .year(course.getYear()) .semester(course.getTerm()) .credit(credit) - .time_location(time_location) .COUNT_comments(0) .build(); courseRepository.save(newCourse); + + // 강의 시간 및 장소 데이터 추가 + List timeLocations = parseTimeLocation(time_location); + if (timeLocations != null && !timeLocations.isEmpty()) { + for (CourseDto.TimeLocation timeLocationDto : timeLocations) { + TimeLocation timeLocation = TimeLocation.builder() + .course_id(newCourse) + .day(timeLocationDto.getDay()) + .startPeriod(timeLocationDto.getStartPeriod()) + .endPeriod(timeLocationDto.getEndPeriod()) + .location(timeLocationDto.getLocation()) + .build(); + timeLocationRepository.save(timeLocation); + } + } } else { @@ -214,8 +228,69 @@ public CourseDto.CheckSynchronization checkCourseSynchronization(CrawlingDto.Syn courseInDatabase.setCredit(course.getTime().isEmpty() ? null : course.getTime().replaceAll("\\(.*?\\)", "")); isUpdate = true; } - if(!Objects.equals(courseInDatabase.getTime_location(), course.getTime_room().isEmpty() ? null : course.getTime_room().replaceAll("<.*?>", ""))) { - courseInDatabase.setTime_location(course.getTime_room().isEmpty() ? null : course.getTime_room().replaceAll("<.*?>", "")); + + // 실제 강의 시간 및 장소 정보 + List realTimeLocations = parseTimeLocation(course.getTime_room().replaceAll("<.*?>", "")); + // 현재 데이터베이스에 저장되어 있는 강의 시간 및 장소 정보 + List savedTimeLocations = timeLocationRepository.findByCourseId(courseInDatabase.getCourse_id()); + boolean timeLocationIsDifferent = false; + + // 실제 강의 시간 및 장소 정보와 현재 데이터베이스에 저장되어 있는 강의 시간 및 장소 정보가 동일한지 확인 + if(realTimeLocations == null && savedTimeLocations == null) + timeLocationIsDifferent = false; + else if(realTimeLocations != null && savedTimeLocations == null) + timeLocationIsDifferent = true; + else if(realTimeLocations == null) + timeLocationIsDifferent = true; + else if(realTimeLocations.size() != savedTimeLocations.size()) + timeLocationIsDifferent = true; + else + { + for(CourseDto.TimeLocation realTimeLocation : realTimeLocations) + { + boolean isDifferent = true; + + for(TimeLocation savedTimeLocation : savedTimeLocations) + { + if(Objects.equals(savedTimeLocation.getDay(), realTimeLocation.getDay()) && + Objects.equals(savedTimeLocation.getStartPeriod(), realTimeLocation.getStartPeriod()) && + Objects.equals(savedTimeLocation.getEndPeriod(), realTimeLocation.getEndPeriod()) && + Objects.equals(savedTimeLocation.getLocation(), realTimeLocation.getLocation())) + { + isDifferent = false; + break; + } + } + + if(isDifferent) + { + timeLocationIsDifferent = true; + break; + } + } + } + + // 실제 강의 시간 및 장소 정보와 현재 데이터베이스에 저장되어 있는 강의 시간 및 장소 정보가 다를 때 + // 현재 데이터베이스에 저장되어 있는 강의 시간 및 장소 정보를 전부 삭제 + // 그 후, 실제 강의 시간 및 장소 정보를 저장 + if(timeLocationIsDifferent) + { + if(savedTimeLocations != null) + timeLocationRepository.deleteAll(savedTimeLocations); + + if(realTimeLocations != null) { + for (CourseDto.TimeLocation timeLocationDto : realTimeLocations) { + TimeLocation timeLocation = TimeLocation.builder() + .course_id(courseInDatabase) + .day(timeLocationDto.getDay()) + .startPeriod(timeLocationDto.getStartPeriod()) + .endPeriod(timeLocationDto.getEndPeriod()) + .location(timeLocationDto.getLocation()) + .build(); + timeLocationRepository.save(timeLocation); + } + } + isUpdate = true; } diff --git a/src/main/java/com/example/Devkor_project/service/CourseService.java b/src/main/java/com/example/Devkor_project/service/CourseService.java index 812f835..47cc5ec 100644 --- a/src/main/java/com/example/Devkor_project/service/CourseService.java +++ b/src/main/java/com/example/Devkor_project/service/CourseService.java @@ -32,6 +32,7 @@ public class CourseService private final CommentRatingRepository commentRatingRepository; private final CommentLikeRepository commentLikeRepository; private final CommentReportRepository commentReportRepository; + private final TimeLocationRepository timeLocationRepository; /* 강의 검색 서비스 */ public List searchCourse(String keyword, String order, int page, Principal principal) @@ -65,7 +66,11 @@ else if(order.equals("RATING_ASC")) // Course 엔티티 리스트 -> courseDto.ExpiredBasic 리스트 List courseDtos = courses.stream() .map(course -> { - return CourseDto.entityToExpiredBasic(course, false); + + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + + return CourseDto.entityToExpiredBasic(course, timeLocations, false); }) .toList(); @@ -90,10 +95,13 @@ else if(order.equals("RATING_ASC")) // 해당 강의의 평점 데이터 CourseRating courseRating = course.getCourseRating_id(); + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + // 사용자의 해당 강의 북마크 여부 boolean isBookmark = !bookmarkRepository.searchBookmark(profile_id, course.getCourse_id()).isEmpty(); - return CourseDto.entityToBasic(course, courseRating, isBookmark); + return CourseDto.entityToBasic(course, courseRating, timeLocations, isBookmark); }) .toList(); @@ -105,10 +113,13 @@ else if(order.equals("RATING_ASC")) List courseDtos = courses.stream() .map(course -> { + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + // 사용자의 해당 강의 북마크 여부 boolean isBookmark = !bookmarkRepository.searchBookmark(profile_id, course.getCourse_id()).isEmpty(); - return CourseDto.entityToExpiredBasic(course, isBookmark); + return CourseDto.entityToExpiredBasic(course, timeLocations, isBookmark); }) .toList(); @@ -141,11 +152,14 @@ public Object courseDetail(Long course_id, String order, int page, Principal pri Course course = courseRepository.findById(course_id) .orElseThrow(() -> new AppException(ErrorCode.COURSE_NOT_FOUND, course_id)); + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + // 비로그인 시, 평점 데이터와 강의평 리스트를 전달하지 않으며, 북마크 여부가 항상 false if(principal == null) { // CourseDto.ExpiredDetail 반환 - return CourseDto.entityToExpiredDetail(course, false); + return CourseDto.entityToExpiredDetail(course, timeLocations, false); } else { @@ -228,7 +242,7 @@ else if(order.equals("LIKES_ASC")) boolean isBookmark = !bookmarkRepository.searchBookmark(principalProfile_id, course.getCourse_id()).isEmpty(); // course 엔티티와 강의평 dto 리스트로 CourseDto.Detail 만들어서 반환 - return CourseDto.entityToDetail(course, courseRating, commentDtos, isBookmark); + return CourseDto.entityToDetail(course, courseRating, commentDtos, timeLocations, isBookmark); } else { @@ -236,7 +250,7 @@ else if(order.equals("LIKES_ASC")) boolean isBookmark = !bookmarkRepository.searchBookmark(principalProfile_id, course.getCourse_id()).isEmpty(); // CourseDto.ExpiredDetail 반환 - return CourseDto.entityToExpiredDetail(course, isBookmark); + return CourseDto.entityToExpiredDetail(course, timeLocations, isBookmark); } } } @@ -289,6 +303,9 @@ public CourseDto.Basic startInsertComment(Principal principal, Long course_id) Course course = courseRepository.findById(course_id) .orElseThrow(() -> new AppException(ErrorCode.COURSE_NOT_FOUND, course_id)); + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + // 해당 사용자가 이미 해당 강의에 강의평을 달았다면, 예외 처리 List comment = commentRepository.searchComment(profile.getProfile_id(), course_id); if(!comment.isEmpty()) @@ -300,7 +317,7 @@ public CourseDto.Basic startInsertComment(Principal principal, Long course_id) // 사용자의 해당 강의 북마크 여부 boolean isBookmark = !bookmarkRepository.searchBookmark(profile.getProfile_id(), course.getCourse_id()).isEmpty(); - return CourseDto.entityToBasic(course, courseRating, isBookmark); + return CourseDto.entityToBasic(course, courseRating, timeLocations, isBookmark); } /* 강의평 작성 완료 및 등록 서비스 */ @@ -428,13 +445,16 @@ public CommentDto.StartUpdate startUpdateComment(Principal principal, Long comme // 강의 평점 정보 CourseRating courseRating = course.getCourseRating_id(); + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + // 해당 강의평이 해당 사용자가 작성한 강의평이 아니라면, 예외 처리 if(!Objects.equals(comment.getProfile_id().getProfile_id(), profile.getProfile_id())) throw new AppException(ErrorCode.NOT_COMMENT_BY_USER, null); CommentRating commentRating = comment.getCommentRating_id(); - return CommentDto.entityToStartUpdate(course, courseRating, comment, commentRating); + return CommentDto.entityToStartUpdate(course, courseRating, comment, commentRating, timeLocations); } /* 강의평 수정 완료 서비스 */ diff --git a/src/main/java/com/example/Devkor_project/service/MyPageService.java b/src/main/java/com/example/Devkor_project/service/MyPageService.java index 9be185e..3d91b3f 100644 --- a/src/main/java/com/example/Devkor_project/service/MyPageService.java +++ b/src/main/java/com/example/Devkor_project/service/MyPageService.java @@ -31,6 +31,7 @@ public class MyPageService private final CommentRepository commentRepository; private final CourseRatingRepository courseRatingRepository; private final CommentRatingRepository commentRatingRepository; + private final TimeLocationRepository timeLocationRepository; private final BCryptPasswordEncoder encoder; /* 마이페이지 기본 정보 서비스 */ @@ -142,8 +143,9 @@ public List myComments(Principal principal, int page) Course course = comment.getCourse_id(); // 강의 정보 CommentRating commentRating = comment.getCommentRating_id(); // 강의평 평점 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); // 강의 시간 및 장소 정보 - return CommentDto.entityToMyPage(comment, course, commentRating); + return CommentDto.entityToMyPage(comment, course, commentRating, timeLocations); }) .toList(); @@ -191,11 +193,12 @@ public List myBookmarks(Principal principal, int page) Course course = bookmark.getCourse_id(); // 강의 정보 CourseRating courseRating = course.getCourseRating_id(); // 강의 평점 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); // 강의 시간 및 장소 정보 // 사용자의 해당 강의 북마크 여부 boolean isBookmark = !bookmarkRepository.searchBookmark(profile.getProfile_id(), course.getCourse_id()).isEmpty(); - return CourseDto.entityToBasic(course, courseRating, isBookmark); + return CourseDto.entityToBasic(course, courseRating, timeLocations, isBookmark); }) .toList(); From cf41f6a783f373a9f85cf5d7ac3e260b4d90ffe8 Mon Sep 17 00:00:00 2001 From: YunJaeHoon Date: Sun, 5 Jan 2025 20:42:54 +0900 Subject: [PATCH 2/4] VER: v1.1.4 --- README.md | 2 +- src/main/resources/application.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 427bf84..3c8b594 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Academ Back-end repository입니다. --- ### 프로젝트 구조 -( 최신화 : v1.1.3 ) +( 최신화 : v1.1.4 ) ``` │ ├── .github diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 04a0540..27f10d6 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,5 +1,5 @@ academ: - version: "v1.1.3" + version: "v1.1.4" spring: From b637dc7571c02a6d9a2cd35ad011b647aa44b8f9 Mon Sep 17 00:00:00 2001 From: YunJaeHoon Date: Wed, 15 Jan 2025 17:02:38 +0900 Subject: [PATCH 3/4] =?UTF-8?q?FTR:=20=ED=94=84=EB=A1=A0=ED=8A=B8=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=A1=B0=EC=B9=98=EA=B0=80=20=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20api=EB=A5=BC=20UpdateController,=20UpdateServcie?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EB=94=B0=EB=A1=9C=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CourseController.java | 14 +- .../controller/MyPageController.java | 8 +- .../controller/UpdateController.java | 212 +++++++++ .../Devkor_project/dto/CommentDto.java | 350 ++++++++++++++- .../example/Devkor_project/dto/CourseDto.java | 417 +++++++++++++++++- .../example/Devkor_project/entity/Course.java | 1 + .../Devkor_project/service/CourseService.java | 47 +- .../Devkor_project/service/MyPageService.java | 22 +- .../Devkor_project/service/UpdateService.java | 375 ++++++++++++++++ 9 files changed, 1361 insertions(+), 85 deletions(-) create mode 100644 src/main/java/com/example/Devkor_project/controller/UpdateController.java create mode 100644 src/main/java/com/example/Devkor_project/service/UpdateService.java diff --git a/src/main/java/com/example/Devkor_project/controller/CourseController.java b/src/main/java/com/example/Devkor_project/controller/CourseController.java index 279b0ac..39d1c4f 100644 --- a/src/main/java/com/example/Devkor_project/controller/CourseController.java +++ b/src/main/java/com/example/Devkor_project/controller/CourseController.java @@ -41,8 +41,8 @@ public class CourseController @Parameter(name = "page", description = "페이지 번호 ( 1부터 시작 )") }) @ApiResponses(value = { - @ApiResponse(responseCode = "200 (열람권 보유)", description = "CourseDto.Basic 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.Basic.class))), - @ApiResponse(responseCode = "200 (열람권 만료, 비로그인)", description = "CourseDto.ExpiredBasic 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.ExpiredBasic.class))), + @ApiResponse(responseCode = "200 (열람권 보유)", description = "CourseDto.Basic 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.NOT_UPDATED_Basic.class))), + @ApiResponse(responseCode = "200 (열람권 만료, 비로그인)", description = "CourseDto.ExpiredBasic 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.NOT_UPDATED_ExpiredBasic.class))), @ApiResponse(responseCode = "실패: 400 (SHORT_SEARCH_WORD)", description = "검색어가 1글자 이하인 경우 (입력받은 검색어를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 400 (INVALID_ORDER)", description = "입력받은 order 인자가 올바르지 않은 경우 (입력받은 배치 순서를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 404 (NO_RESULT)", description = "검색 결과가 존재하지 않는 경우 (입력받은 검색어를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @@ -97,7 +97,7 @@ public ResponseEntity searchCourseCountPage(@RequestParam(" @Parameter(name = "page", description = "페이지 번호 ( 1부터 시작 )"), }) @ApiResponses(value = { - @ApiResponse(responseCode = "200 (열람권 보유)", description = "CourseDto.Detail 데이터를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.Detail.class))), + @ApiResponse(responseCode = "200 (열람권 보유)", description = "CourseDto.Detail 데이터를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.NOT_UPDATED_Detail.class))), @ApiResponse(responseCode = "실패: 401 (NO_ACCESS_AUTHORITY)", description = "강의평 열람권이 만료된 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 404 (COURSE_NOT_FOUND)", description = "상세 정보를 요청한 course_id에 대한 강의가 존재하지 않는 경우 (입력받은 course_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 404 (USER_NOT_FOUND)", description = "특정 강의평에 대한 사용자 데이터가 존재하지 않는 경우 (profile_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @@ -158,7 +158,7 @@ public ResponseEntity bookmark(Principal principal, @Parameter(name = "course_id", description = "강의평을 추가할 강의의 course_id") }) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "CourseDto.Basic 데이터를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.Basic.class))), + @ApiResponse(responseCode = "200", description = "CourseDto.Basic 데이터를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.NOT_UPDATED_Basic.class))), @ApiResponse(responseCode = "실패: 401 (UNAUTHORIZED)", description = "로그인하지 않은 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 400 (ALREADY_EXIST)", description = "해당 사용자가 해당 강의에 이미 강의평을 등록한 경우 (입력받은 course_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 404 (COURSE_NOT_FOUND)", description = "요청으로 보낸 course_id에 해당하는 강의가 존재하지 않는 경우 (입력받은 course_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @@ -167,7 +167,7 @@ public ResponseEntity bookmark(Principal principal, public ResponseEntity startInsertComment(Principal principal, @RequestParam("course_id") Long course_id) { - CourseDto.Basic dto = courseService.startInsertComment(principal, course_id); + CourseDto.NOT_UPDATED_Basic dto = courseService.startInsertComment(principal, course_id); return ResponseEntity.status(HttpStatus.OK) .body( @@ -218,7 +218,7 @@ public ResponseEntity insertComment(Principal principal, @Parameter(name = "comment_id", description = "수정할 강의평의 comment_id") }) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "CommentDto.StartUpdate 데이터를 반환합니다.", content = @Content(schema = @Schema(implementation = CommentDto.StartUpdate.class))), + @ApiResponse(responseCode = "200", description = "CommentDto.StartUpdate 데이터를 반환합니다.", content = @Content(schema = @Schema(implementation = CommentDto.NOT_UPDATED_StartUpdate.class))), @ApiResponse(responseCode = "실패: 401 (UNAUTHORIZED)", description = "로그인하지 않은 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 400 (NOT_COMMENT_BY_USER)", description = "해당 강의평이 해당 사용자가 작성한 강의평이 아닌 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 404 (COMMENT_NOT_FOUND)", description = "요청으로 보낸 comment_id에 해당하는 강의평이 존재하지 않는 경우 (입력받은 comment_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @@ -227,7 +227,7 @@ public ResponseEntity insertComment(Principal principal, public ResponseEntity startUpdateComment(Principal principal, @RequestParam("comment_id") Long comment_id) { - CommentDto.StartUpdate dto = courseService.startUpdateComment(principal, comment_id); + CommentDto.NOT_UPDATED_StartUpdate dto = courseService.startUpdateComment(principal, comment_id); return ResponseEntity.status(HttpStatus.OK) .body( diff --git a/src/main/java/com/example/Devkor_project/controller/MyPageController.java b/src/main/java/com/example/Devkor_project/controller/MyPageController.java index 8951fc2..061d259 100644 --- a/src/main/java/com/example/Devkor_project/controller/MyPageController.java +++ b/src/main/java/com/example/Devkor_project/controller/MyPageController.java @@ -91,14 +91,14 @@ public ResponseEntity buyAccessAuthority(Principal principa @Parameter(name = "page", description = "페이지 번호 ( 1부터 시작 )") }) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "CommentDto.MyPage 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CommentDto.MyPage.class))), + @ApiResponse(responseCode = "200", description = "CommentDto.MyPage 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CommentDto.NOT_UPDATED_MyPage.class))), @ApiResponse(responseCode = "실패: 401 (UNAUTHORIZED)", description = "로그인하지 않은 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 404 (EMAIL_NOT_FOUND)", description = "요청을 보낸 사용자 계정이 존재하지 않는 경우 (이메일을 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 404 (NO_RESULT)", description = "결과가 없는 경우 (요청으로 보낸 page를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), }) public ResponseEntity myComments(@RequestParam("page") int page, Principal principal) { - List my_comments = myPageService.myComments(principal, page - 1); + List my_comments = myPageService.myComments(principal, page - 1); return ResponseEntity.status(HttpStatus.OK) .body( @@ -143,14 +143,14 @@ public ResponseEntity countMyComments(Principal principal) @Parameter(name = "page", description = "페이지 번호 ( 1부터 시작 )") }) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "CourseDto.Basic 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.Basic.class))), + @ApiResponse(responseCode = "200", description = "CourseDto.Basic 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.NOT_UPDATED_Basic.class))), @ApiResponse(responseCode = "실패: 401 (UNAUTHORIZED)", description = "로그인하지 않은 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 404 (EMAIL_NOT_FOUND)", description = "요청을 보낸 사용자 계정이 존재하지 않는 경우 (이메일을 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), @ApiResponse(responseCode = "실패: 404 (NO_RESULT)", description = "결과가 없는 경우 (요청으로 보낸 page를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), }) public ResponseEntity myBookmarks(@RequestParam("page") int page, Principal principal) { - List my_bookmarks = myPageService.myBookmarks(principal, page - 1); + List my_bookmarks = myPageService.myBookmarks(principal, page - 1); return ResponseEntity.status(HttpStatus.OK) .body( diff --git a/src/main/java/com/example/Devkor_project/controller/UpdateController.java b/src/main/java/com/example/Devkor_project/controller/UpdateController.java new file mode 100644 index 0000000..6ebc2ce --- /dev/null +++ b/src/main/java/com/example/Devkor_project/controller/UpdateController.java @@ -0,0 +1,212 @@ +package com.example.Devkor_project.controller; + +import com.example.Devkor_project.configuration.VersionProvider; +import com.example.Devkor_project.dto.CommentDto; +import com.example.Devkor_project.dto.CourseDto; +import com.example.Devkor_project.dto.ResponseDto; +import com.example.Devkor_project.service.CourseService; +import com.example.Devkor_project.service.UpdateService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.security.Principal; +import java.util.List; + +@RestController +@RequiredArgsConstructor +@Tag(name = "업데이트", description = "변경되었지만 프론트 측에서 아직 조치를 취하지 않은 api입니다.") +public class UpdateController +{ + private final UpdateService updateService; + private final VersionProvider versionProvider; + + /* [변경] 강의 검색 컨트롤러 */ + @GetMapping("/api/update/course/search") + @Operation(summary = "[변경] 강의 검색", description = "**avg_rating, avg_r1_amount_of_studying, avg_r2_difficulty, avg_r3_delivery_power, avg_r4_grading**의 경우, 등록된 강의평이 존재하지 않는다면 0.0 값을 가집니다.\n\n**credit**의 경우, 값이 null일 수 있습니다.\n\n**time_locations**의 경우, 비어있거나 값이 여러 개일 수도 있습니다.\n\n**semester**의 경우 다음과 같은 값을 가집니다.\n- 1R : 1학기\n- 1S : 여름계절\n- 2R : 2학기\n- 2W : 겨울계절\n- M0 : Module0\n- M1 : Module1\n- M2 : Module2\n- M3 : Module3\n- M4 : Module4\n- M5 : Module5\n- M6 : Module6\n- M7 : Module7\n\n페이지 하나 당 10개의 결과를 반환합니다.") + @Parameters(value = { + @Parameter(name = "keyword", description = "검색어"), + @Parameter(name = "order", description = "검색 결과 배치 순서 ( NEWEST : 최신순 | RATING_DESC : 평점 높은순 | RATING_ASC : 평점 낮은순 )"), + @Parameter(name = "page", description = "페이지 번호 ( 1부터 시작 )") + }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200 (열람권 보유)", description = "CourseDto.Basic 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.UPDATED_Basic.class))), + @ApiResponse(responseCode = "200 (열람권 만료, 비로그인)", description = "CourseDto.ExpiredBasic 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.UPDATED_ExpiredBasic.class))), + @ApiResponse(responseCode = "실패: 400 (SHORT_SEARCH_WORD)", description = "검색어가 1글자 이하인 경우 (입력받은 검색어를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 400 (INVALID_ORDER)", description = "입력받은 order 인자가 올바르지 않은 경우 (입력받은 배치 순서를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (NO_RESULT)", description = "검색 결과가 존재하지 않는 경우 (입력받은 검색어를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (EMAIL_NOT_FOUND)", description = "요청을 보낸 사용자의 계정이 존재하지 않는 경우 (이메일을 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + }) + public ResponseEntity searchCourse(@RequestParam("keyword") String keyword, + @RequestParam("order") String order, + @RequestParam("page") int page, + Principal principal) + { + List courses = updateService.searchCourse(keyword, order, page - 1, principal); + + return ResponseEntity.status(HttpStatus.OK) + .body(ResponseDto.Success.builder() + .message("강의 검색이 성공적으로 수행되었습니다.") + .data(courses) + .version(versionProvider.getVersion()) + .build() + ); + } + + /* [변경] 강의 상세 정보 컨트롤러 */ + @GetMapping("api/update/course/detail") + @Operation(summary = "[변경] 강의 상세 정보", description = "**avg_rating, avg_r1_amount_of_studying, avg_r2_difficulty, avg_r3_delivery_power, avg_r4_grading**의 경우, 등록된 강의평이 존재하지 않는다면 0.0 값을 가집니다.\n\n**credit**의 경우, 값이 null일 수 있습니다.\n\n**time_locations**의 경우, 비어있거나 값이 여러 개일 수도 있습니다.\n\n**semester**의 경우 다음과 같은 값을 가집니다.\n- 1R : 1학기\n- 1S : 여름계절\n- 2R : 2학기\n- 2W : 겨울계절\n- M0 : Module0\n- M1 : Module1\n- M2 : Module2\n- M3 : Module3\n- M4 : Module4\n- M5 : Module5\n- M6 : Module6\n- M7 : Module7\n\n페이지 하나 당 10개의 강의평 정보를 반환합니다.") + @Parameters(value = { + @Parameter(name = "course_id", description = "상세 정보를 요청할 강의의 course_id"), + @Parameter(name = "order", description = "강의평 배치 순서 ( NEWEST : 최신순 | RATING_DESC : 평점 높은순 | RATING_ASC : 평점 낮은순 | LIKES_DESC : 좋아요 많은순 | LIKES_ASC : 좋아요 적은순 )"), + @Parameter(name = "page", description = "페이지 번호 ( 1부터 시작 )"), + }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200 (열람권 보유)", description = "CourseDto.Detail 데이터를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.UPDATED_Detail.class))), + @ApiResponse(responseCode = "실패: 401 (NO_ACCESS_AUTHORITY)", description = "강의평 열람권이 만료된 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (COURSE_NOT_FOUND)", description = "상세 정보를 요청한 course_id에 대한 강의가 존재하지 않는 경우 (입력받은 course_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (USER_NOT_FOUND)", description = "특정 강의평에 대한 사용자 데이터가 존재하지 않는 경우 (profile_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (COURSE_RATING_NOT_FOUND)", description = "특정 강의에 대한 평점 데이터가 존재하지 않는 경우 (courseRating_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (COMMENT_RATING_NOT_FOUND)", description = "특정 강의평에 대한 평점 데이터가 존재하지 않는 경우 (commentRating_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + }) + public ResponseEntity courseDetail(@RequestParam("course_id") Long course_id, + @RequestParam("order") String order, + @RequestParam("page") int page, + Principal principal) + { + Object dto = updateService.courseDetail(course_id, order, page - 1, principal); + + return ResponseEntity.status(HttpStatus.OK) + .body( + ResponseDto.Success.builder() + .message("강의 상세 정보가 성공적으로 반환되었습니다.") + .data(dto) + .version(versionProvider.getVersion()) + .build() + ); + } + + /* [변경] 강의평 작성 시작 컨트롤러 */ + @GetMapping("/api/update/course/start-insert-comment") + @Operation(summary = "[변경] 강의평 작성 시작") + @Parameters(value = { + @Parameter(in = ParameterIn.HEADER, name = "Authorization", description = "Bearer {access token}"), + @Parameter(name = "course_id", description = "강의평을 추가할 강의의 course_id") + }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "CourseDto.Basic 데이터를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.UPDATED_Basic.class))), + @ApiResponse(responseCode = "실패: 401 (UNAUTHORIZED)", description = "로그인하지 않은 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 400 (ALREADY_EXIST)", description = "해당 사용자가 해당 강의에 이미 강의평을 등록한 경우 (입력받은 course_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (COURSE_NOT_FOUND)", description = "요청으로 보낸 course_id에 해당하는 강의가 존재하지 않는 경우 (입력받은 course_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (EMAIL_NOT_FOUND)", description = "요청을 보낸 사용자의 계정이 존재하지 않는 경우 (이메일을 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + }) + public ResponseEntity startInsertComment(Principal principal, + @RequestParam("course_id") Long course_id) + { + CourseDto.UPDATED_Basic dto = updateService.startInsertComment(principal, course_id); + + return ResponseEntity.status(HttpStatus.OK) + .body( + ResponseDto.Success.builder() + .message("강의평 작성을 시작합니다.") + .data(dto) + .version(versionProvider.getVersion()) + .build() + ); + } + + /* [변경] 강의평 수정 시작 컨트롤러 */ + @GetMapping("/api/update/course/start-update-comment") + @Operation(summary = "[변경] 강의평 수정 시작") + @Parameters(value = { + @Parameter(in = ParameterIn.HEADER, name = "Authorization", description = "Bearer {access token}"), + @Parameter(name = "comment_id", description = "수정할 강의평의 comment_id") + }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "CommentDto.StartUpdate 데이터를 반환합니다.", content = @Content(schema = @Schema(implementation = CommentDto.UPDATED_StartUpdate.class))), + @ApiResponse(responseCode = "실패: 401 (UNAUTHORIZED)", description = "로그인하지 않은 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 400 (NOT_COMMENT_BY_USER)", description = "해당 강의평이 해당 사용자가 작성한 강의평이 아닌 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (COMMENT_NOT_FOUND)", description = "요청으로 보낸 comment_id에 해당하는 강의평이 존재하지 않는 경우 (입력받은 comment_id를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (EMAIL_NOT_FOUND)", description = "요청을 보낸 사용자의 계정이 존재하지 않는 경우 (이메일을 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + }) + public ResponseEntity startUpdateComment(Principal principal, + @RequestParam("comment_id") Long comment_id) + { + CommentDto.UPDATED_StartUpdate dto = updateService.startUpdateComment(principal, comment_id); + + return ResponseEntity.status(HttpStatus.OK) + .body( + ResponseDto.Success.builder() + .message("강의평 수정을 시작합니다.") + .data(dto) + .version(versionProvider.getVersion()) + .build() + ); + } + + /* [변경] 내가 작성한 강의평 정보 조회 컨트롤러 */ + @GetMapping("/api/update/mypage/my-comments") + @Operation(summary = "[변경] 내가 작성한 강의평 정보 조회", description = "페이지 하나 당 10개의 강의평 정보를 반환합니다.") + @Parameters(value = { + @Parameter(in = ParameterIn.HEADER, name = "Authorization", description = "Bearer {access token}"), + @Parameter(name = "page", description = "페이지 번호 ( 1부터 시작 )") + }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "CommentDto.MyPage 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CommentDto.UPDATED_MyPage.class))), + @ApiResponse(responseCode = "실패: 401 (UNAUTHORIZED)", description = "로그인하지 않은 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (EMAIL_NOT_FOUND)", description = "요청을 보낸 사용자 계정이 존재하지 않는 경우 (이메일을 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (NO_RESULT)", description = "결과가 없는 경우 (요청으로 보낸 page를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + }) + public ResponseEntity myComments(@RequestParam("page") int page, Principal principal) + { + List my_comments = updateService.myComments(principal, page - 1); + + return ResponseEntity.status(HttpStatus.OK) + .body( + ResponseDto.Success.builder() + .message("내가 작성한 강의평 정보 조회를 정상적으로 완료하였습니다.") + .data(my_comments) + .version(versionProvider.getVersion()) + .build() + ); + } + + /* [변경] 내가 북마크한 강의 정보 조회 컨트롤러 */ + @GetMapping("/api/update/mypage/my-bookmarks") + @Operation(summary = "[변경] 내가 북마크한 강의 정보 조회", description = "페이지 하나 당 10개의 강의 정보를 반환합니다.") + @Parameters(value = { + @Parameter(in = ParameterIn.HEADER, name = "Authorization", description = "Bearer {access token}"), + @Parameter(name = "page", description = "페이지 번호 ( 1부터 시작 )") + }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "CourseDto.Basic 리스트를 반환합니다.", content = @Content(schema = @Schema(implementation = CourseDto.UPDATED_Basic.class))), + @ApiResponse(responseCode = "실패: 401 (UNAUTHORIZED)", description = "로그인하지 않은 경우", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (EMAIL_NOT_FOUND)", description = "요청을 보낸 사용자 계정이 존재하지 않는 경우 (이메일을 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + @ApiResponse(responseCode = "실패: 404 (NO_RESULT)", description = "결과가 없는 경우 (요청으로 보낸 page를 반환)", content = @Content(schema = @Schema(implementation = ResponseDto.Error.class))), + }) + public ResponseEntity myBookmarks(@RequestParam("page") int page, Principal principal) + { + List my_bookmarks = updateService.myBookmarks(principal, page - 1); + + return ResponseEntity.status(HttpStatus.OK) + .body( + ResponseDto.Success.builder() + .message("내가 북마크한 강의 정보 조회를 정상적으로 완료하였습니다.") + .data(my_bookmarks) + .version(versionProvider.getVersion()) + .build() + ); + } +} diff --git a/src/main/java/com/example/Devkor_project/dto/CommentDto.java b/src/main/java/com/example/Devkor_project/dto/CommentDto.java index 5bc9267..ed80154 100644 --- a/src/main/java/com/example/Devkor_project/dto/CommentDto.java +++ b/src/main/java/com/example/Devkor_project/dto/CommentDto.java @@ -233,7 +233,147 @@ public static class Insert @ToString @Getter @Builder - public static class StartUpdate + public static class NOT_UPDATED_StartUpdate + { + // CourseDto.Basic + @NotNull(message = "course_id는 null일 수 없습니다.") + @Schema(description = "course_id") + private Long course_id; + @NotBlank(message = "course_code는 빈 문자열일 수 없습니다.") + @Schema(description = "학수번호") + private String course_code; + @NotBlank(message = "class_number는 빈 문자열일 수 없습니다.") + @Schema(description = "분반") + private String class_number; + @NotBlank(message = "graduate_school은 빈 문자열일 수 없습니다.") + @Schema(description = "대학원") + private String graduate_school; + @NotBlank(message = "department는 빈 문자열일 수 없습니다.") + @Schema(description = "학과") + private String department; + @NotBlank(message = "year은 빈 문자열일 수 없습니다.") + @Schema(description = "연도") + private String year; + @NotBlank(message = "semester은 빈 문자열일 수 없습니다.") + @Schema(description = "학기") + private String semester; + @NotBlank(message = "name은 빈 문자열일 수 없습니다.") + @Schema(description = "강의명") + private String name; + @NotBlank(message = "professor은 빈 문자열일 수 없습니다.") + @Schema(description = "교수명") + private String professor; + @Schema(description = "학점") + private String credit; + @Schema(description = "시간, 장소") + private String time_location; + @NotNull(message = "COUNT_comments는 null일 수 없습니다.") + @Schema(description = "강의평 개수") + private int COUNT_comments; + + @NotNull(message = "AVG_rating은 null일 수 없습니다.") + @Schema(description = "평균 평점") + private double AVG_rating; + @NotNull(message = "AVG_r1_amount_of_studying은 null일 수 없습니다.") + @Schema(description = "평균 학습량") + private double AVG_r1_amount_of_studying; + @NotNull(message = "AVG_r2_difficulty는 null일 수 없습니다.") + @Schema(description = "평균 난이도") + private double AVG_r2_difficulty; + @NotNull(message = "AVG_r3_delivery_power은 null일 수 없습니다.") + @Schema(description = "평균 전달력") + private double AVG_r3_delivery_power; + @NotNull(message = "AVG_r4_grading은 null일 수 없습니다.") + @Schema(description = "평균 성적 관대함") + private double AVG_r4_grading; + + @NotNull(message = "COUNT_teach_t1_theory는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-이론 강의 태그 개수") + private int COUNT_teach_t1_theory; + @NotNull(message = "COUNT_teach_t2_practice는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-실습 및 실험 태그 개수") + private int COUNT_teach_t2_practice; + @NotNull(message = "COUNT_teach_t3_seminar는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-세미나 태그 개수") + private int COUNT_teach_t3_seminar; + @NotNull(message = "COUNT_teach_t4_discussion는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-토론 태그 개수") + private int COUNT_teach_t4_discussion; + @NotNull(message = "COUNT_teach_t5_presentation는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-발표 태그 개수") + private int COUNT_teach_t5_presentation; + @NotNull(message = "COUNT_learn_t1_theory는 null일 수 없습니다.") + @Schema(description = "학습 내용-이론 지식 습득 태그 개수") + private int COUNT_learn_t1_theory; + @NotNull(message = "COUNT_learn_t2_thesis는 null일 수 없습니다.") + @Schema(description = "학습 내용-논문 작성 도움 태그 개수") + private int COUNT_learn_t2_thesis; + @NotNull(message = "COUNT_learn_t3_exam는 null일 수 없습니다.") + @Schema(description = "학습 내용-졸업 시험 대비 태그 개수") + private int COUNT_learn_t3_exam; + @NotNull(message = "COUNT_learn_t4_industry는 null일 수 없습니다.") + @Schema(description = "학습 내용-현업 적용 태그 개수") + private int COUNT_learn_t4_industry; + + // CommentDto.Update + @NotNull(message = "[comment_id] cannot be null.") + @Schema(description = "comment_id") + private Long comment_id; + + @NotNull(message = "[rating] cannot be null.") + @Schema(description = "평점") + private int rating; + @NotNull(message = "[r1_amount_of_studying] cannot be null.") + @Schema(description = "학습량") + private int r1_amount_of_studying; + @NotNull(message = "[r2_difficulty] cannot be null.") + @Schema(description = "난이도") + private int r2_difficulty; + @NotNull(message = "[r3_delivery_power] cannot be null.") + @Schema(description = "전달력") + private int r3_delivery_power; + @NotNull(message = "[r4_grading] cannot be null.") + @Schema(description = "성적 관대함") + private int r4_grading; + + @NotBlank(message = "[review] cannot be blank.") + @Schema(description = "강의평 내용") + private String review; + + @NotNull(message = "[teach_t1_theory] cannot be null.") + @Schema(description = "수업 진행방식-이론 강의 태그 선택 여부") + private boolean teach_t1_theory; + @NotNull(message = "[teach_t2_practice] cannot be null.") + @Schema(description = "수업 진행방식-실습 및 실험 태그 선택 여부") + private boolean teach_t2_practice; + @NotNull(message = "[teach_t3_seminar] cannot be null.") + @Schema(description = "수업 진행방식-세미나 태그 선택 여부") + private boolean teach_t3_seminar; + @NotNull(message = "[teach_t4_discussion] cannot be null.") + @Schema(description = "수업 진행방식-토론 태그 선택 여부") + private boolean teach_t4_discussion; + @NotNull(message = "[teach_t5_presentation] cannot be null.") + @Schema(description = "수업 진행방식-발표 태그 선택 여부") + private boolean teach_t5_presentation; + @NotNull(message = "[learn_t1_theory] cannot be null.") + @Schema(description = "학습 내용-이론 지식 습득 태그 선택 여부") + private boolean learn_t1_theory; + @NotNull(message = "[learn_t2_thesis] cannot be null.") + @Schema(description = "학습 내용-논문 작성 도움 태그 선택 여부") + private boolean learn_t2_thesis; + @NotNull(message = "[learn_t3_exam] cannot be null.") + @Schema(description = "학습 내용-졸업 시험 대비 태그 선택 여부") + private boolean learn_t3_exam; + @NotNull(message = "[learn_t4_industry] cannot be null.") + @Schema(description = "학습 내용-현업 적용 태그 선택 여부") + private boolean learn_t4_industry; + } + + @AllArgsConstructor + @ToString + @Getter + @Builder + public static class UPDATED_StartUpdate { // CourseDto.Basic @NotNull(message = "course_id는 null일 수 없습니다.") @@ -528,7 +668,110 @@ public static class ReportList @Getter @ToString @Builder - public static class MyPage + public static class NOT_UPDATED_MyPage + { + @NotNull(message = "[comment_id] cannot be null.") + @Schema(description = "comment_id") + private Long comment_id; + + @NotNull(message = "course_id는 null일 수 없습니다.") + @Schema(description = "course_id") + private Long course_id; + @NotBlank(message = "course_code는 빈 문자열일 수 없습니다.") + @Schema(description = "학수번호") + private String course_code; + @NotBlank(message = "class_number는 빈 문자열일 수 없습니다.") + @Schema(description = "분반") + private String class_number; + @NotBlank(message = "graduate_school은 빈 문자열일 수 없습니다.") + @Schema(description = "대학원") + private String graduate_school; + @NotBlank(message = "department는 빈 문자열일 수 없습니다.") + @Schema(description = "학과") + private String department; + @NotBlank(message = "year은 빈 문자열일 수 없습니다.") + @Schema(description = "연도") + private String year; + @NotBlank(message = "semester은 빈 문자열일 수 없습니다.") + @Schema(description = "학기") + private String semester; + @NotBlank(message = "name은 빈 문자열일 수 없습니다.") + @Schema(description = "강의명") + private String name; + @NotBlank(message = "professor은 빈 문자열일 수 없습니다.") + @Schema(description = "교수명") + private String professor; + @Schema(description = "학점") + private String credit; + @Schema(description = "시간, 장소") + private String time_location; + + @NotBlank(message = "[review] cannot be blank.") + @Schema(description = "강의평 내용") + private String review; + @NotNull(message = "[likes] cannot be null.") + @Schema(description = "좋아요 개수") + private int likes; + @NotNull(message = "[created_at] cannot be null.") + @Schema(description = "생성 날짜") + private LocalDate created_at; + @NotNull(message = "[updated_at] cannot be null.") + @Schema(description = "수정 날짜") + private LocalDate updated_at; + @Schema(description = "포인트 지급 여부") + @NotNull(message = "[reward] cannot be null.") + private boolean reward; + + @NotNull(message = "[rating] cannot be null.") + @Schema(description = "평점") + private int rating; + @NotNull(message = "[r1_amount_of_studying] cannot be null.") + @Schema(description = "학습량") + private int r1_amount_of_studying; + @NotNull(message = "[r2_difficulty] cannot be null.") + @Schema(description = "난이도") + private int r2_difficulty; + @NotNull(message = "[r3_delivery_power] cannot be null.") + @Schema(description = "전달력") + private int r3_delivery_power; + @NotNull(message = "[r4_grading] cannot be null.") + @Schema(description = "성적 관대함") + private int r4_grading; + + @NotNull(message = "[teach_t1_theory] cannot be null.") + @Schema(description = "수업 진행방식-이론 강의 태그 선택 여부") + private boolean teach_t1_theory; + @NotNull(message = "[teach_t2_practice] cannot be null.") + @Schema(description = "수업 진행방식-실습 및 실험 태그 선택 여부") + private boolean teach_t2_practice; + @NotNull(message = "[teach_t3_seminar] cannot be null.") + @Schema(description = "수업 진행방식-세미나 태그 선택 여부") + private boolean teach_t3_seminar; + @NotNull(message = "[teach_t4_discussion] cannot be null.") + @Schema(description = "수업 진행방식-토론 태그 선택 여부") + private boolean teach_t4_discussion; + @NotNull(message = "[teach_t5_presentation] cannot be null.") + @Schema(description = "수업 진행방식-발표 태그 선택 여부") + private boolean teach_t5_presentation; + @NotNull(message = "[learn_t1_theory] cannot be null.") + @Schema(description = "학습 내용-이론 지식 습득 태그 선택 여부") + private boolean learn_t1_theory; + @NotNull(message = "[learn_t2_thesis] cannot be null.") + @Schema(description = "학습 내용-논문 작성 도움 태그 선택 여부") + private boolean learn_t2_thesis; + @NotNull(message = "[learn_t3_exam] cannot be null.") + @Schema(description = "학습 내용-졸업 시험 대비 태그 선택 여부") + private boolean learn_t3_exam; + @NotNull(message = "[learn_t4_industry] cannot be null.") + @Schema(description = "학습 내용-현업 적용 태그 선택 여부") + private boolean learn_t4_industry; + } + + @AllArgsConstructor + @Getter + @ToString + @Builder + public static class UPDATED_MyPage { @NotNull(message = "[comment_id] cannot be null.") @Schema(description = "comment_id") @@ -627,15 +870,66 @@ public static class MyPage private boolean learn_t4_industry; } - public static CommentDto.StartUpdate entityToStartUpdate( + public static CommentDto.NOT_UPDATED_StartUpdate NOT_UPDATED_entityToStartUpdate( + Course course, + CourseRating courseRating, + com.example.Devkor_project.entity.Comment comment, + CommentRating commentRating) + { + return NOT_UPDATED_StartUpdate.builder() + .course_id(course.getCourse_id()) + .course_code(course.getCourse_code()) + .class_number(course.getClass_number()) + .graduate_school(course.getGraduate_school()) + .department(course.getDepartment()) + .year(course.getYear()) + .semester(course.getSemester()) + .name(course.getName()) + .professor(course.getProfessor()) + .credit(course.getCredit()) + .time_location(course.getTime_location()) + .COUNT_comments(course.getCOUNT_comments()) + .AVG_rating(courseRating.getAVG_rating()) + .AVG_r1_amount_of_studying(courseRating.getAVG_r1_amount_of_studying()) + .AVG_r2_difficulty(courseRating.getAVG_r2_difficulty()) + .AVG_r3_delivery_power(courseRating.getAVG_r3_delivery_power()) + .AVG_r4_grading(courseRating.getAVG_r4_grading()) + .COUNT_teach_t1_theory(courseRating.getCOUNT_teach_t1_theory()) + .COUNT_teach_t2_practice(courseRating.getCOUNT_teach_t2_practice()) + .COUNT_teach_t3_seminar(courseRating.getCOUNT_teach_t3_seminar()) + .COUNT_teach_t4_discussion(courseRating.getCOUNT_teach_t4_discussion()) + .COUNT_teach_t5_presentation(courseRating.getCOUNT_teach_t5_presentation()) + .COUNT_learn_t1_theory(courseRating.getCOUNT_learn_t1_theory()) + .COUNT_learn_t2_thesis(courseRating.getCOUNT_learn_t2_thesis()) + .COUNT_learn_t3_exam(courseRating.getCOUNT_learn_t3_exam()) + .COUNT_learn_t4_industry(courseRating.getCOUNT_learn_t4_industry()) + .comment_id(comment.getComment_id()) + .rating(commentRating.getRating()) + .r1_amount_of_studying(commentRating.getR1_amount_of_studying()) + .r2_difficulty(commentRating.getR2_difficulty()) + .r3_delivery_power(commentRating.getR3_delivery_power()) + .r4_grading(commentRating.getR4_grading()) + .review(comment.getReview()) + .teach_t1_theory(commentRating.isTeach_t1_theory()) + .teach_t2_practice(commentRating.isTeach_t2_practice()) + .teach_t3_seminar(commentRating.isTeach_t3_seminar()) + .teach_t4_discussion(commentRating.isTeach_t4_discussion()) + .teach_t5_presentation(commentRating.isTeach_t5_presentation()) + .learn_t1_theory(commentRating.isLearn_t1_theory()) + .learn_t2_thesis(commentRating.isLearn_t2_thesis()) + .learn_t3_exam(commentRating.isLearn_t3_exam()) + .learn_t4_industry(commentRating.isLearn_t4_industry()) + .build(); + } + + public static CommentDto.UPDATED_StartUpdate UPDATED_entityToStartUpdate( Course course, CourseRating courseRating, com.example.Devkor_project.entity.Comment comment, CommentRating commentRating, - List timeLocations - ) + List timeLocations) { - return StartUpdate.builder() + return UPDATED_StartUpdate.builder() .course_id(course.getCourse_id()) .course_code(course.getCourse_code()) .class_number(course.getClass_number()) @@ -692,14 +986,54 @@ public static CommentDto.StartUpdate entityToStartUpdate( .build(); } - public static CommentDto.MyPage entityToMyPage( + public static CommentDto.NOT_UPDATED_MyPage NOT_UPDATED_entityToMyPage( + com.example.Devkor_project.entity.Comment comment, + Course course, + CommentRating commentRating) + { + return NOT_UPDATED_MyPage.builder() + .comment_id(comment.getComment_id()) + .course_id(course.getCourse_id()) + .course_code(course.getCourse_code()) + .class_number(course.getClass_number()) + .graduate_school(course.getGraduate_school()) + .department(course.getDepartment()) + .year(course.getYear()) + .semester(course.getSemester()) + .name(course.getName()) + .professor(course.getProfessor()) + .credit(course.getCredit()) + .time_location(course.getTime_location()) + .review(comment.getReview()) + .likes(comment.getLikes()) + .created_at(comment.getCreated_at()) + .updated_at(comment.getUpdated_at()) + .reward(comment.isReward()) + .rating(commentRating.getRating()) + .r1_amount_of_studying(commentRating.getR1_amount_of_studying()) + .r2_difficulty(commentRating.getR2_difficulty()) + .r3_delivery_power(commentRating.getR3_delivery_power()) + .r4_grading(commentRating.getR4_grading()) + .teach_t1_theory(commentRating.isTeach_t1_theory()) + .teach_t2_practice(commentRating.isTeach_t2_practice()) + .teach_t3_seminar(commentRating.isTeach_t3_seminar()) + .teach_t4_discussion(commentRating.isTeach_t4_discussion()) + .teach_t5_presentation(commentRating.isTeach_t5_presentation()) + .learn_t1_theory(commentRating.isLearn_t1_theory()) + .learn_t2_thesis(commentRating.isLearn_t2_thesis()) + .learn_t3_exam(commentRating.isLearn_t3_exam()) + .learn_t4_industry(commentRating.isLearn_t4_industry()) + .build(); + } + + public static CommentDto.UPDATED_MyPage UPDATED_entityToMyPage( com.example.Devkor_project.entity.Comment comment, Course course, CommentRating commentRating, List timeLocations ) { - return MyPage.builder() + return UPDATED_MyPage.builder() .comment_id(comment.getComment_id()) .course_id(course.getCourse_id()) .course_code(course.getCourse_code()) diff --git a/src/main/java/com/example/Devkor_project/dto/CourseDto.java b/src/main/java/com/example/Devkor_project/dto/CourseDto.java index 3d8198a..d29666d 100644 --- a/src/main/java/com/example/Devkor_project/dto/CourseDto.java +++ b/src/main/java/com/example/Devkor_project/dto/CourseDto.java @@ -18,7 +18,96 @@ public class CourseDto @Getter @ToString @Builder - public static class Basic + public static class NOT_UPDATED_Basic + { + @NotNull(message = "course_id는 null일 수 없습니다.") + @Schema(description = "course_id") + private Long course_id; + @NotBlank(message = "course_code는 빈 문자열일 수 없습니다.") + @Schema(description = "학수번호") + private String course_code; + @NotBlank(message = "class_number는 빈 문자열일 수 없습니다.") + @Schema(description = "분반") + private String class_number; + @NotBlank(message = "graduate_school은 빈 문자열일 수 없습니다.") + @Schema(description = "대학원") + private String graduate_school; + @NotBlank(message = "department는 빈 문자열일 수 없습니다.") + @Schema(description = "학과") + private String department; + @NotBlank(message = "year은 빈 문자열일 수 없습니다.") + @Schema(description = "연도") + private String year; + @NotBlank(message = "semester은 빈 문자열일 수 없습니다.") + @Schema(description = "학기") + private String semester; + @NotBlank(message = "name은 빈 문자열일 수 없습니다.") + @Schema(description = "강의명") + private String name; + @NotBlank(message = "professor은 빈 문자열일 수 없습니다.") + @Schema(description = "교수명") + private String professor; + @Schema(description = "학점") + private String credit; + @Schema(description = "시간, 장소") + private String time_location; + @NotNull(message = "COUNT_comments는 null일 수 없습니다.") + @Schema(description = "강의평 개수") + private int COUNT_comments; + @Schema(description = "북마크 여부") + private Boolean isBookmark; + + @NotNull(message = "AVG_rating은 null일 수 없습니다.") + @Schema(description = "평균 평점") + private double AVG_rating; + @NotNull(message = "AVG_r1_amount_of_studying은 null일 수 없습니다.") + @Schema(description = "평균 학습량") + private double AVG_r1_amount_of_studying; + @NotNull(message = "AVG_r2_difficulty는 null일 수 없습니다.") + @Schema(description = "평균 난이도") + private double AVG_r2_difficulty; + @NotNull(message = "AVG_r3_delivery_power은 null일 수 없습니다.") + @Schema(description = "평균 전달력") + private double AVG_r3_delivery_power; + @NotNull(message = "AVG_r4_grading은 null일 수 없습니다.") + @Schema(description = "평균 성적 관대함") + private double AVG_r4_grading; + + @NotNull(message = "COUNT_teach_t1_theory는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-이론 강의 태그 개수") + private int COUNT_teach_t1_theory; + @NotNull(message = "COUNT_teach_t2_practice는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-실습 및 실험 태그 개수") + private int COUNT_teach_t2_practice; + @NotNull(message = "COUNT_teach_t3_seminar는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-세미나 태그 개수") + private int COUNT_teach_t3_seminar; + @NotNull(message = "COUNT_teach_t4_discussion는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-토론 태그 개수") + private int COUNT_teach_t4_discussion; + @NotNull(message = "COUNT_teach_t5_presentation는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-발표 태그 개수") + private int COUNT_teach_t5_presentation; + @NotNull(message = "COUNT_learn_t1_theory는 null일 수 없습니다.") + @Schema(description = "학습 내용-이론 지식 습득 태그 개수") + private int COUNT_learn_t1_theory; + @NotNull(message = "COUNT_learn_t2_thesis는 null일 수 없습니다.") + @Schema(description = "학습 내용-논문 작성 도움 태그 개수") + private int COUNT_learn_t2_thesis; + @NotNull(message = "COUNT_learn_t3_exam는 null일 수 없습니다.") + @Schema(description = "학습 내용-졸업 시험 대비 태그 개수") + private int COUNT_learn_t3_exam; + @NotNull(message = "COUNT_learn_t4_industry는 null일 수 없습니다.") + @Schema(description = "학습 내용-현업 적용 태그 개수") + private int COUNT_learn_t4_industry; + } + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @ToString + @Builder + public static class UPDATED_Basic { @NotNull(message = "course_id는 null일 수 없습니다.") @Schema(description = "course_id") @@ -107,7 +196,52 @@ public static class Basic @Getter @ToString @Builder - public static class ExpiredBasic + public static class NOT_UPDATED_ExpiredBasic + { + @NotNull(message = "course_id는 null일 수 없습니다.") + @Schema(description = "course_id") + private Long course_id; + @NotBlank(message = "course_code는 빈 문자열일 수 없습니다.") + @Schema(description = "학수번호") + private String course_code; + @NotBlank(message = "class_number는 빈 문자열일 수 없습니다.") + @Schema(description = "분반") + private String class_number; + @NotBlank(message = "graduate_school은 빈 문자열일 수 없습니다.") + @Schema(description = "대학원") + private String graduate_school; + @NotBlank(message = "department는 빈 문자열일 수 없습니다.") + @Schema(description = "학과") + private String department; + @NotBlank(message = "year은 빈 문자열일 수 없습니다.") + @Schema(description = "연도") + private String year; + @NotBlank(message = "semester은 빈 문자열일 수 없습니다.") + @Schema(description = "학기") + private String semester; + @NotBlank(message = "name은 빈 문자열일 수 없습니다.") + @Schema(description = "강의명") + private String name; + @NotBlank(message = "professor은 빈 문자열일 수 없습니다.") + @Schema(description = "교수명") + private String professor; + @Schema(description = "학점") + private String credit; + @Schema(description = "시간, 장소") + private String time_location; + @NotNull(message = "COUNT_comments는 null일 수 없습니다.") + @Schema(description = "강의평 개수") + private int COUNT_comments; + @Schema(description = "북마크 여부") + private Boolean isBookmark; + } + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @ToString + @Builder + public static class UPDATED_ExpiredBasic { @NotNull(message = "course_id는 null일 수 없습니다.") @Schema(description = "course_id") @@ -152,7 +286,99 @@ public static class ExpiredBasic @Getter @ToString @Builder - public static class Detail + public static class NOT_UPDATED_Detail + { + @NotNull(message = "course_id는 null일 수 없습니다.") + @Schema(description = "course_id") + private Long course_id; + @NotBlank(message = "course_code는 빈 문자열일 수 없습니다.") + @Schema(description = "학수번호") + private String course_code; + @NotBlank(message = "class_number는 빈 문자열일 수 없습니다.") + @Schema(description = "분반") + private String class_number; + @NotBlank(message = "graduate_school은 빈 문자열일 수 없습니다.") + @Schema(description = "대학원") + private String graduate_school; + @NotBlank(message = "department는 빈 문자열일 수 없습니다.") + @Schema(description = "학과") + private String department; + @NotBlank(message = "year은 빈 문자열일 수 없습니다.") + @Schema(description = "연도") + private String year; + @NotBlank(message = "semester은 빈 문자열일 수 없습니다.") + @Schema(description = "학기") + private String semester; + @NotBlank(message = "name은 빈 문자열일 수 없습니다.") + @Schema(description = "강의명") + private String name; + @NotBlank(message = "professor은 빈 문자열일 수 없습니다.") + @Schema(description = "교수명") + private String professor; + @Schema(description = "학점") + private String credit; + @Schema(description = "시간, 장소") + private String time_location; + @NotNull(message = "COUNT_comments는 null일 수 없습니다.") + @Schema(description = "강의평 개수") + private int COUNT_comments; + @Schema(description = "북마크 여부") + private Boolean isBookmark; + + @NotNull(message = "AVG_rating은 null일 수 없습니다.") + @Schema(description = "평균 평점") + private double AVG_rating; + @NotNull(message = "AVG_r1_amount_of_studying은 null일 수 없습니다.") + @Schema(description = "평균 학습량") + private double AVG_r1_amount_of_studying; + @NotNull(message = "AVG_r2_difficulty는 null일 수 없습니다.") + @Schema(description = "평균 난이도") + private double AVG_r2_difficulty; + @NotNull(message = "AVG_r3_delivery_power은 null일 수 없습니다.") + @Schema(description = "평균 전달력") + private double AVG_r3_delivery_power; + @NotNull(message = "AVG_r4_grading은 null일 수 없습니다.") + @Schema(description = "평균 성적 관대함") + private double AVG_r4_grading; + + @NotNull(message = "COUNT_teach_t1_theory는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-이론 강의 태그 개수") + private int COUNT_teach_t1_theory; + @NotNull(message = "COUNT_teach_t2_practice는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-실습 및 실험 태그 개수") + private int COUNT_teach_t2_practice; + @NotNull(message = "COUNT_teach_t3_seminar는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-세미나 태그 개수") + private int COUNT_teach_t3_seminar; + @NotNull(message = "COUNT_teach_t4_discussion는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-토론 태그 개수") + private int COUNT_teach_t4_discussion; + @NotNull(message = "COUNT_teach_t5_presentation는 null일 수 없습니다.") + @Schema(description = "수업 진행방식-발표 태그 개수") + private int COUNT_teach_t5_presentation; + @NotNull(message = "COUNT_learn_t1_theory는 null일 수 없습니다.") + @Schema(description = "학습 내용-이론 지식 습득 태그 개수") + private int COUNT_learn_t1_theory; + @NotNull(message = "COUNT_learn_t2_thesis는 null일 수 없습니다.") + @Schema(description = "학습 내용-논문 작성 도움 태그 개수") + private int COUNT_learn_t2_thesis; + @NotNull(message = "COUNT_learn_t3_exam는 null일 수 없습니다.") + @Schema(description = "학습 내용-졸업 시험 대비 태그 개수") + private int COUNT_learn_t3_exam; + @NotNull(message = "COUNT_learn_t4_industry는 null일 수 없습니다.") + @Schema(description = "학습 내용-현업 적용 태그 개수") + private int COUNT_learn_t4_industry; + + @Schema(description = "강의평 리스트") + private List comments; + } + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @ToString + @Builder + public static class UPDATED_Detail { @NotNull(message = "course_id는 null일 수 없습니다.") @Schema(description = "course_id") @@ -244,7 +470,52 @@ public static class Detail @Getter @ToString @Builder - public static class ExpiredDetail + public static class NOT_UPDATED_ExpiredDetail + { + @NotNull(message = "course_id는 null일 수 없습니다.") + @Schema(description = "course_id") + private Long course_id; + @NotBlank(message = "course_code는 빈 문자열일 수 없습니다.") + @Schema(description = "학수번호") + private String course_code; + @NotBlank(message = "class_number는 빈 문자열일 수 없습니다.") + @Schema(description = "분반") + private String class_number; + @NotBlank(message = "graduate_school은 빈 문자열일 수 없습니다.") + @Schema(description = "대학원") + private String graduate_school; + @NotBlank(message = "department는 빈 문자열일 수 없습니다.") + @Schema(description = "학과") + private String department; + @NotBlank(message = "year은 빈 문자열일 수 없습니다.") + @Schema(description = "연도") + private String year; + @NotBlank(message = "semester은 빈 문자열일 수 없습니다.") + @Schema(description = "학기") + private String semester; + @NotBlank(message = "name은 빈 문자열일 수 없습니다.") + @Schema(description = "강의명") + private String name; + @NotBlank(message = "professor은 빈 문자열일 수 없습니다.") + @Schema(description = "교수명") + private String professor; + @Schema(description = "학점") + private String credit; + @Schema(description = "시간, 장소") + private String time_location; + @NotNull(message = "COUNT_comments는 null일 수 없습니다.") + @Schema(description = "강의평 개수") + private int COUNT_comments; + @Schema(description = "북마크 여부") + private Boolean isBookmark; + } + + @AllArgsConstructor + @NoArgsConstructor + @Getter + @ToString + @Builder + public static class UPDATED_ExpiredDetail { @NotNull(message = "course_id는 null일 수 없습니다.") @Schema(description = "course_id") @@ -325,14 +596,50 @@ public static class TimeLocation private String location; } - public static CourseDto.Basic entityToBasic( + public static CourseDto.NOT_UPDATED_Basic NOT_UPDATED_entityToBasic( + Course course, + CourseRating courseRating, + Boolean isBookmark) + { + return NOT_UPDATED_Basic.builder() + .course_id(course.getCourse_id()) + .course_code(course.getCourse_code()) + .class_number(course.getClass_number()) + .graduate_school(course.getGraduate_school()) + .department(course.getDepartment()) + .year(course.getYear()) + .semester(course.getSemester()) + .name(course.getName()) + .professor(course.getProfessor()) + .credit(course.getCredit()) + .time_location(course.getTime_location()) + .COUNT_comments(course.getCOUNT_comments()) + .isBookmark(isBookmark) + .AVG_rating(courseRating.getAVG_rating()) + .AVG_r1_amount_of_studying(courseRating.getAVG_r1_amount_of_studying()) + .AVG_r2_difficulty(courseRating.getAVG_r2_difficulty()) + .AVG_r3_delivery_power(courseRating.getAVG_r3_delivery_power()) + .AVG_r4_grading(courseRating.getAVG_r4_grading()) + .COUNT_teach_t1_theory(courseRating.getCOUNT_teach_t1_theory()) + .COUNT_teach_t2_practice(courseRating.getCOUNT_teach_t2_practice()) + .COUNT_teach_t3_seminar(courseRating.getCOUNT_teach_t3_seminar()) + .COUNT_teach_t4_discussion(courseRating.getCOUNT_teach_t4_discussion()) + .COUNT_teach_t5_presentation(courseRating.getCOUNT_teach_t5_presentation()) + .COUNT_learn_t1_theory(courseRating.getCOUNT_learn_t1_theory()) + .COUNT_learn_t2_thesis(courseRating.getCOUNT_learn_t2_thesis()) + .COUNT_learn_t3_exam(courseRating.getCOUNT_learn_t3_exam()) + .COUNT_learn_t4_industry(courseRating.getCOUNT_learn_t4_industry()) + .build(); + } + + public static CourseDto.UPDATED_Basic UPDATED_entityToBasic( Course course, CourseRating courseRating, List timeLocations, Boolean isBookmark ) { - return Basic.builder() + return UPDATED_Basic.builder() .course_id(course.getCourse_id()) .course_code(course.getCourse_code()) .class_number(course.getClass_number()) @@ -374,13 +681,34 @@ public static CourseDto.Basic entityToBasic( .build(); } - public static CourseDto.ExpiredBasic entityToExpiredBasic( + public static CourseDto.NOT_UPDATED_ExpiredBasic NOT_UPDATED_entityToExpiredBasic( + Course course, + Boolean isBookmark) + { + return NOT_UPDATED_ExpiredBasic.builder() + .course_id(course.getCourse_id()) + .course_code(course.getCourse_code()) + .class_number(course.getClass_number()) + .graduate_school(course.getGraduate_school()) + .department(course.getDepartment()) + .year(course.getYear()) + .semester(course.getSemester()) + .name(course.getName()) + .professor(course.getProfessor()) + .credit(course.getCredit()) + .time_location(course.getTime_location()) + .COUNT_comments(course.getCOUNT_comments()) + .isBookmark(isBookmark) + .build(); + } + + public static CourseDto.UPDATED_ExpiredBasic UPDATED_entityToExpiredBasic( Course course, List timeLocations, Boolean isBookmark ) { - return ExpiredBasic.builder() + return UPDATED_ExpiredBasic.builder() .course_id(course.getCourse_id()) .course_code(course.getCourse_code()) .class_number(course.getClass_number()) @@ -408,15 +736,52 @@ public static CourseDto.ExpiredBasic entityToExpiredBasic( .build(); } - public static CourseDto.Detail entityToDetail( + public static CourseDto.NOT_UPDATED_Detail NOT_UPDATED_entityToDetail( + Course course, + CourseRating courseRating, + List commentDtos, + Boolean isBookmark) + { + return NOT_UPDATED_Detail.builder() + .course_id(course.getCourse_id()) + .course_code(course.getCourse_code()) + .class_number(course.getClass_number()) + .graduate_school(course.getGraduate_school()) + .department(course.getDepartment()) + .year(course.getYear()) + .semester(course.getSemester()) + .name(course.getName()) + .professor(course.getProfessor()) + .credit(course.getCredit()) + .time_location(course.getTime_location()) + .COUNT_comments(course.getCOUNT_comments()) + .isBookmark(isBookmark) + .AVG_rating(courseRating.getAVG_rating()) + .AVG_r1_amount_of_studying(courseRating.getAVG_r1_amount_of_studying()) + .AVG_r2_difficulty(courseRating.getAVG_r2_difficulty()) + .AVG_r3_delivery_power(courseRating.getAVG_r3_delivery_power()) + .AVG_r4_grading(courseRating.getAVG_r4_grading()) + .COUNT_teach_t1_theory(courseRating.getCOUNT_teach_t1_theory()) + .COUNT_teach_t2_practice(courseRating.getCOUNT_teach_t2_practice()) + .COUNT_teach_t3_seminar(courseRating.getCOUNT_teach_t3_seminar()) + .COUNT_teach_t4_discussion(courseRating.getCOUNT_teach_t4_discussion()) + .COUNT_teach_t5_presentation(courseRating.getCOUNT_teach_t5_presentation()) + .COUNT_learn_t1_theory(courseRating.getCOUNT_learn_t1_theory()) + .COUNT_learn_t2_thesis(courseRating.getCOUNT_learn_t2_thesis()) + .COUNT_learn_t3_exam(courseRating.getCOUNT_learn_t3_exam()) + .COUNT_learn_t4_industry(courseRating.getCOUNT_learn_t4_industry()) + .comments(commentDtos) + .build(); + } + + public static CourseDto.UPDATED_Detail UPDATED_entityToDetail( Course course, CourseRating courseRating, List commentDtos, List timeLocations, - Boolean isBookmark - ) + Boolean isBookmark) { - return Detail.builder() + return UPDATED_Detail.builder() .course_id(course.getCourse_id()) .course_code(course.getCourse_code()) .class_number(course.getClass_number()) @@ -459,13 +824,33 @@ public static CourseDto.Detail entityToDetail( .build(); } - public static CourseDto.ExpiredDetail entityToExpiredDetail( + public static CourseDto.NOT_UPDATED_ExpiredDetail NOT_UPDATED_entityToExpiredDetail( + Course course, + Boolean isBookmark) + { + return NOT_UPDATED_ExpiredDetail.builder() + .course_id(course.getCourse_id()) + .course_code(course.getCourse_code()) + .class_number(course.getClass_number()) + .graduate_school(course.getGraduate_school()) + .department(course.getDepartment()) + .year(course.getYear()) + .semester(course.getSemester()) + .name(course.getName()) + .professor(course.getProfessor()) + .credit(course.getCredit()) + .time_location(course.getTime_location()) + .COUNT_comments(course.getCOUNT_comments()) + .isBookmark(isBookmark) + .build(); + } + + public static CourseDto.UPDATED_ExpiredDetail UPDATED_entityToExpiredDetail( Course course, List timeLocations, - Boolean isBookmark - ) + Boolean isBookmark) { - return ExpiredDetail.builder() + return UPDATED_ExpiredDetail.builder() .course_id(course.getCourse_id()) .course_code(course.getCourse_code()) .class_number(course.getClass_number()) diff --git a/src/main/java/com/example/Devkor_project/entity/Course.java b/src/main/java/com/example/Devkor_project/entity/Course.java index 73f1e81..dd730ef 100644 --- a/src/main/java/com/example/Devkor_project/entity/Course.java +++ b/src/main/java/com/example/Devkor_project/entity/Course.java @@ -35,5 +35,6 @@ public class Course @Column(nullable = false) private String year; @Column(nullable = false) private String semester; @Column private String credit; + @Column private String time_location; @Column(nullable = false) private int COUNT_comments; } diff --git a/src/main/java/com/example/Devkor_project/service/CourseService.java b/src/main/java/com/example/Devkor_project/service/CourseService.java index 47cc5ec..e49ff89 100644 --- a/src/main/java/com/example/Devkor_project/service/CourseService.java +++ b/src/main/java/com/example/Devkor_project/service/CourseService.java @@ -32,7 +32,6 @@ public class CourseService private final CommentRatingRepository commentRatingRepository; private final CommentLikeRepository commentLikeRepository; private final CommentReportRepository commentReportRepository; - private final TimeLocationRepository timeLocationRepository; /* 강의 검색 서비스 */ public List searchCourse(String keyword, String order, int page, Principal principal) @@ -64,13 +63,9 @@ else if(order.equals("RATING_ASC")) if(principal == null) { // Course 엔티티 리스트 -> courseDto.ExpiredBasic 리스트 - List courseDtos = courses.stream() + List courseDtos = courses.stream() .map(course -> { - - // 강의 시간 및 장소 정보 - List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); - - return CourseDto.entityToExpiredBasic(course, timeLocations, false); + return CourseDto.NOT_UPDATED_entityToExpiredBasic(course, false); }) .toList(); @@ -89,19 +84,16 @@ else if(order.equals("RATING_ASC")) if(profile.getAccess_expiration_date().isAfter(LocalDate.now())) { // Course 엔티티 리스트 -> courseDto.Basic 리스트 - List courseDtos = courses.stream() + List courseDtos = courses.stream() .map(course -> { // 해당 강의의 평점 데이터 CourseRating courseRating = course.getCourseRating_id(); - // 강의 시간 및 장소 정보 - List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); - // 사용자의 해당 강의 북마크 여부 boolean isBookmark = !bookmarkRepository.searchBookmark(profile_id, course.getCourse_id()).isEmpty(); - return CourseDto.entityToBasic(course, courseRating, timeLocations, isBookmark); + return CourseDto.NOT_UPDATED_entityToBasic(course, courseRating, isBookmark); }) .toList(); @@ -110,16 +102,12 @@ else if(order.equals("RATING_ASC")) else { // Course 엔티티 리스트 -> courseDto.ExpiredBasic 리스트 - List courseDtos = courses.stream() + List courseDtos = courses.stream() .map(course -> { - - // 강의 시간 및 장소 정보 - List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); - // 사용자의 해당 강의 북마크 여부 boolean isBookmark = !bookmarkRepository.searchBookmark(profile_id, course.getCourse_id()).isEmpty(); - return CourseDto.entityToExpiredBasic(course, timeLocations, isBookmark); + return CourseDto.NOT_UPDATED_entityToExpiredBasic(course, isBookmark); }) .toList(); @@ -152,14 +140,11 @@ public Object courseDetail(Long course_id, String order, int page, Principal pri Course course = courseRepository.findById(course_id) .orElseThrow(() -> new AppException(ErrorCode.COURSE_NOT_FOUND, course_id)); - // 강의 시간 및 장소 정보 - List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); - // 비로그인 시, 평점 데이터와 강의평 리스트를 전달하지 않으며, 북마크 여부가 항상 false if(principal == null) { // CourseDto.ExpiredDetail 반환 - return CourseDto.entityToExpiredDetail(course, timeLocations, false); + return CourseDto.NOT_UPDATED_entityToExpiredDetail(course, false); } else { @@ -242,7 +227,7 @@ else if(order.equals("LIKES_ASC")) boolean isBookmark = !bookmarkRepository.searchBookmark(principalProfile_id, course.getCourse_id()).isEmpty(); // course 엔티티와 강의평 dto 리스트로 CourseDto.Detail 만들어서 반환 - return CourseDto.entityToDetail(course, courseRating, commentDtos, timeLocations, isBookmark); + return CourseDto.NOT_UPDATED_entityToDetail(course, courseRating, commentDtos, isBookmark); } else { @@ -250,7 +235,7 @@ else if(order.equals("LIKES_ASC")) boolean isBookmark = !bookmarkRepository.searchBookmark(principalProfile_id, course.getCourse_id()).isEmpty(); // CourseDto.ExpiredDetail 반환 - return CourseDto.entityToExpiredDetail(course, timeLocations, isBookmark); + return CourseDto.NOT_UPDATED_entityToExpiredDetail(course, isBookmark); } } } @@ -290,7 +275,7 @@ public void bookmark(Principal principal, Long course_id) } /* 강의평 작성 시작 서비스 */ - public CourseDto.Basic startInsertComment(Principal principal, Long course_id) + public CourseDto.NOT_UPDATED_Basic startInsertComment(Principal principal, Long course_id) { // 강의평 작성 시작 요청을 보낸 사용자의 계정 이메일 String email = principal.getName(); @@ -303,9 +288,6 @@ public CourseDto.Basic startInsertComment(Principal principal, Long course_id) Course course = courseRepository.findById(course_id) .orElseThrow(() -> new AppException(ErrorCode.COURSE_NOT_FOUND, course_id)); - // 강의 시간 및 장소 정보 - List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); - // 해당 사용자가 이미 해당 강의에 강의평을 달았다면, 예외 처리 List comment = commentRepository.searchComment(profile.getProfile_id(), course_id); if(!comment.isEmpty()) @@ -317,7 +299,7 @@ public CourseDto.Basic startInsertComment(Principal principal, Long course_id) // 사용자의 해당 강의 북마크 여부 boolean isBookmark = !bookmarkRepository.searchBookmark(profile.getProfile_id(), course.getCourse_id()).isEmpty(); - return CourseDto.entityToBasic(course, courseRating, timeLocations, isBookmark); + return CourseDto.NOT_UPDATED_entityToBasic(course, courseRating, isBookmark); } /* 강의평 작성 완료 및 등록 서비스 */ @@ -426,7 +408,7 @@ public void insertComment(Principal principal, CommentDto.Insert dto) } /* 강의평 수정 시작 서비스 */ - public CommentDto.StartUpdate startUpdateComment(Principal principal, Long comment_id) + public CommentDto.NOT_UPDATED_StartUpdate startUpdateComment(Principal principal, Long comment_id) { // 강의평 작성 시작 요청을 보낸 사용자의 계정 이메일 String email = principal.getName(); @@ -445,16 +427,13 @@ public CommentDto.StartUpdate startUpdateComment(Principal principal, Long comme // 강의 평점 정보 CourseRating courseRating = course.getCourseRating_id(); - // 강의 시간 및 장소 정보 - List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); - // 해당 강의평이 해당 사용자가 작성한 강의평이 아니라면, 예외 처리 if(!Objects.equals(comment.getProfile_id().getProfile_id(), profile.getProfile_id())) throw new AppException(ErrorCode.NOT_COMMENT_BY_USER, null); CommentRating commentRating = comment.getCommentRating_id(); - return CommentDto.entityToStartUpdate(course, courseRating, comment, commentRating, timeLocations); + return CommentDto.NOT_UPDATED_entityToStartUpdate(course, courseRating, comment, commentRating); } /* 강의평 수정 완료 서비스 */ diff --git a/src/main/java/com/example/Devkor_project/service/MyPageService.java b/src/main/java/com/example/Devkor_project/service/MyPageService.java index 3d91b3f..7d3267c 100644 --- a/src/main/java/com/example/Devkor_project/service/MyPageService.java +++ b/src/main/java/com/example/Devkor_project/service/MyPageService.java @@ -27,11 +27,7 @@ public class MyPageService { private final ProfileRepository profileRepository; private final BookmarkRepository bookmarkRepository; - private final CourseRepository courseRepository; private final CommentRepository commentRepository; - private final CourseRatingRepository courseRatingRepository; - private final CommentRatingRepository commentRatingRepository; - private final TimeLocationRepository timeLocationRepository; private final BCryptPasswordEncoder encoder; /* 마이페이지 기본 정보 서비스 */ @@ -118,7 +114,7 @@ else if(Objects.equals(dto.getItem(), "180DAYS")) { } /* 내가 작성한 강의평 정보 조회 서비스 */ - public List myComments(Principal principal, int page) + public List myComments(Principal principal, int page) { // 요청을 보낸 사용자의 계정 이메일 String email = principal.getName(); @@ -138,15 +134,12 @@ public List myComments(Principal principal, int page) throw new AppException(ErrorCode.NO_RESULT, page + 1); // 강의평 엔티티 페이지를 강의평 dto 리스트로 변환 - List commentDtos = comments.stream() + List commentDtos = comments.stream() .map(comment -> { - Course course = comment.getCourse_id(); // 강의 정보 CommentRating commentRating = comment.getCommentRating_id(); // 강의평 평점 정보 - List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); // 강의 시간 및 장소 정보 - - return CommentDto.entityToMyPage(comment, course, commentRating, timeLocations); + return CommentDto.NOT_UPDATED_entityToMyPage(comment, course, commentRating); }) .toList(); @@ -168,7 +161,7 @@ public int countMyComments(Principal principal) } /* 내가 북마크한 강의 정보 조회 서비스 */ - public List myBookmarks(Principal principal, int page) + public List myBookmarks(Principal principal, int page) { // 요청을 보낸 사용자의 계정 이메일 String email = principal.getName(); @@ -188,18 +181,15 @@ public List myBookmarks(Principal principal, int page) throw new AppException(ErrorCode.NO_RESULT, page + 1); // 강의 엔티티 페이지를 강의 dto 리스트로 변환 - List courseDtos = bookmarks.stream() + List courseDtos = bookmarks.stream() .map(bookmark -> { - Course course = bookmark.getCourse_id(); // 강의 정보 CourseRating courseRating = course.getCourseRating_id(); // 강의 평점 정보 - List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); // 강의 시간 및 장소 정보 // 사용자의 해당 강의 북마크 여부 boolean isBookmark = !bookmarkRepository.searchBookmark(profile.getProfile_id(), course.getCourse_id()).isEmpty(); - return CourseDto.entityToBasic(course, courseRating, timeLocations, isBookmark); - + return CourseDto.NOT_UPDATED_entityToBasic(course, courseRating, isBookmark); }) .toList(); diff --git a/src/main/java/com/example/Devkor_project/service/UpdateService.java b/src/main/java/com/example/Devkor_project/service/UpdateService.java new file mode 100644 index 0000000..4071947 --- /dev/null +++ b/src/main/java/com/example/Devkor_project/service/UpdateService.java @@ -0,0 +1,375 @@ +package com.example.Devkor_project.service; + +import com.example.Devkor_project.dto.CommentDto; +import com.example.Devkor_project.dto.CourseDto; +import com.example.Devkor_project.entity.*; +import com.example.Devkor_project.exception.AppException; +import com.example.Devkor_project.exception.ErrorCode; +import com.example.Devkor_project.repository.*; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; + +import java.security.Principal; +import java.time.LocalDate; +import java.util.List; +import java.util.Objects; + +@Service +@RequiredArgsConstructor +public class UpdateService +{ + private final ProfileRepository profileRepository; + private final CourseRepository courseRepository; + private final CourseRatingRepository courseRatingRepository; + private final BookmarkRepository bookmarkRepository; + private final CommentRepository commentRepository; + private final CommentRatingRepository commentRatingRepository; + private final CommentLikeRepository commentLikeRepository; + private final TimeLocationRepository timeLocationRepository; + + /* [변경] 강의 검색 서비스 */ + public List searchCourse(String keyword, String order, int page, Principal principal) + { + // 검색어가 2글자 미만이면 예외 발생 + if(keyword.length() < 2) + throw new AppException(ErrorCode.SHORT_SEARCH_WORD, keyword); + + // Pageable 객체 생성 (size = 10개) + Pageable pageable = PageRequest.of(page, 10); + + // 강의명+교수명+학수번호 검색 후, Course 엔티티 리스트 생성 + Page courses = null; + + if(order.equals("NEWEST")) + courses = courseRepository.searchCourseByNewest(keyword, pageable); + else if(order.equals("RATING_DESC")) + courses = courseRepository.searchCourseByRatingDesc(keyword, pageable); + else if(order.equals("RATING_ASC")) + courses = courseRepository.searchCourseByRatingAsc(keyword, pageable); + else + throw new AppException(ErrorCode.INVALID_ORDER, order); + + // 검색 결과가 없다면 예외 발생 + if(courses.isEmpty()) + throw new AppException(ErrorCode.NO_RESULT, keyword); + + // 비로그인 시, 평점 데이터를 전달하지 않으며, 북마크 여부가 항상 false + if(principal == null) + { + // Course 엔티티 리스트 -> courseDto.ExpiredBasic 리스트 + List courseDtos = courses.stream() + .map(course -> { + + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + + return CourseDto.UPDATED_entityToExpiredBasic(course, timeLocations, false); + }) + .toList(); + + return courseDtos; + } + else + { + // 사용자 정보 확인 + String email = principal.getName(); + Profile profile = profileRepository.findByEmail(email) + .orElseThrow(() -> new AppException(ErrorCode.EMAIL_NOT_FOUND, email)); + Long profile_id = profile.getProfile_id(); + + // 열람권 보유 시, 평점 데이터도 전달 + // 열람권 만료 시, 평점 데이터는 전달하지 않음 + if(profile.getAccess_expiration_date().isAfter(LocalDate.now())) + { + // Course 엔티티 리스트 -> courseDto.Basic 리스트 + List courseDtos = courses.stream() + .map(course -> { + + // 해당 강의의 평점 데이터 + CourseRating courseRating = course.getCourseRating_id(); + + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + + // 사용자의 해당 강의 북마크 여부 + boolean isBookmark = !bookmarkRepository.searchBookmark(profile_id, course.getCourse_id()).isEmpty(); + + return CourseDto.UPDATED_entityToBasic(course, courseRating, timeLocations, isBookmark); + }) + .toList(); + + return courseDtos; + } + else + { + // Course 엔티티 리스트 -> courseDto.ExpiredBasic 리스트 + List courseDtos = courses.stream() + .map(course -> { + + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + + // 사용자의 해당 강의 북마크 여부 + boolean isBookmark = !bookmarkRepository.searchBookmark(profile_id, course.getCourse_id()).isEmpty(); + + return CourseDto.UPDATED_entityToExpiredBasic(course, timeLocations, isBookmark); + }) + .toList(); + + return courseDtos; + } + } + } + + /* [변경] 강의 상세 정보 서비스 */ + public Object courseDetail(Long course_id, String order, int page, Principal principal) + { + // 사용자가 상세 정보를 요청한 강의가 존재하지 않으면 예외 처리 + Course course = courseRepository.findById(course_id) + .orElseThrow(() -> new AppException(ErrorCode.COURSE_NOT_FOUND, course_id)); + + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + + // 비로그인 시, 평점 데이터와 강의평 리스트를 전달하지 않으며, 북마크 여부가 항상 false + if(principal == null) + { + // CourseDto.ExpiredDetail 반환 + return CourseDto.UPDATED_entityToExpiredDetail(course, timeLocations, false); + } + else + { + // 요청을 보낸 사용자의 계정 정보 + String principalEmail = principal.getName(); + Profile principalProfile = profileRepository.findByEmail(principalEmail) + .orElseThrow(() -> new AppException(ErrorCode.EMAIL_NOT_FOUND, principalEmail)); + Long principalProfile_id = principalProfile.getProfile_id(); + + // 열람권 보유 시, 평점 데이터와 강의평 리스트도 전달 + // 열람권 만료 시, 평점 데이터와 강의평 리스트를 전달하지 않음 + if(principalProfile.getAccess_expiration_date().isAfter(LocalDate.now())) + { + // 해당 강의의 평점 데이터가 존재하지 않으면 예외 처리 + CourseRating courseRating = courseRatingRepository.findById(course.getCourseRating_id().getCourseRating_id()) + .orElseThrow(() -> new AppException(ErrorCode.COURSE_RATING_NOT_FOUND, course.getCourseRating_id().getCourseRating_id())); + + // Pageable 객체 생성 (size = 10개) + Pageable pageable = PageRequest.of(page, 10); + + // 해당 강의의 강의평들 검색 + Page comments = null; + + if(order.equals("NEWEST")) + comments = commentRepository.findByCourseIdOrderNewest(course_id, pageable); + else if(order.equals("RATING_DESC")) + comments = commentRepository.findByCourseIdOrderRatingDesc(course_id, pageable); + else if(order.equals("RATING_ASC")) + comments = commentRepository.findByCourseIdOrderRatingAsc(course_id, pageable); + else if(order.equals("LIKES_DESC")) + comments = commentRepository.findByCourseIdOrderLikesDesc(course_id, pageable); + else if(order.equals("LIKES_ASC")) + comments = commentRepository.findByCourseIdOrderLikesAsc(course_id, pageable); + else + throw new AppException(ErrorCode.INVALID_ORDER, order); + + // 강의평 엔티티 리스트를 강의평 dto 리스트로 변환 + List commentDtos = comments.stream() + .map(comment -> { + + // 해당 강의평을 작성한 사용자의 profile_id가 존재하지 않으면 예외 처리 + Profile profile = profileRepository.findById(comment.getProfile_id().getProfile_id()) + .orElseThrow(() -> new AppException(ErrorCode.USER_NOT_FOUND, comment.getProfile_id().getProfile_id())); + + // 해당 강의평의 평점 데이터가 존재하지 않으면 예외 처리 + CommentRating commentRating = commentRatingRepository.findById(comment.getCommentRating_id().getCommentRating_id()) + .orElseThrow(() -> new AppException(ErrorCode.COMMENT_RATING_NOT_FOUND, comment.getCommentRating_id().getCommentRating_id())); + + CommentLike commentLike = commentLikeRepository.searchCommentLike(principalProfile_id, comment.getComment_id()); + + return CommentDto.Detail.builder() + .comment_id(comment.getComment_id()) + .profile_id(profile.getProfile_id()) + .username(profile.getUsername()) + .rating(commentRating.getRating()) + .r1_amount_of_studying(commentRating.getR1_amount_of_studying()) + .r2_difficulty(commentRating.getR2_difficulty()) + .r3_delivery_power(commentRating.getR3_delivery_power()) + .r4_grading(commentRating.getR4_grading()) + .review(comment.getReview()) + .teach_t1_theory(commentRating.isTeach_t1_theory()) + .teach_t2_practice(commentRating.isTeach_t2_practice()) + .teach_t3_seminar(commentRating.isTeach_t3_seminar()) + .teach_t4_discussion(commentRating.isTeach_t4_discussion()) + .teach_t5_presentation(commentRating.isTeach_t5_presentation()) + .learn_t1_theory(commentRating.isLearn_t1_theory()) + .learn_t2_thesis(commentRating.isLearn_t2_thesis()) + .learn_t3_exam(commentRating.isLearn_t3_exam()) + .learn_t4_industry(commentRating.isLearn_t4_industry()) + .likes(comment.getLikes()) + .created_at(comment.getCreated_at()) + .updated_at(comment.getUpdated_at()) + .already_like(commentLike != null) + .build(); + + }) + .toList(); + + // 사용자의 해당 강의 북마크 여부 + boolean isBookmark = !bookmarkRepository.searchBookmark(principalProfile_id, course.getCourse_id()).isEmpty(); + + // course 엔티티와 강의평 dto 리스트로 CourseDto.Detail 만들어서 반환 + return CourseDto.UPDATED_entityToDetail(course, courseRating, commentDtos, timeLocations, isBookmark); + } + else + { + // 사용자의 해당 강의 북마크 여부 + boolean isBookmark = !bookmarkRepository.searchBookmark(principalProfile_id, course.getCourse_id()).isEmpty(); + + // CourseDto.ExpiredDetail 반환 + return CourseDto.UPDATED_entityToExpiredDetail(course, timeLocations, isBookmark); + } + } + } + + /* [변경] 강의평 작성 시작 서비스 */ + public CourseDto.UPDATED_Basic startInsertComment(Principal principal, Long course_id) + { + // 강의평 작성 시작 요청을 보낸 사용자의 계정 이메일 + String email = principal.getName(); + + // 강의평 작성 시작 요청을 보낸 사용자의 계정이 존재하지 않으면, 예외 처리 + Profile profile = profileRepository.findByEmail(email) + .orElseThrow(() -> new AppException(ErrorCode.EMAIL_NOT_FOUND, email)); + + // 사용자가 강의평을 추가할 강의가 존재하지 않으면, 예외 처리 + Course course = courseRepository.findById(course_id) + .orElseThrow(() -> new AppException(ErrorCode.COURSE_NOT_FOUND, course_id)); + + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + + // 해당 사용자가 이미 해당 강의에 강의평을 달았다면, 예외 처리 + List comment = commentRepository.searchComment(profile.getProfile_id(), course_id); + if(!comment.isEmpty()) + throw new AppException(ErrorCode.ALREADY_EXIST, course_id); + + // 해당 강의의 평점 데이터 + CourseRating courseRating = course.getCourseRating_id(); + + // 사용자의 해당 강의 북마크 여부 + boolean isBookmark = !bookmarkRepository.searchBookmark(profile.getProfile_id(), course.getCourse_id()).isEmpty(); + + return CourseDto.UPDATED_entityToBasic(course, courseRating, timeLocations, isBookmark); + } + + /* [변경] 강의평 수정 시작 서비스 */ + public CommentDto.UPDATED_StartUpdate startUpdateComment(Principal principal, Long comment_id) + { + // 강의평 작성 시작 요청을 보낸 사용자의 계정 이메일 + String email = principal.getName(); + + // 강의평 작성 시작 요청을 보낸 사용자의 계정이 존재하지 않으면, 예외 처리 + Profile profile = profileRepository.findByEmail(email) + .orElseThrow(() -> new AppException(ErrorCode.EMAIL_NOT_FOUND, email)); + + // 사용자가 수정할 강의평이 존재하지 않으면, 예외 처리 + Comment comment = commentRepository.findById(comment_id) + .orElseThrow(() -> new AppException(ErrorCode.COMMENT_NOT_FOUND, comment_id)); + + // 강의 정보 + Course course = comment.getCourse_id(); + + // 강의 평점 정보 + CourseRating courseRating = course.getCourseRating_id(); + + // 강의 시간 및 장소 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); + + // 해당 강의평이 해당 사용자가 작성한 강의평이 아니라면, 예외 처리 + if(!Objects.equals(comment.getProfile_id().getProfile_id(), profile.getProfile_id())) + throw new AppException(ErrorCode.NOT_COMMENT_BY_USER, null); + + CommentRating commentRating = comment.getCommentRating_id(); + + return CommentDto.UPDATED_entityToStartUpdate(course, courseRating, comment, commentRating, timeLocations); + } + + /* [변경] 내가 작성한 강의평 정보 조회 서비스 */ + public List myComments(Principal principal, int page) + { + // 요청을 보낸 사용자의 계정 이메일 + String email = principal.getName(); + + // 요청을 보낸 사용자의 계정이 존재하지 않으면 예외 처리 + Profile profile = profileRepository.findByEmail(email) + .orElseThrow(() -> new AppException(ErrorCode.EMAIL_NOT_FOUND, email)); + + // Pageable 객체 생성 (size = 10개) + Pageable pageable = PageRequest.of(page, 10); + + // 사용자가 작성한 강의평 엔티티 페이지 조회 + Page comments = commentRepository.findByProfileIdOrderNewest(profile.getProfile_id(), pageable); + + // 결과가 없으면 예외 발생 + if(comments.isEmpty()) + throw new AppException(ErrorCode.NO_RESULT, page + 1); + + // 강의평 엔티티 페이지를 강의평 dto 리스트로 변환 + List commentDtos = comments.stream() + .map(comment -> { + + Course course = comment.getCourse_id(); // 강의 정보 + CommentRating commentRating = comment.getCommentRating_id(); // 강의평 평점 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); // 강의 시간 및 장소 정보 + + return CommentDto.UPDATED_entityToMyPage(comment, course, commentRating, timeLocations); + + }) + .toList(); + + return commentDtos; + } + + /* [변경] 내가 북마크한 강의 정보 조회 서비스 */ + public List myBookmarks(Principal principal, int page) + { + // 요청을 보낸 사용자의 계정 이메일 + String email = principal.getName(); + + // 요청을 보낸 사용자의 계정이 존재하지 않으면 예외 처리 + Profile profile = profileRepository.findByEmail(email) + .orElseThrow(() -> new AppException(ErrorCode.EMAIL_NOT_FOUND, email)); + + // Pageable 객체 생성 (size = 10개) + Pageable pageable = PageRequest.of(page, 10); + + // 사용자가 북마크한 강의 엔티티 페이지 조회 + Page bookmarks = bookmarkRepository.findByProfileId(profile.getProfile_id(), pageable); + + // 결과가 없으면 예외 발생 + if(bookmarks.isEmpty()) + throw new AppException(ErrorCode.NO_RESULT, page + 1); + + // 강의 엔티티 페이지를 강의 dto 리스트로 변환 + List courseDtos = bookmarks.stream() + .map(bookmark -> { + + Course course = bookmark.getCourse_id(); // 강의 정보 + CourseRating courseRating = course.getCourseRating_id(); // 강의 평점 정보 + List timeLocations = timeLocationRepository.findByCourseId(course.getCourse_id()); // 강의 시간 및 장소 정보 + + // 사용자의 해당 강의 북마크 여부 + boolean isBookmark = !bookmarkRepository.searchBookmark(profile.getProfile_id(), course.getCourse_id()).isEmpty(); + + return CourseDto.UPDATED_entityToBasic(course, courseRating, timeLocations, isBookmark); + + }) + .toList(); + + return courseDtos; + } +} From 12d08280b511eca87f5d8c24fdc28882b631c7ec Mon Sep 17 00:00:00 2001 From: YunJaeHoon Date: Wed, 15 Jan 2025 17:03:16 +0900 Subject: [PATCH 4/4] VER: v1.2.0-alpha --- README.md | 2 +- src/main/resources/application.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3c8b594..6aa1b17 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Academ Back-end repository입니다. --- ### 프로젝트 구조 -( 최신화 : v1.1.4 ) +( 최신화 : v1.2.0-alpha ) ``` │ ├── .github diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 27f10d6..bc1b584 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,5 +1,5 @@ academ: - version: "v1.1.4" + version: "v1.2.0-alpha" spring: