diff --git a/backend/src/main/java/com/project/capstone/book/domain/Book.java b/backend/src/main/java/com/project/capstone/book/domain/Book.java index 8e92b888b0..17e849b33a 100644 --- a/backend/src/main/java/com/project/capstone/book/domain/Book.java +++ b/backend/src/main/java/com/project/capstone/book/domain/Book.java @@ -1,6 +1,8 @@ package com.project.capstone.book.domain; import com.project.capstone.club.domain.Club; +import com.project.capstone.content.domain.Content; +import com.project.capstone.quiz.domain.Quiz; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; @@ -32,4 +34,10 @@ public class Book { @OneToMany(mappedBy = "book") private List clubs = new ArrayList<>(); + + @OneToMany(mappedBy = "book") + private List contents = new ArrayList<>(); + + @OneToMany(mappedBy = "book") + private List quizzes = new ArrayList<>(); } diff --git a/backend/src/main/java/com/project/capstone/book/domain/BookRepository.java b/backend/src/main/java/com/project/capstone/book/domain/BookRepository.java new file mode 100644 index 0000000000..6da8fcbdde --- /dev/null +++ b/backend/src/main/java/com/project/capstone/book/domain/BookRepository.java @@ -0,0 +1,9 @@ +package com.project.capstone.book.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface BookRepository extends JpaRepository { + Optional findBookById(Long id); +} diff --git a/backend/src/main/java/com/project/capstone/book/exception/BookException.java b/backend/src/main/java/com/project/capstone/book/exception/BookException.java new file mode 100644 index 0000000000..85e77763b5 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/book/exception/BookException.java @@ -0,0 +1,10 @@ +package com.project.capstone.book.exception; + +import com.project.capstone.common.exception.BaseException; +import com.project.capstone.common.exception.ExceptionType; + +public class BookException extends BaseException { + public BookException(ExceptionType exceptionType) { + super(exceptionType); + } +} diff --git a/backend/src/main/java/com/project/capstone/book/exception/BookExceptionType.java b/backend/src/main/java/com/project/capstone/book/exception/BookExceptionType.java new file mode 100644 index 0000000000..545afef3a0 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/book/exception/BookExceptionType.java @@ -0,0 +1,33 @@ +package com.project.capstone.book.exception; + +import com.project.capstone.common.exception.ExceptionType; +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; + +import static org.springframework.http.HttpStatus.NOT_FOUND; + +@AllArgsConstructor +public enum BookExceptionType implements ExceptionType { + + BOOK_NOT_FOUND(NOT_FOUND, 801, "해당 책을 찾을 수 없습니다.") + ; + + private final HttpStatus status; + private final int exceptionCode; + private final String message; + + @Override + public HttpStatus httpStatus() { + return status; + } + + @Override + public int exceptionCode() { + return exceptionCode; + } + + @Override + public String message() { + return message; + } +} diff --git a/backend/src/main/java/com/project/capstone/club/domain/Club.java b/backend/src/main/java/com/project/capstone/club/domain/Club.java index fc63b9b0d6..deb76b3cd4 100644 --- a/backend/src/main/java/com/project/capstone/club/domain/Club.java +++ b/backend/src/main/java/com/project/capstone/club/domain/Club.java @@ -6,6 +6,7 @@ import com.project.capstone.memberclub.domain.MemberClub; import com.project.capstone.content.domain.Content; import com.project.capstone.post.domain.Post; +import com.project.capstone.quiz.domain.Quiz; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; @@ -54,6 +55,10 @@ public class Club { @OneToMany(mappedBy = "club") private List contents = new ArrayList<>(); + @JsonManagedReference + @OneToMany(mappedBy = "club") + private List quizzes = new ArrayList<>(); + @ManyToOne private Book book; diff --git a/backend/src/main/java/com/project/capstone/club/domain/PublicStatus.java b/backend/src/main/java/com/project/capstone/club/domain/PublicStatus.java index 4e47ba4bf5..037b091cae 100644 --- a/backend/src/main/java/com/project/capstone/club/domain/PublicStatus.java +++ b/backend/src/main/java/com/project/capstone/club/domain/PublicStatus.java @@ -13,7 +13,7 @@ public enum PublicStatus { private final String description; - @JsonCreator + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) public static PublicStatus from(String status) { for (PublicStatus publicStatus : PublicStatus.values()) { if (publicStatus.getDescription().equals(status)) { diff --git a/backend/src/main/java/com/project/capstone/content/controller/ContentController.java b/backend/src/main/java/com/project/capstone/content/controller/ContentController.java new file mode 100644 index 0000000000..92b6c3b014 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/content/controller/ContentController.java @@ -0,0 +1,43 @@ +package com.project.capstone.content.controller; + +import com.project.capstone.auth.domain.PrincipalDetails; +import com.project.capstone.content.controller.dto.ContentCreateRequest; +import com.project.capstone.content.controller.dto.ContentResponse; +import com.project.capstone.content.service.ContentService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/content") +public class ContentController { + + private final ContentService contentService; + + // 컨텐츠 생성 + @PostMapping("/create") + public ResponseEntity createContent(@AuthenticationPrincipal PrincipalDetails details, + @RequestBody ContentCreateRequest request, + @RequestParam Long bookId, @RequestParam(required = false) Long clubId) { + contentService.createContent(details.getUserId(), request, bookId, clubId); + return ResponseEntity.ok().body("컨텐츠 생성 완료"); + } + + // 단일 컨텐츠 조회 + @GetMapping("/{id}") + public ResponseEntity getContent(@PathVariable Long id) { + ContentResponse contentResponse = contentService.getContent(id); + return ResponseEntity.ok().body(contentResponse); + } + + // 컨텐츠 종류별 조회 + @GetMapping("/get") + public ResponseEntity> getContents(@RequestParam String type) { + List contentResponseList = contentService.getContents(type); + return ResponseEntity.ok().body(contentResponseList); + } +} diff --git a/backend/src/main/java/com/project/capstone/content/controller/dto/ContentCreateRequest.java b/backend/src/main/java/com/project/capstone/content/controller/dto/ContentCreateRequest.java new file mode 100644 index 0000000000..f35b74de83 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/content/controller/dto/ContentCreateRequest.java @@ -0,0 +1,10 @@ +package com.project.capstone.content.controller.dto; + +import com.project.capstone.content.domain.ContentType; + +public record ContentCreateRequest( + ContentType contentType, + String title, + String body +) { +} diff --git a/backend/src/main/java/com/project/capstone/content/controller/dto/ContentResponse.java b/backend/src/main/java/com/project/capstone/content/controller/dto/ContentResponse.java new file mode 100644 index 0000000000..13352f609e --- /dev/null +++ b/backend/src/main/java/com/project/capstone/content/controller/dto/ContentResponse.java @@ -0,0 +1,22 @@ +package com.project.capstone.content.controller.dto; + +import com.project.capstone.content.domain.Content; +import com.project.capstone.content.domain.ContentType; + +import java.util.UUID; + +public record ContentResponse( + Long id, + UUID memberId, + Long bookId, + Long clubId, + ContentType type, + String title, + String body, + int likes +) { + public ContentResponse(Content content) { + this(content.getId(), content.getMember().getId(), content.getBook().getId(), + content.getClub() == null ? null : content.getClub().getId(), content.getType(), content.getTitle(), content.getBody(), content.getLikes()); + } +} diff --git a/backend/src/main/java/com/project/capstone/content/domain/Content.java b/backend/src/main/java/com/project/capstone/content/domain/Content.java index fcddadaf73..b042f06fe1 100644 --- a/backend/src/main/java/com/project/capstone/content/domain/Content.java +++ b/backend/src/main/java/com/project/capstone/content/domain/Content.java @@ -1,5 +1,6 @@ package com.project.capstone.content.domain; +import com.fasterxml.jackson.annotation.JsonBackReference; import com.project.capstone.book.domain.Book; import com.project.capstone.club.domain.Club; import com.project.capstone.member.domain.Member; @@ -20,21 +21,23 @@ public class Content { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - private String type; - @Column(name = "quiz_type") - private String quizType; - @Column(name = "quiz_answer") - private String quizAnswer; + + @Enumerated(EnumType.STRING) + @Column(name = "content_type") + private ContentType type; private String title; private String body; - private String likes; + private int likes; + @JsonBackReference @ManyToOne private Member member; + @JsonBackReference @ManyToOne private Book book; + @JsonBackReference @ManyToOne private Club club; } diff --git a/backend/src/main/java/com/project/capstone/content/domain/ContentRepository.java b/backend/src/main/java/com/project/capstone/content/domain/ContentRepository.java new file mode 100644 index 0000000000..cf9c9190cc --- /dev/null +++ b/backend/src/main/java/com/project/capstone/content/domain/ContentRepository.java @@ -0,0 +1,11 @@ +package com.project.capstone.content.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +public interface ContentRepository extends JpaRepository { + Optional findContentById(Long id); + List findContentsByType(ContentType type); +} diff --git a/backend/src/main/java/com/project/capstone/content/domain/ContentType.java b/backend/src/main/java/com/project/capstone/content/domain/ContentType.java new file mode 100644 index 0000000000..52faacdcc4 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/content/domain/ContentType.java @@ -0,0 +1,28 @@ +package com.project.capstone.content.domain; + +import com.fasterxml.jackson.annotation.JsonCreator; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@AllArgsConstructor +@Getter +@Slf4j +public enum ContentType { + + Review("독후감"), + Quotation("인용구"), + ShortReview("한줄평"); + + private final String type; + + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static ContentType from(String type) { + for (ContentType contentType : ContentType.values()) { + if (contentType.getType().equals(type)) { + return contentType; + } + } + throw new RuntimeException("잘못된 컨텐츠 타입 입니다."); + } +} diff --git a/backend/src/main/java/com/project/capstone/content/exception/ContentException.java b/backend/src/main/java/com/project/capstone/content/exception/ContentException.java new file mode 100644 index 0000000000..255c7a321a --- /dev/null +++ b/backend/src/main/java/com/project/capstone/content/exception/ContentException.java @@ -0,0 +1,10 @@ +package com.project.capstone.content.exception; + +import com.project.capstone.common.exception.BaseException; +import com.project.capstone.common.exception.ExceptionType; + +public class ContentException extends BaseException { + public ContentException(ExceptionType exceptionType) { + super(exceptionType); + } +} diff --git a/backend/src/main/java/com/project/capstone/content/exception/ContentExceptionType.java b/backend/src/main/java/com/project/capstone/content/exception/ContentExceptionType.java new file mode 100644 index 0000000000..ca4f3e9cae --- /dev/null +++ b/backend/src/main/java/com/project/capstone/content/exception/ContentExceptionType.java @@ -0,0 +1,34 @@ +package com.project.capstone.content.exception; + +import com.project.capstone.common.exception.ExceptionType; +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; + +import static org.springframework.http.HttpStatus.NOT_FOUND; + +@AllArgsConstructor +public enum ContentExceptionType implements ExceptionType { + CONTENT_NOT_FOUND(NOT_FOUND, 901, "해당 컨텐츠를 찾을 수 없습니다."), + TYPE_NOT_FOUND(NOT_FOUND, 902, "해당 타입을 찾을 수 없습니다.") + ; + + + private final HttpStatus status; + private final int exceptionCode; + private final String message; + + @Override + public HttpStatus httpStatus() { + return status; + } + + @Override + public int exceptionCode() { + return exceptionCode; + } + + @Override + public String message() { + return message; + } +} diff --git a/backend/src/main/java/com/project/capstone/content/service/ContentService.java b/backend/src/main/java/com/project/capstone/content/service/ContentService.java new file mode 100644 index 0000000000..3efb4238b3 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/content/service/ContentService.java @@ -0,0 +1,101 @@ +package com.project.capstone.content.service; + +import com.project.capstone.book.domain.Book; +import com.project.capstone.book.domain.BookRepository; +import com.project.capstone.book.exception.BookException; +import com.project.capstone.book.exception.BookExceptionType; +import com.project.capstone.club.domain.Club; +import com.project.capstone.club.domain.ClubRepository; +import com.project.capstone.club.exception.ClubException; +import com.project.capstone.club.exception.ClubExceptionType; +import com.project.capstone.content.controller.dto.ContentCreateRequest; +import com.project.capstone.content.controller.dto.ContentResponse; +import com.project.capstone.content.domain.Content; +import com.project.capstone.content.domain.ContentRepository; +import com.project.capstone.content.domain.ContentType; +import com.project.capstone.content.exception.ContentException; +import com.project.capstone.content.exception.ContentExceptionType; +import com.project.capstone.member.domain.Member; +import com.project.capstone.member.domain.MemberRepository; +import com.project.capstone.member.exception.MemberException; +import com.project.capstone.member.exception.MemberExceptionType; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import static com.project.capstone.book.exception.BookExceptionType.BOOK_NOT_FOUND; +import static com.project.capstone.club.exception.ClubExceptionType.CLUB_NOT_FOUND; +import static com.project.capstone.content.exception.ContentExceptionType.CONTENT_NOT_FOUND; +import static com.project.capstone.content.exception.ContentExceptionType.TYPE_NOT_FOUND; +import static com.project.capstone.member.exception.MemberExceptionType.MEMBER_NOT_FOUND; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ContentService { + + private final ContentRepository contentRepository; + private final BookRepository bookRepository; + private final ClubRepository clubRepository; + private final MemberRepository memberRepository; + + public void createContent(String userId, ContentCreateRequest request, Long bookId, Long clubId) { + Member member = memberRepository.findMemberById(UUID.fromString(userId)).orElseThrow( + () -> new MemberException(MEMBER_NOT_FOUND) + ); + Book book = bookRepository.findBookById(bookId).orElseThrow( + () -> new BookException(BOOK_NOT_FOUND) + ); + Club club; + if (clubId == null) { + club = null; + } + else { + club = clubRepository.findClubById(clubId).orElseThrow( + () -> new ClubException(CLUB_NOT_FOUND) + ); + } + Content saved = contentRepository.save( + Content.builder() + .type(request.contentType()) + .title(request.title()) + .body(request.body()) + .likes(0) + .member(member) + .book(book) + .club(club) + .build() + ); + + member.getContents().add(saved); + book.getContents().add(saved); + if (club != null) { + club.getContents().add(saved); + } + } + + public ContentResponse getContent(Long id) { + Content content = contentRepository.findContentById(id).orElseThrow( + () -> new ContentException(CONTENT_NOT_FOUND) + ); + + return new ContentResponse(content); + } + + public List getContents(String type) { + for (ContentType contentType : ContentType.values()) { + if (contentType.equals(ContentType.valueOf(type))) { + List contentsByType = contentRepository.findContentsByType(ContentType.valueOf(type)); + return contentsByType.stream() + .map(ContentResponse::new) + .toList(); + } + } + throw new ContentException(TYPE_NOT_FOUND); + } +} diff --git a/backend/src/main/java/com/project/capstone/member/domain/Member.java b/backend/src/main/java/com/project/capstone/member/domain/Member.java index 74fa70fe69..5f926c1ed1 100644 --- a/backend/src/main/java/com/project/capstone/member/domain/Member.java +++ b/backend/src/main/java/com/project/capstone/member/domain/Member.java @@ -6,6 +6,7 @@ import com.project.capstone.memberclub.domain.MemberClub; import com.project.capstone.content.domain.Content; import com.project.capstone.post.domain.Post; +import com.project.capstone.quiz.domain.Quiz; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; @@ -55,8 +56,12 @@ public class Member { @OneToMany(mappedBy = "member") private List contents = new ArrayList<>(); + @JsonManagedReference + @OneToMany(mappedBy = "member") + private List quizzes = new ArrayList<>(); + public Member(SignupRequest request) { this(null, request.email(), request.name(), request.age(), request.gender(), null, - new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); + new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>()); } } diff --git a/backend/src/main/java/com/project/capstone/quiz/controller/QuizController.java b/backend/src/main/java/com/project/capstone/quiz/controller/QuizController.java new file mode 100644 index 0000000000..d8c9b0bd36 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/quiz/controller/QuizController.java @@ -0,0 +1,34 @@ +package com.project.capstone.quiz.controller; + + +import com.project.capstone.auth.domain.PrincipalDetails; +import com.project.capstone.quiz.controller.dto.CreateQuizRequest; +import com.project.capstone.quiz.controller.dto.QuizResponse; +import com.project.capstone.quiz.service.QuizService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/quiz") +public class QuizController { + private final QuizService quizService; + + // 퀴즈 생성 + @PostMapping("/create") + public ResponseEntity createQuiz(@AuthenticationPrincipal PrincipalDetails details, + @RequestBody CreateQuizRequest request, + @RequestParam Long bookId, @RequestParam(required = false) Long clubId) { + quizService.createQuiz(details.getUserId(), request, bookId, clubId); + return ResponseEntity.ok().body("퀴즈 생성 완료"); + } + + // 단건 조회 + @GetMapping("/{id}") + public ResponseEntity getQuiz(@PathVariable Long id) { + QuizResponse quizResponse = quizService.getQuiz(id); + return ResponseEntity.ok().body(quizResponse); + } +} diff --git a/backend/src/main/java/com/project/capstone/quiz/controller/dto/CreateQuizRequest.java b/backend/src/main/java/com/project/capstone/quiz/controller/dto/CreateQuizRequest.java new file mode 100644 index 0000000000..15b091bc78 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/quiz/controller/dto/CreateQuizRequest.java @@ -0,0 +1,14 @@ +package com.project.capstone.quiz.controller.dto; + +import com.project.capstone.quiz.domain.QuizType; + +public record CreateQuizRequest( + QuizType type, + String description, + String answer, + String example1, + String example2, + String example3, + String example4 +) { +} diff --git a/backend/src/main/java/com/project/capstone/quiz/controller/dto/QuizResponse.java b/backend/src/main/java/com/project/capstone/quiz/controller/dto/QuizResponse.java new file mode 100644 index 0000000000..13a7484279 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/quiz/controller/dto/QuizResponse.java @@ -0,0 +1,25 @@ +package com.project.capstone.quiz.controller.dto; + +import com.project.capstone.quiz.domain.Quiz; +import com.project.capstone.quiz.domain.QuizType; + +import java.util.UUID; + +public record QuizResponse ( + Long id, + UUID memberId, + Long bookId, + Long clubId, + QuizType type, + String description, + String answer, + String example1, + String example2, + String example3, + String example4 +) { + public QuizResponse(Quiz quiz) { + this(quiz.getId(), quiz.getMember().getId(), quiz.getBook().getId(), quiz.getClub() == null ? null : quiz.getClub().getId(), quiz.getType(), + quiz.getDescription(), quiz.getAnswer(), quiz.getExample1(), quiz.getExample2(), quiz.getExample3(), quiz.getExample4()); + } +} diff --git a/backend/src/main/java/com/project/capstone/quiz/domain/Quiz.java b/backend/src/main/java/com/project/capstone/quiz/domain/Quiz.java new file mode 100644 index 0000000000..d3849b80e8 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/quiz/domain/Quiz.java @@ -0,0 +1,43 @@ +package com.project.capstone.quiz.domain; + +import com.project.capstone.book.domain.Book; +import com.project.capstone.club.domain.Club; +import com.project.capstone.member.domain.Member; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +@Entity +@EntityListeners(AuditingEntityListener.class) +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class Quiz { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Enumerated(EnumType.STRING) + private QuizType type; + private String description; + private String answer; + private String example1; + private String example2; + private String example3; + private String example4; + + @ManyToOne + private Member member; + + @ManyToOne + private Book book; + + @ManyToOne + private Club club; + +} diff --git a/backend/src/main/java/com/project/capstone/quiz/domain/QuizRepository.java b/backend/src/main/java/com/project/capstone/quiz/domain/QuizRepository.java new file mode 100644 index 0000000000..7d0568b8bc --- /dev/null +++ b/backend/src/main/java/com/project/capstone/quiz/domain/QuizRepository.java @@ -0,0 +1,9 @@ +package com.project.capstone.quiz.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface QuizRepository extends JpaRepository { + Optional findQuizById(Long id); +} diff --git a/backend/src/main/java/com/project/capstone/quiz/domain/QuizType.java b/backend/src/main/java/com/project/capstone/quiz/domain/QuizType.java new file mode 100644 index 0000000000..3b7ea7f7d6 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/quiz/domain/QuizType.java @@ -0,0 +1,27 @@ +package com.project.capstone.quiz.domain; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.project.capstone.club.domain.PublicStatus; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum QuizType { + MultipleChoice("객관식"), + ShortAnswer("단답식"), + OX("OX") + ; + + private final String type; + + @JsonCreator(mode = JsonCreator.Mode.DELEGATING) + public static QuizType from(String type) { + for (QuizType quizType : QuizType.values()) { + if (quizType.getType().equals(type)) { + return quizType; + } + } + throw new RuntimeException("잘못된 퀴즈 타입 입니다."); + } +} diff --git a/backend/src/main/java/com/project/capstone/quiz/exception/QuizException.java b/backend/src/main/java/com/project/capstone/quiz/exception/QuizException.java new file mode 100644 index 0000000000..c5fc2a5d13 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/quiz/exception/QuizException.java @@ -0,0 +1,10 @@ +package com.project.capstone.quiz.exception; + +import com.project.capstone.common.exception.BaseException; +import com.project.capstone.common.exception.ExceptionType; + +public class QuizException extends BaseException { + public QuizException(ExceptionType exceptionType) { + super(exceptionType); + } +} diff --git a/backend/src/main/java/com/project/capstone/quiz/exception/QuizExceptionType.java b/backend/src/main/java/com/project/capstone/quiz/exception/QuizExceptionType.java new file mode 100644 index 0000000000..96b7fd32b2 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/quiz/exception/QuizExceptionType.java @@ -0,0 +1,32 @@ +package com.project.capstone.quiz.exception; + +import com.project.capstone.common.exception.ExceptionType; +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; + +import static org.springframework.http.HttpStatus.NOT_FOUND; + +@AllArgsConstructor +public enum QuizExceptionType implements ExceptionType { + QUIZ_NOT_FOUND(NOT_FOUND, 701, "해당 퀴즈를 찾을 수 없습니다.") + ; + + private final HttpStatus status; + private final int exceptionCode; + private final String message; + + @Override + public HttpStatus httpStatus() { + return status; + } + + @Override + public int exceptionCode() { + return exceptionCode; + } + + @Override + public String message() { + return message; + } +} diff --git a/backend/src/main/java/com/project/capstone/quiz/service/QuizService.java b/backend/src/main/java/com/project/capstone/quiz/service/QuizService.java new file mode 100644 index 0000000000..4579b9d9cd --- /dev/null +++ b/backend/src/main/java/com/project/capstone/quiz/service/QuizService.java @@ -0,0 +1,89 @@ +package com.project.capstone.quiz.service; + +import com.project.capstone.book.domain.Book; +import com.project.capstone.book.domain.BookRepository; +import com.project.capstone.book.exception.BookException; +import com.project.capstone.book.exception.BookExceptionType; +import com.project.capstone.club.domain.Club; +import com.project.capstone.club.domain.ClubRepository; +import com.project.capstone.club.exception.ClubException; +import com.project.capstone.club.exception.ClubExceptionType; +import com.project.capstone.member.domain.Member; +import com.project.capstone.member.domain.MemberRepository; +import com.project.capstone.member.exception.MemberException; +import com.project.capstone.member.exception.MemberExceptionType; +import com.project.capstone.quiz.controller.dto.CreateQuizRequest; +import com.project.capstone.quiz.controller.dto.QuizResponse; +import com.project.capstone.quiz.domain.Quiz; +import com.project.capstone.quiz.domain.QuizRepository; +import com.project.capstone.quiz.exception.QuizException; +import com.project.capstone.quiz.exception.QuizExceptionType; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +import static com.project.capstone.book.exception.BookExceptionType.BOOK_NOT_FOUND; +import static com.project.capstone.club.exception.ClubExceptionType.CLUB_NOT_FOUND; +import static com.project.capstone.member.exception.MemberExceptionType.MEMBER_NOT_FOUND; +import static com.project.capstone.quiz.exception.QuizExceptionType.QUIZ_NOT_FOUND; + +@RequiredArgsConstructor +@Service +@Slf4j +public class QuizService { + + private final QuizRepository quizRepository; + private final MemberRepository memberRepository; + private final BookRepository bookRepository; + private final ClubRepository clubRepository; + + public void createQuiz(String userId, CreateQuizRequest request, Long bookId, Long clubId) { + Member member = memberRepository.findMemberById(UUID.fromString(userId)).orElseThrow( + () -> new MemberException(MEMBER_NOT_FOUND) + ); + + Book book = bookRepository.findBookById(bookId).orElseThrow( + () -> new BookException(BOOK_NOT_FOUND) + ); + Club club; + if (clubId == null) { + club = null; + } + else { + club = clubRepository.findClubById(clubId).orElseThrow( + ()-> new ClubException(CLUB_NOT_FOUND) + ); + } + + Quiz saved = quizRepository.save( + Quiz.builder() + .type(request.type()) + .description(request.description()) + .answer(request.answer()) + .example1(request.example1()) + .example2(request.example2()) + .example3(request.example3()) + .example4(request.example4()) + .member(member) + .book(book) + .club(club) + .build() + ); + + member.getQuizzes().add(saved); + book.getQuizzes().add(saved); + if (club != null) { + club.getQuizzes().add(saved); + } + } + + + public QuizResponse getQuiz(Long id) { + Quiz quiz = quizRepository.findQuizById(id).orElseThrow( + () -> new QuizException(QUIZ_NOT_FOUND) + ); + return new QuizResponse(quiz); + } +} diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index 96d105d2a2..98c1b8ba6c 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -1,9 +1,9 @@ spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://localhost:3306/bm?serverTimezone=UTC&characterEncoding=UTF-8 - username: root - password: 12345678 + url: jdbc:mysql://${DB_ENDPOINT}:${DB_PORT}/${DB_NAME}?serverTimezone=UTC&characterEncoding=UTF-8 + username: ${DB_USERNAME} + password: ${DB_PASSWORD} jpa: hibernate: @@ -15,4 +15,4 @@ spring: mode: always jwt: - secret: gDpXHGuTSnwn6IkHoQE0TyrHT4qGDsbAm6L21qSbzUe8s/Nvo2JsiJyawX8fvUD6 Nh4CdIeQxAqnAzysgk+nUw== \ No newline at end of file + secret: ${JWT_SECRET} \ No newline at end of file