diff --git a/src/main/java/HookKiller/server/board/controller/ReplyController.java b/src/main/java/HookKiller/server/board/controller/ReplyController.java new file mode 100644 index 0000000..9811918 --- /dev/null +++ b/src/main/java/HookKiller/server/board/controller/ReplyController.java @@ -0,0 +1,44 @@ +package HookKiller.server.board.controller; + +import HookKiller.server.board.dto.ReplyResponseDto; +import HookKiller.server.board.service.ReplyService; +import HookKiller.server.common.type.LanguageType; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Slf4j +@RestController +@RequestMapping("/reply") +@RequiredArgsConstructor +public class ReplyController { + + private final ReplyService replyService; + + @PostMapping + public void createReply(@RequestBody ReplyResponseDto responseDto) { + replyService.createReply(responseDto); + } + + @GetMapping("/{articleId}") + public List getReplyList(@PathVariable Long articleId, HttpServletRequest request) { + return replyService.getReplyList(articleId, LanguageType.findTypeByRequest(request)); + } + + @DeleteMapping("/{replyId}") + public ResponseEntity deleteReply(@PathVariable Long replyId) { + replyService.deleteReply(replyId); + return ResponseEntity.ok("삭제처리가 완료되었습니다."); + } + +} diff --git a/src/main/java/HookKiller/server/board/dto/ReplyResponseDto.java b/src/main/java/HookKiller/server/board/dto/ReplyResponseDto.java new file mode 100644 index 0000000..200298c --- /dev/null +++ b/src/main/java/HookKiller/server/board/dto/ReplyResponseDto.java @@ -0,0 +1,38 @@ +package HookKiller.server.board.dto; + + +import HookKiller.server.board.entity.Reply; +import HookKiller.server.board.entity.ReplyContent; +import HookKiller.server.common.AbstractTimeStamp; +import HookKiller.server.common.type.LanguageType; +import HookKiller.server.user.entity.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ReplyResponseDto extends AbstractTimeStamp { + + private Long articleId; + + private Long replyId; + + private LanguageType orgReplyLanguage; + + private User createUser; + + private String content; + + public static ReplyResponseDto of(Reply reply, ReplyContent replyContent) { + return ReplyResponseDto.builder() + .replyId(reply.getId()) + .createUser(reply.getCreatedUser()) + .content(replyContent.getContent()) + .build(); + } + +} diff --git a/src/main/java/HookKiller/server/board/entity/Reply.java b/src/main/java/HookKiller/server/board/entity/Reply.java index a1b657f..1381b40 100644 --- a/src/main/java/HookKiller/server/board/entity/Reply.java +++ b/src/main/java/HookKiller/server/board/entity/Reply.java @@ -1,7 +1,12 @@ package HookKiller.server.board.entity; +import HookKiller.server.board.type.ReplyStatus; import HookKiller.server.common.AbstractTimeStamp; +import HookKiller.server.common.type.LanguageType; +import HookKiller.server.user.entity.User; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -10,7 +15,10 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -32,20 +40,47 @@ @Getter @Table(name = "tbl_reply") @NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor public class Reply extends AbstractTimeStamp { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToMany(mappedBy = "reply", fetch = FetchType.EAGER) + private List replyContent; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="article_id") private Article article; - @OneToMany(mappedBy = "reply") - private List replyContent; + @NotNull + private LanguageType orgReplyLanguage; + + @NotNull + @Enumerated(EnumType.STRING) + private ReplyStatus replyStatus; + + @NotNull + @ManyToOne(fetch = FetchType.EAGER) + private User createdUser; + + @NotNull + @ManyToOne(fetch = FetchType.EAGER) + private User updatedUser; + + @Builder + public Reply(Long id, LanguageType orgReplyLanguage, ReplyStatus replyStatus, + User createdUser, User updatedUser) { + this.id = id; + this.orgReplyLanguage = orgReplyLanguage; + this.replyStatus = replyStatus; + this.createdUser = createdUser; + this.updatedUser = updatedUser; + } + + public void updateStatus(ReplyStatus status) { + replyStatus = status; + } - private String orgReplyLanguage; - private boolean isDeleted; - private Long createdUserId; - private Long updatedUserId; } diff --git a/src/main/java/HookKiller/server/board/entity/ReplyContent.java b/src/main/java/HookKiller/server/board/entity/ReplyContent.java index f4f2266..349c527 100644 --- a/src/main/java/HookKiller/server/board/entity/ReplyContent.java +++ b/src/main/java/HookKiller/server/board/entity/ReplyContent.java @@ -13,6 +13,7 @@ import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -28,7 +29,7 @@ public class ReplyContent { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private long id; + private Long id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name="reply_id") @@ -41,5 +42,12 @@ public class ReplyContent { @Lob private String content; + @Builder + public ReplyContent(Long id, Reply reply, LanguageType language, String content) { + this.id = id; + this.reply = reply; + this.language = language; + this.content = content; + } } diff --git a/src/main/java/HookKiller/server/board/exception/BoardException.java b/src/main/java/HookKiller/server/board/exception/BoardException.java index 92c0e27..e4024b4 100644 --- a/src/main/java/HookKiller/server/board/exception/BoardException.java +++ b/src/main/java/HookKiller/server/board/exception/BoardException.java @@ -13,7 +13,8 @@ public enum BoardException implements BaseErrorCode { BOARD_NOT_FOUND_ERROR(NOT_FOUND.value(), "Board_404_1", "해당 게시판을 찾을 수 없습니다."), - ARTICLE_CONTENT_NOT_FOUND_ERROR(NOT_FOUND.value(), "ArticleContent_404_1", "해당 게시글을 찾을 수 없습니다."); + ARTICLE_CONTENT_NOT_FOUND_ERROR(NOT_FOUND.value(), "ArticleContent_404_1", "해당 게시글을 찾을 수 없습니다."), + REPLY_CONTENT_NOT_FOUND_ERROR(NOT_FOUND.value(), "ReplyContent_404_1", "해당 댓글을 찾을 수 없습니다."); private final Integer statusCode; private final String errorCode; diff --git a/src/main/java/HookKiller/server/board/exception/ReplyContentNotFoundException.java b/src/main/java/HookKiller/server/board/exception/ReplyContentNotFoundException.java new file mode 100644 index 0000000..8842685 --- /dev/null +++ b/src/main/java/HookKiller/server/board/exception/ReplyContentNotFoundException.java @@ -0,0 +1,13 @@ +package HookKiller.server.board.exception; + +import HookKiller.server.common.exception.BaseException; + +public class ReplyContentNotFoundException extends BaseException { + + public static final BaseException EXCEPTION = new ReplyContentNotFoundException(); + + private ReplyContentNotFoundException() { + super(BoardException.REPLY_CONTENT_NOT_FOUND_ERROR); + } + +} diff --git a/src/main/java/HookKiller/server/board/repository/ArticleRepository.java b/src/main/java/HookKiller/server/board/repository/ArticleRepository.java index 1495257..16f1ef0 100644 --- a/src/main/java/HookKiller/server/board/repository/ArticleRepository.java +++ b/src/main/java/HookKiller/server/board/repository/ArticleRepository.java @@ -7,13 +7,12 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; import java.util.Optional; public interface ArticleRepository extends JpaRepository { - List
findAllByBoardAndArticleStatus(Board board, ArticleStatus status); + Optional
findByIdAndArticleStatus(Long id, ArticleStatus status); diff --git a/src/main/java/HookKiller/server/board/repository/ReplyContentRepository.java b/src/main/java/HookKiller/server/board/repository/ReplyContentRepository.java index 2ed9d65..315c916 100644 --- a/src/main/java/HookKiller/server/board/repository/ReplyContentRepository.java +++ b/src/main/java/HookKiller/server/board/repository/ReplyContentRepository.java @@ -1,7 +1,13 @@ package HookKiller.server.board.repository; +import HookKiller.server.board.entity.Reply; import HookKiller.server.board.entity.ReplyContent; +import HookKiller.server.common.type.LanguageType; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface ReplyContentRepository extends JpaRepository { + + Optional findByReplyAndLanguage(Reply reply, LanguageType language); } diff --git a/src/main/java/HookKiller/server/board/repository/ReplyRepository.java b/src/main/java/HookKiller/server/board/repository/ReplyRepository.java index 0a42bfb..0074e2e 100644 --- a/src/main/java/HookKiller/server/board/repository/ReplyRepository.java +++ b/src/main/java/HookKiller/server/board/repository/ReplyRepository.java @@ -1,7 +1,12 @@ package HookKiller.server.board.repository; +import HookKiller.server.board.entity.Article; import HookKiller.server.board.entity.Reply; +import HookKiller.server.board.type.ReplyStatus; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + public interface ReplyRepository extends JpaRepository { + List findAllByArticleAndReplyStatus(Article article, ReplyStatus replyStatus); } diff --git a/src/main/java/HookKiller/server/board/service/ArticleContentService.java b/src/main/java/HookKiller/server/board/service/ArticleContentService.java index ada76df..6b4bcb6 100644 --- a/src/main/java/HookKiller/server/board/service/ArticleContentService.java +++ b/src/main/java/HookKiller/server/board/service/ArticleContentService.java @@ -4,6 +4,7 @@ import HookKiller.server.board.entity.Article; import HookKiller.server.board.entity.ArticleContent; import HookKiller.server.board.repository.ArticleContentRepository; +import HookKiller.server.common.service.TranslateService; import HookKiller.server.common.type.LanguageType; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -18,6 +19,7 @@ @RequiredArgsConstructor public class ArticleContentService { private final ArticleContentRepository articleContentRepository; + private final TranslateService translateService; public void createContent(PostArticleRequestDto requestDto, Article article) { @@ -30,8 +32,8 @@ public void createContent(PostArticleRequestDto requestDto, Article article) { languageType -> ArticleContent.builder() .article(article) .language(languageType) - // .title(getTranslatePapagoTextArticleContent(requestDto.getOrgArticleLanguage().getLanguageCode(), languageType.getLanguageCode(), requestDto.getTitle())) - // .content(getTranslatePapagoHTMLArticleContent(requestDto.getOrgArticleLanguage().getLanguageCode(), languageType.getLanguageCode(), requestDto.getContent())) + // .title(translateService.naverPapagoTextTranslate(requestDto.getOrgArticleLanguage(), languageType.getLanguageCode(), requestDto.getTitle())) + // .content(translateService.naverPapagoHtmlTranslate(requestDto.getOrgArticleLanguage(), languageType.getLanguageCode(), requestDto.getContent())) .build() ).toList() ); @@ -63,8 +65,9 @@ public void updateContent(PostArticleRequestDto requestDto, Article article) { existingContents.stream() .filter(content -> content.getLanguage().equals(languageType)) .forEach(content -> { - // content.articleUpdate(getTranslatePapagoTextArticleContent(requestDto.getOrgArticleLanguage().getLanguageCode(), languageType.getLanguageCode(), requestDto.getTitle()), - // getTranslatePapagoHTMLArticleContent(requestDto.getOrgArticleLanguage().getLanguageCode(), languageType.getLanguageCode(), requestDto.getContent())); + content.articleUpdate( + getTranslatePapagoTextArticleContent(requestDto.getOrgArticleLanguage().getLanguageCode(), languageType.getLanguageCode(), requestDto.getTitle()), + getTranslatePapagoHTMLArticleContent(requestDto.getOrgArticleLanguage().getLanguageCode(), languageType.getLanguageCode(), requestDto.getContent())); }); } } diff --git a/src/main/java/HookKiller/server/board/service/ArticleService.java b/src/main/java/HookKiller/server/board/service/ArticleService.java index e894ce7..310d567 100644 --- a/src/main/java/HookKiller/server/board/service/ArticleService.java +++ b/src/main/java/HookKiller/server/board/service/ArticleService.java @@ -21,7 +21,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; import java.util.List; import static HookKiller.server.board.type.ArticleStatus.PUBLIC; @@ -65,7 +64,7 @@ public Article createArticle(PostArticleRequestDto postArticleRequestDto) { User requestUser = userUtils.getUser(); return articleRepository.save(Article.builder() .board(board) - .articleStatus(PUBLIC) + .articleStatus(ArticleStatus.PUBLIC) .orgArticleLanguage(postArticleRequestDto.getOrgArticleLanguage()) .createdUser(requestUser) .updatedUser(requestUser) @@ -99,5 +98,4 @@ public void deleteArticle(Long articleId) { .orElseThrow(() -> ArticleContentNotFoundException.EXCEPTION) .updateStatus(ArticleStatus.DELETE); } - } diff --git a/src/main/java/HookKiller/server/board/service/ReplyService.java b/src/main/java/HookKiller/server/board/service/ReplyService.java new file mode 100644 index 0000000..40e80e9 --- /dev/null +++ b/src/main/java/HookKiller/server/board/service/ReplyService.java @@ -0,0 +1,105 @@ +package HookKiller.server.board.service; + +import HookKiller.server.board.dto.ReplyResponseDto; +import HookKiller.server.board.entity.Article; +import HookKiller.server.board.entity.Reply; +import HookKiller.server.board.entity.ReplyContent; +import HookKiller.server.board.exception.ArticleContentNotFoundException; +import HookKiller.server.board.exception.ReplyContentNotFoundException; +import HookKiller.server.board.repository.ArticleRepository; +import HookKiller.server.board.repository.ReplyContentRepository; +import HookKiller.server.board.repository.ReplyRepository; +import HookKiller.server.common.service.TranslateService; +import HookKiller.server.common.type.LanguageType; +import HookKiller.server.common.util.UserUtils; +import HookKiller.server.user.entity.User; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +import static HookKiller.server.board.type.ReplyStatus.FALSE; +import static HookKiller.server.board.type.ReplyStatus.TURE; + + +@Slf4j +@Service +@RequiredArgsConstructor +public class ReplyService { + + private final UserUtils userUtils; + private final ArticleRepository articleRepository; + private final ReplyRepository replyRepository; + private final ReplyContentRepository replyContentRepository; + private final TranslateService translateService; + + @Transactional + public void createReply(ReplyResponseDto responseDto) { + + User user = userUtils.getUser(); + + Reply reply = replyRepository.save( + Reply.builder() + .replyStatus(FALSE) + .orgReplyLanguage(responseDto.getOrgReplyLanguage()) + .createdUser(user) + .updatedUser(user) + .build() + ); + + List replyContentList = new ArrayList<>(); + replyContentList.add( + ReplyContent.builder() + .reply(reply) + .language(responseDto.getOrgReplyLanguage()) + .content(responseDto.getContent()) + .build() + ); + + responseDto + .getOrgReplyLanguage() + .getTranslateTargetLanguage() + .forEach(targetLanguage -> + replyContentList.add( + ReplyContent + .builder() + .reply(reply) + .language(targetLanguage) + .content( + translateService.naverPapagoTextTranslate( + responseDto.getOrgReplyLanguage(), targetLanguage, responseDto.getContent() + ) + ) + .build() + ) + ); + + replyContentRepository.saveAll(replyContentList); + } + + + @Transactional(readOnly = true) + public List getReplyList(Long articleId, LanguageType language) { + Article article = articleRepository.findById(articleId).orElseThrow(() -> ArticleContentNotFoundException.EXCEPTION); + List replyList = replyRepository.findAllByArticleAndReplyStatus(article, FALSE); + + return replyList.stream() + .map(reply -> + ReplyResponseDto.of(reply, replyContentRepository + .findByReplyAndLanguage(reply, language) + .orElseThrow(() -> ReplyContentNotFoundException.EXCEPTION))) + .toList(); + } + + @Transactional + public void deleteReply(Long replyId) { + replyRepository + .findById(replyId) + .orElseThrow(() -> ReplyContentNotFoundException.EXCEPTION) + .updateStatus(TURE); + } + +} diff --git a/src/main/java/HookKiller/server/board/type/ReplyStatus.java b/src/main/java/HookKiller/server/board/type/ReplyStatus.java new file mode 100644 index 0000000..288b366 --- /dev/null +++ b/src/main/java/HookKiller/server/board/type/ReplyStatus.java @@ -0,0 +1,13 @@ +package HookKiller.server.board.type; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum ReplyStatus { + FALSE("공개상태"), + TURE("삭제처리"); + + private final String typeName; +} diff --git a/src/main/java/HookKiller/server/common/service/TranslateService.java b/src/main/java/HookKiller/server/common/service/TranslateService.java index 18eb9a0..45774bd 100644 --- a/src/main/java/HookKiller/server/common/service/TranslateService.java +++ b/src/main/java/HookKiller/server/common/service/TranslateService.java @@ -1,6 +1,7 @@ package HookKiller.server.common.service; -import HookKiller.server.common.dto.*; +import HookKiller.server.common.dto.PapagoTextRequest; +import HookKiller.server.common.dto.PapagoTextResponse; import HookKiller.server.common.exception.NaverErrorException; import HookKiller.server.common.type.LanguageType; import HookKiller.server.properties.PapagoProperties; @@ -8,14 +9,12 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.*; -import org.springframework.http.converter.FormHttpMessageConverter; import org.springframework.stereotype.Service; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; import java.net.URI; -import java.util.HashMap; import java.util.Map; @Slf4j diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 48f75cd..d7e07c8 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -1,8 +1,8 @@ # TODO : 각자 개발용 URL, 개인 Database명 입력 필요, 해당 2개의 속성은 커밋 제외 필수!!!!! hook: db: - url: db-it7f7-kr.vpc-pub-cdb.ntruss.com - database: jh + url: + database: username: hooklocal password: hooklocal1234! port: 3306