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/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..615f658e6a --- /dev/null +++ b/backend/src/main/java/com/project/capstone/content/controller/ContentController.java @@ -0,0 +1,25 @@ +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.service.ContentService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@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("컨텐츠 생성 완료"); + } +} 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/domain/Content.java b/backend/src/main/java/com/project/capstone/content/domain/Content.java index d253becc2f..80ce953717 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 @@ -20,10 +20,13 @@ public class Content { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - private String type; + + @Enumerated(EnumType.STRING) + @Column(name = "content_type") + private ContentType type; private String title; private String body; - private String likes; + private int likes; @ManyToOne private Member member; 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..e9e3bb3baf --- /dev/null +++ b/backend/src/main/java/com/project/capstone/content/domain/ContentRepository.java @@ -0,0 +1,7 @@ +package com.project.capstone.content.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ContentRepository extends JpaRepository { + +} 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/service/ContentService.java b/backend/src/main/java/com/project/capstone/content/service/ContentService.java new file mode 100644 index 0000000000..3bd7c76703 --- /dev/null +++ b/backend/src/main/java/com/project/capstone/content/service/ContentService.java @@ -0,0 +1,72 @@ +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.domain.Content; +import com.project.capstone.content.domain.ContentRepository; +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.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; + +@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); + } + } +}