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/controller/dto/ClubResponse.java b/backend/src/main/java/com/project/capstone/club/controller/dto/ClubResponse.java index c47b916330..204b647f92 100644 --- a/backend/src/main/java/com/project/capstone/club/controller/dto/ClubResponse.java +++ b/backend/src/main/java/com/project/capstone/club/controller/dto/ClubResponse.java @@ -1,9 +1,12 @@ package com.project.capstone.club.controller.dto; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.project.capstone.club.domain.Club; import com.project.capstone.club.domain.PublicStatus; +import com.project.capstone.post.domain.Post; import java.time.LocalDateTime; +import java.util.List; public record ClubResponse ( Long id, @@ -12,9 +15,11 @@ public record ClubResponse ( String name, LocalDateTime createdAt, int maximum, - PublicStatus publicstatus + PublicStatus publicstatus, + List posts + ) { public ClubResponse(Club club) { - this(club.getId(), club.getBook() == null ? null : club.getBook().getId(), club.getTopic(), club.getName(), club.getCreatedAt(), club.getMaximum(), club.getPublicStatus()); + this(club.getId(), club.getBook() == null ? null : club.getBook().getId(), club.getTopic(), club.getName(), club.getCreatedAt(), club.getMaximum(), club.getPublicStatus(), club.getPosts()); } } \ No newline at end of file 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 000cb159ed..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 @@ -1,9 +1,12 @@ package com.project.capstone.club.domain; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonManagedReference; import com.project.capstone.book.domain.Book; 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; @@ -40,15 +43,22 @@ public class Club { private PublicStatus publicStatus; private Integer password; + @JsonManagedReference @OneToMany(mappedBy = "club") private List posts = new ArrayList<>(); + @JsonManagedReference @OneToMany(mappedBy = "club") private List members = new ArrayList<>(); + @JsonManagedReference @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/comment/controller/CommentController.java b/backend/src/main/java/com/project/capstone/comment/controller/CommentController.java new file mode 100644 index 0000000000..70571da939 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/comment/controller/CommentController.java @@ -0,0 +1,33 @@ +package com.project.capstone.comment.controller; + +import com.project.capstone.auth.domain.PrincipalDetails; +import com.project.capstone.comment.controller.dto.CommentResponse; +import com.project.capstone.comment.controller.dto.CreateCommentRequest; +import com.project.capstone.comment.service.CommentService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/comment") +public class CommentController { + + private final CommentService commentService; + + @PostMapping("create") + public ResponseEntity createComment(@AuthenticationPrincipal PrincipalDetails details, + @RequestParam Long postId, @RequestBody CreateCommentRequest request) { + commentService.createPost(details.getUserId(), postId, request); + return ResponseEntity.ok().body("댓글 생성 완료"); + } + + @GetMapping("/{id}") + public ResponseEntity getComment(@AuthenticationPrincipal PrincipalDetails details, + @PathVariable Long id) { + CommentResponse commentResponse = commentService.getComment(details.getUserId(), id); + return ResponseEntity.ok().body(commentResponse); + } + +} diff --git a/backend/src/main/java/com/project/capstone/comment/controller/dto/CommentResponse.java b/backend/src/main/java/com/project/capstone/comment/controller/dto/CommentResponse.java new file mode 100644 index 0000000000..fb8d6d3e19 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/comment/controller/dto/CommentResponse.java @@ -0,0 +1,18 @@ +package com.project.capstone.comment.controller.dto; + +import com.project.capstone.comment.domain.Comment; + +import java.time.LocalDateTime; +import java.util.UUID; + +public record CommentResponse( + Long id, + Long postId, + UUID memberId, + String body, + LocalDateTime createdAt +) { + public CommentResponse(Comment comment) { + this(comment.getId(), comment.getPost().getId(), comment.getMember().getId(), comment.getBody(), comment.getCreatedAt()); + } +} diff --git a/backend/src/main/java/com/project/capstone/comment/controller/dto/CreateCommentRequest.java b/backend/src/main/java/com/project/capstone/comment/controller/dto/CreateCommentRequest.java new file mode 100644 index 0000000000..6dadaa4ca5 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/comment/controller/dto/CreateCommentRequest.java @@ -0,0 +1,6 @@ +package com.project.capstone.comment.controller.dto; + +public record CreateCommentRequest ( + String body +) { +} diff --git a/backend/src/main/java/com/project/capstone/comment/domain/Comment.java b/backend/src/main/java/com/project/capstone/comment/domain/Comment.java index 26b1884f41..0ccb661e8c 100644 --- a/backend/src/main/java/com/project/capstone/comment/domain/Comment.java +++ b/backend/src/main/java/com/project/capstone/comment/domain/Comment.java @@ -1,5 +1,6 @@ package com.project.capstone.comment.domain; +import com.fasterxml.jackson.annotation.JsonBackReference; import com.project.capstone.member.domain.Member; import com.project.capstone.post.domain.Post; import jakarta.persistence.*; @@ -27,9 +28,11 @@ public class Comment { @Column(name = "created_at") private LocalDateTime createdAt; + @JsonBackReference @ManyToOne private Member member; + @JsonBackReference @ManyToOne private Post post; } diff --git a/backend/src/main/java/com/project/capstone/comment/domain/CommentRepository.java b/backend/src/main/java/com/project/capstone/comment/domain/CommentRepository.java new file mode 100644 index 0000000000..a5e39f660c --- /dev/null +++ b/backend/src/main/java/com/project/capstone/comment/domain/CommentRepository.java @@ -0,0 +1,9 @@ +package com.project.capstone.comment.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface CommentRepository extends JpaRepository { + Optional findCommentById(Long id); +} diff --git a/backend/src/main/java/com/project/capstone/comment/exception/CommentException.java b/backend/src/main/java/com/project/capstone/comment/exception/CommentException.java new file mode 100644 index 0000000000..3803fe7794 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/comment/exception/CommentException.java @@ -0,0 +1,10 @@ +package com.project.capstone.comment.exception; + +import com.project.capstone.common.exception.BaseException; +import com.project.capstone.common.exception.ExceptionType; + +public class CommentException extends BaseException { + public CommentException(ExceptionType exceptionType) { + super(exceptionType); + } +} diff --git a/backend/src/main/java/com/project/capstone/comment/exception/CommentExceptionType.java b/backend/src/main/java/com/project/capstone/comment/exception/CommentExceptionType.java new file mode 100644 index 0000000000..c31291e063 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/comment/exception/CommentExceptionType.java @@ -0,0 +1,32 @@ +package com.project.capstone.comment.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 CommentExceptionType implements ExceptionType { + COMMENT_NOT_FOUND(NOT_FOUND, 501, "해당 댓글을 찾을 수 없습니다."); + ; + + 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/comment/service/CommentService.java b/backend/src/main/java/com/project/capstone/comment/service/CommentService.java new file mode 100644 index 0000000000..5e5fa7c47f --- /dev/null +++ b/backend/src/main/java/com/project/capstone/comment/service/CommentService.java @@ -0,0 +1,62 @@ +package com.project.capstone.comment.service; + +import com.project.capstone.comment.controller.dto.CommentResponse; +import com.project.capstone.comment.controller.dto.CreateCommentRequest; +import com.project.capstone.comment.domain.Comment; +import com.project.capstone.comment.domain.CommentRepository; +import com.project.capstone.comment.exception.CommentException; +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.post.domain.Post; +import com.project.capstone.post.domain.PostRepository; +import com.project.capstone.post.exception.PostException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +import static com.project.capstone.comment.exception.CommentExceptionType.COMMENT_NOT_FOUND; +import static com.project.capstone.member.exception.MemberExceptionType.MEMBER_NOT_FOUND; +import static com.project.capstone.post.exception.PostExceptionType.POST_NOT_FOUND; + +@Service +@RequiredArgsConstructor +@Slf4j +public class CommentService { + + private final CommentRepository commentRepository; + private final MemberRepository memberRepository; + private final PostRepository postRepository; + + public void createPost(String userId, Long postId, CreateCommentRequest request) { + Member member = memberRepository.findMemberById(UUID.fromString(userId)).orElseThrow( + () -> new MemberException(MEMBER_NOT_FOUND) + ); + + Post post = postRepository.findPostById(postId).orElseThrow( + () -> new PostException(POST_NOT_FOUND) + ); + + Comment saved = commentRepository.save(Comment.builder() + .body(request.body()) + .member(member) + .post(post) + .build()); + + member.getComments().add(saved); + post.getComments().add(saved); + } + + + public CommentResponse getComment(String userId, Long id) { + if (memberRepository.findMemberById(UUID.fromString(userId)).isEmpty()) { + throw new MemberException(MEMBER_NOT_FOUND); + } + Comment comment = commentRepository.findCommentById(id).orElseThrow( + () -> new CommentException(COMMENT_NOT_FOUND) + ); + return new CommentResponse(comment); + } +} 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/controller/MemberController.java b/backend/src/main/java/com/project/capstone/member/controller/MemberController.java index 64397c5dd4..3f809acad5 100644 --- a/backend/src/main/java/com/project/capstone/member/controller/MemberController.java +++ b/backend/src/main/java/com/project/capstone/member/controller/MemberController.java @@ -10,7 +10,6 @@ @RequiredArgsConstructor @RequestMapping("/member") public class MemberController { - @GetMapping("/test") public ResponseEntity test() { return ResponseEntity.ok("ok"); 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 30e8b0e554..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 @@ -1,10 +1,12 @@ package com.project.capstone.member.domain; +import com.fasterxml.jackson.annotation.JsonManagedReference; import com.project.capstone.auth.controller.dto.SignupRequest; import com.project.capstone.comment.domain.Comment; 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; @@ -38,20 +40,28 @@ public class Member { @Column(name = "created_at") private LocalDateTime createdAt; + @JsonManagedReference @OneToMany(mappedBy = "member") private List clubs = new ArrayList<>(); + @JsonManagedReference @OneToMany(mappedBy = "member") private List posts = new ArrayList<>(); + @JsonManagedReference @OneToMany(mappedBy = "member") private List comments = new ArrayList<>(); + @JsonManagedReference @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/memberclub/exception/MemberClubExceptionType.java b/backend/src/main/java/com/project/capstone/memberclub/exception/MemberClubExceptionType.java index 147aa022ce..9c2feb635d 100644 --- a/backend/src/main/java/com/project/capstone/memberclub/exception/MemberClubExceptionType.java +++ b/backend/src/main/java/com/project/capstone/memberclub/exception/MemberClubExceptionType.java @@ -10,7 +10,7 @@ @AllArgsConstructor public enum MemberClubExceptionType implements ExceptionType { ALREADY_JOIN(BAD_REQUEST, 301, "이미 가입한 모임입니다."), - MEMBERCLUB_NOT_FOUND(NOT_FOUND, 302, "위임 또는 추방하려는 멤버가 모임 구성원이 아닙니다."); + MEMBERCLUB_NOT_FOUND(NOT_FOUND, 302, "모임에서 멤버를 찾을 수 없습니다."); ; private final HttpStatus status; diff --git a/backend/src/main/java/com/project/capstone/post/controller/PostController.java b/backend/src/main/java/com/project/capstone/post/controller/PostController.java new file mode 100644 index 0000000000..ece40121e5 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/post/controller/PostController.java @@ -0,0 +1,36 @@ +package com.project.capstone.post.controller; + +import com.project.capstone.auth.domain.PrincipalDetails; +import com.project.capstone.post.controller.dto.PostCreateRequest; +import com.project.capstone.post.controller.dto.PostResponse; +import com.project.capstone.post.service.PostService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/post") +public class PostController { + + private final PostService postService; + + // 게시글 작성하기 + @PostMapping("/create") + public ResponseEntity createPost(@AuthenticationPrincipal PrincipalDetails details, + @RequestBody PostCreateRequest request, @RequestParam Long clubId) { + postService.createPost(details.getUserId(), request, clubId); + return ResponseEntity.ok().body("게시글 생성"); + } + + // 게시글 조회 + @GetMapping("/{postId}") + public ResponseEntity getPost(@AuthenticationPrincipal PrincipalDetails details, + @PathVariable Long postId, @RequestParam Long clubId) { + PostResponse postResponse = postService.getPost(details.getUserId(), postId, clubId); + return ResponseEntity.ok().body(postResponse); + } + + +} diff --git a/backend/src/main/java/com/project/capstone/post/controller/dto/PostCreateRequest.java b/backend/src/main/java/com/project/capstone/post/controller/dto/PostCreateRequest.java new file mode 100644 index 0000000000..8659e882bd --- /dev/null +++ b/backend/src/main/java/com/project/capstone/post/controller/dto/PostCreateRequest.java @@ -0,0 +1,10 @@ +package com.project.capstone.post.controller.dto; + +import java.util.UUID; + +public record PostCreateRequest( + String title, + String body, + boolean isSticky +) { +} diff --git a/backend/src/main/java/com/project/capstone/post/controller/dto/PostResponse.java b/backend/src/main/java/com/project/capstone/post/controller/dto/PostResponse.java new file mode 100644 index 0000000000..cf0f388231 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/post/controller/dto/PostResponse.java @@ -0,0 +1,22 @@ +package com.project.capstone.post.controller.dto; + +import com.project.capstone.comment.domain.Comment; +import com.project.capstone.post.domain.Post; + +import java.util.List; +import java.util.UUID; + +public record PostResponse( + Long id, + UUID memberId, + Long clubId, + String title, + String body, + boolean isSticky, + List comments + +) { + public PostResponse(Post post) { + this(post.getId(), post.getMember().getId(), post.getClub().getId(), post.getTitle(), post.getBody(), post.isSticky(), post.getComments()); + } +} diff --git a/backend/src/main/java/com/project/capstone/post/domain/Post.java b/backend/src/main/java/com/project/capstone/post/domain/Post.java index 18345c7e01..f8f21ad34e 100644 --- a/backend/src/main/java/com/project/capstone/post/domain/Post.java +++ b/backend/src/main/java/com/project/capstone/post/domain/Post.java @@ -1,5 +1,7 @@ package com.project.capstone.post.domain; +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonManagedReference; import com.project.capstone.club.domain.Club; import com.project.capstone.comment.domain.Comment; import com.project.capstone.member.domain.Member; @@ -33,12 +35,15 @@ public class Post { @Column(name = "is_sticky") private boolean isSticky; + @JsonManagedReference @OneToMany(mappedBy = "post") private List comments = new ArrayList<>(); + @JsonBackReference @ManyToOne private Member member; + @JsonBackReference @ManyToOne private Club club; } diff --git a/backend/src/main/java/com/project/capstone/post/domain/PostRepository.java b/backend/src/main/java/com/project/capstone/post/domain/PostRepository.java new file mode 100644 index 0000000000..e0dada89b9 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/post/domain/PostRepository.java @@ -0,0 +1,9 @@ +package com.project.capstone.post.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface PostRepository extends JpaRepository { + Optional findPostById(Long id); +} diff --git a/backend/src/main/java/com/project/capstone/post/exception/PostException.java b/backend/src/main/java/com/project/capstone/post/exception/PostException.java new file mode 100644 index 0000000000..4168b5751c --- /dev/null +++ b/backend/src/main/java/com/project/capstone/post/exception/PostException.java @@ -0,0 +1,10 @@ +package com.project.capstone.post.exception; + +import com.project.capstone.common.exception.BaseException; +import com.project.capstone.common.exception.ExceptionType; + +public class PostException extends BaseException { + public PostException(ExceptionType exceptionType) { + super(exceptionType); + } +} diff --git a/backend/src/main/java/com/project/capstone/post/exception/PostExceptionType.java b/backend/src/main/java/com/project/capstone/post/exception/PostExceptionType.java new file mode 100644 index 0000000000..38e2b81447 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/post/exception/PostExceptionType.java @@ -0,0 +1,33 @@ +package com.project.capstone.post.exception; + +import com.project.capstone.common.exception.ExceptionType; +import lombok.AllArgsConstructor; +import org.springframework.http.HttpStatus; + +import static org.springframework.http.HttpStatus.*; + +@AllArgsConstructor +public enum PostExceptionType implements ExceptionType { + POST_NOT_FOUND(NOT_FOUND, 401, "해당 게시글을 찾을 수 없습니다.") + ; + + + 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/post/service/PostService.java b/backend/src/main/java/com/project/capstone/post/service/PostService.java new file mode 100644 index 0000000000..8492fa9002 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/post/service/PostService.java @@ -0,0 +1,71 @@ +package com.project.capstone.post.service; + +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.member.domain.Member; +import com.project.capstone.member.domain.MemberRepository; +import com.project.capstone.member.exception.MemberException; +import com.project.capstone.memberclub.domain.MemberClubRepository; +import com.project.capstone.memberclub.exception.MemberClubException; +import com.project.capstone.memberclub.exception.MemberClubExceptionType; +import com.project.capstone.post.controller.dto.PostCreateRequest; +import com.project.capstone.post.controller.dto.PostResponse; +import com.project.capstone.post.domain.Post; +import com.project.capstone.post.domain.PostRepository; +import com.project.capstone.post.exception.PostException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +import static com.project.capstone.club.exception.ClubExceptionType.*; +import static com.project.capstone.member.exception.MemberExceptionType.MEMBER_NOT_FOUND; +import static com.project.capstone.memberclub.exception.MemberClubExceptionType.*; +import static com.project.capstone.post.exception.PostExceptionType.POST_NOT_FOUND; + +@Service +@RequiredArgsConstructor +@Slf4j +public class PostService { + + private final PostRepository postRepository; + private final MemberRepository memberRepository; + private final ClubRepository clubRepository; + private final MemberClubRepository memberClubRepository; + + public void createPost(String memberId, PostCreateRequest request, Long clubId) { + Member member = memberRepository.findMemberById(UUID.fromString(memberId)).orElseThrow( + () -> new MemberException(MEMBER_NOT_FOUND) + ); + Club club = clubRepository.findClubById(clubId).orElseThrow( + () -> new ClubException(CLUB_NOT_FOUND) + ); + + if (memberClubRepository.findMemberClubByMember_IdAndClub_Id(UUID.fromString(memberId), clubId).isEmpty()) { + throw new MemberClubException(MEMBERCLUB_NOT_FOUND); + } + + Post saved = postRepository.save(Post.builder() + .title(request.title()) + .body(request.body()) + .isSticky(request.isSticky()) + .member(member) + .club(club) + .build()); + + member.getPosts().add(saved); + club.getPosts().add(saved); + } + + public PostResponse getPost(String memberId, Long id, Long clubId) { + Post post = postRepository.findPostById(id).orElseThrow( + () -> new PostException(POST_NOT_FOUND) + ); + if (memberClubRepository.findMemberClubByMember_IdAndClub_Id(UUID.fromString(memberId), clubId).isEmpty()) { + throw new MemberClubException(MEMBERCLUB_NOT_FOUND); + } + return new PostResponse(post); + } +} 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 diff --git a/backend/src/main/resources/data.sql b/backend/src/main/resources/data.sql index cd94ec6aaf..e0280d343d 100644 --- a/backend/src/main/resources/data.sql +++ b/backend/src/main/resources/data.sql @@ -41,3 +41,15 @@ insert into club (id, manager_id, topic, name, created_at, maximum, public_statu insert into club (id, manager_id, topic, name, created_at, maximum, public_status, password, book_id) values (8, UNHEX(REPLACE("8fbcec63-e527-10ee-bd3d-0242ac120002", "-","")), '사회', '길동4의 모임', '2023-05-26 15:48:57.450179', 10, 'PUBLIC', null, 3); +insert into member_club (id, member_id, club_id) values +(1, UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")), 1); + +insert into post (id, club_id, member_id, title, body, created_at, is_sticky) values +(1, 1, UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")), '게시글 제목 1', '게시글 내용 1', '2023-05-26 15:48:57.450179', true); + +insert into comment (id, post_id, member_id, body, created_at) values +(1, 1, UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")), "댓글 1", "2023-05-26 15:48:57.450179"); +insert into comment (id, post_id, member_id, body, created_at) values + (2, 1, UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")), "댓글 2", "2023-05-26 15:48:57.450179"); +insert into comment (id, post_id, member_id, body, created_at) values + (3, 1, UNHEX(REPLACE("3f06af63-a93c-11e4-9797-00505690773f", "-","")), "댓글 3", "2023-05-26 15:48:57.450179");