diff --git a/src/main/java/HookKiller/server/common/AbstractTimeStamp.java b/src/main/java/HookKiller/server/common/AbstractTimeStamp.java index 8ac865f..79e677d 100644 --- a/src/main/java/HookKiller/server/common/AbstractTimeStamp.java +++ b/src/main/java/HookKiller/server/common/AbstractTimeStamp.java @@ -5,6 +5,7 @@ import jakarta.persistence.EntityListeners; import jakarta.persistence.MappedSuperclass; import lombok.Getter; +import lombok.Setter; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @@ -12,6 +13,7 @@ import java.sql.Timestamp; @Getter +@Setter @MappedSuperclass @EntityListeners(value = {AuditingEntityListener.class}) public abstract class AbstractTimeStamp { @@ -20,9 +22,9 @@ public abstract class AbstractTimeStamp { nullable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") @CreatedDate - @JsonFormat( - shape = JsonFormat.Shape.STRING, - pattern = "yyyy-MM-dd hh:mm:ss") + @JsonFormat( + shape = JsonFormat.Shape.STRING, + pattern = "yyyy-MM-dd hh:mm:ss") private Timestamp createAt; @Column( diff --git a/src/main/java/HookKiller/server/common/type/NoticeArticleStatus.java b/src/main/java/HookKiller/server/common/type/ArticleStatus.java similarity index 73% rename from src/main/java/HookKiller/server/common/type/NoticeArticleStatus.java rename to src/main/java/HookKiller/server/common/type/ArticleStatus.java index 568f192..bdc0ba2 100644 --- a/src/main/java/HookKiller/server/common/type/NoticeArticleStatus.java +++ b/src/main/java/HookKiller/server/common/type/ArticleStatus.java @@ -3,6 +3,6 @@ import lombok.Getter; @Getter -public enum NoticeArticleStatus { +public enum ArticleStatus { PUBLIC, DELETE; } diff --git a/src/main/java/HookKiller/server/common/type/LanguageType.java b/src/main/java/HookKiller/server/common/type/LanguageType.java index 1a76479..e633155 100644 --- a/src/main/java/HookKiller/server/common/type/LanguageType.java +++ b/src/main/java/HookKiller/server/common/type/LanguageType.java @@ -5,6 +5,8 @@ import lombok.Getter; import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; @Getter @AllArgsConstructor @@ -25,4 +27,10 @@ public static LanguageType findType(String value) { public static LanguageType findTypeByRequest(HttpServletRequest request) { return request == null ? KO : findType(request.getHeader(HTTP_REQUEST_HEADER_KEY_LANGUAGE)); } + + public Set getTranslateTargetLanguage() { + return Arrays.stream(LanguageType.values()) + .filter(languageType -> !languageType.equals(this)) + .collect(Collectors.toSet()); + } } diff --git a/src/main/java/HookKiller/server/notice/controller/NoticeController.java b/src/main/java/HookKiller/server/notice/controller/NoticeController.java new file mode 100644 index 0000000..21eef9c --- /dev/null +++ b/src/main/java/HookKiller/server/notice/controller/NoticeController.java @@ -0,0 +1,88 @@ +package HookKiller.server.notice.controller; + +import HookKiller.server.common.type.LanguageType; +import HookKiller.server.notice.dto.AddNoticeRequest; +import HookKiller.server.notice.dto.EditNoticeRequest; +import HookKiller.server.notice.dto.NoticeArticleDto; +import HookKiller.server.notice.service.NoticeService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +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.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@Slf4j +@RestController +@RequiredArgsConstructor +@RequestMapping("/notice") +public class NoticeController { + + private final NoticeService noticeService; + + /** + * 단건 조회 + * + * @param noticeArticleId + * @param request + * @return + */ + @GetMapping("/{noticeArticleId}") + public NoticeArticleDto getNoticeArticle(@PathVariable Long noticeArticleId, HttpServletRequest request) { + log.info("공지사항 단건 조회 >>> {}", noticeArticleId); + return noticeService.getNoticeArticleByArticleId(noticeArticleId, LanguageType.findTypeByRequest(request)); + } + + /** + * 리스트 조회 + * + * @param request + * @return + */ + @GetMapping + public List getNoticeArticleList( + @RequestParam(defaultValue = "0", required = false) int page, + @RequestParam(defaultValue = "10", required = false) int articleLimit, + HttpServletRequest request + ) { + log.info("공지사항 리스트 조회"); + return noticeService.getNoticeList(page, articleLimit, LanguageType.findTypeByRequest(request)); + } + + /** + * 공지사항 등록 + */ + @PostMapping + public void addNotice(@RequestBody @Valid AddNoticeRequest request) { + log.info("공지사항 등록"); + noticeService.saveNotice(request); + } + + /** + * 공지사항 수정 + */ + @PutMapping + public void updateNotice(@RequestBody @Valid EditNoticeRequest request) { + log.info("공지사항 수정"); + noticeService.updateNotice(request); + } + + /** + * 공지사항 삭제 + */ + @DeleteMapping("/{noticeArticleId}") + public void deleteNotice(@PathVariable Long noticeArticleId) { + noticeService.deleteNotice(noticeArticleId); + } + +} + diff --git a/src/main/java/HookKiller/server/notice/dto/AddNoticeRequest.java b/src/main/java/HookKiller/server/notice/dto/AddNoticeRequest.java new file mode 100644 index 0000000..99ffb16 --- /dev/null +++ b/src/main/java/HookKiller/server/notice/dto/AddNoticeRequest.java @@ -0,0 +1,24 @@ +package HookKiller.server.notice.dto; + +import HookKiller.server.common.type.LanguageType; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +/** + * 공지사항 추가 요청 DTO + */ +@Getter +@Setter +public class AddNoticeRequest { + @NotNull(message = "언어 타입을 선택해야 합니다.") + private LanguageType language; + + @NotEmpty(message = "내용을 입력해주세요.") + private String title; + + @NotEmpty(message = "제목을 입력해주세요.") + private String content; + +} diff --git a/src/main/java/HookKiller/server/notice/dto/EditNoticeRequest.java b/src/main/java/HookKiller/server/notice/dto/EditNoticeRequest.java new file mode 100644 index 0000000..6335a08 --- /dev/null +++ b/src/main/java/HookKiller/server/notice/dto/EditNoticeRequest.java @@ -0,0 +1,26 @@ +package HookKiller.server.notice.dto; + +import HookKiller.server.common.type.LanguageType; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +/** + * 공지사항 수정 요청 DTO + */ +@Getter +@Setter +public class EditNoticeRequest { + @NotNull(message = "공지사항 게시물 ID가 입력되지 않았습니다.") + private Long noticeArticleId; + + @NotNull(message = "언어 타입을 선택해야 합니다.") + private LanguageType language; + + private String orgTitle; + private String newTitle; + + + private String orgContent; + private String newContent; +} diff --git a/src/main/java/HookKiller/server/notice/dto/NoticeArticleDto.java b/src/main/java/HookKiller/server/notice/dto/NoticeArticleDto.java new file mode 100644 index 0000000..6b2c341 --- /dev/null +++ b/src/main/java/HookKiller/server/notice/dto/NoticeArticleDto.java @@ -0,0 +1,41 @@ +package HookKiller.server.notice.dto; + +import HookKiller.server.common.AbstractTimeStamp; +import HookKiller.server.common.type.LanguageType; +import HookKiller.server.common.type.ArticleStatus; +import HookKiller.server.notice.entity.NoticeArticle; +import HookKiller.server.notice.entity.NoticeContent; +import HookKiller.server.user.entity.User; +import lombok.Builder; +import lombok.Getter; + +import java.sql.Timestamp; + +@Getter +@Builder +public class NoticeArticleDto extends AbstractTimeStamp { + + private Long id; + private LanguageType language; + private ArticleStatus status; + private User createdUser; + private User updatedUser; + private String content; + private String title; + private Timestamp createAt; + private Timestamp updateAt; + + public static NoticeArticleDto of(NoticeArticle noticeArticle, NoticeContent noticeContent) { + return NoticeArticleDto.builder() + .id(noticeArticle.getId()) + .language(noticeContent.getLanguage()) + .status(noticeArticle.getStatus()) + .createdUser(noticeArticle.getCreatedUser()) + .updatedUser(noticeArticle.getUpdatedUser()) + .content(noticeContent.getContent()) + .title(noticeContent.getTitle()) + .createAt(noticeArticle.getCreateAt()) + .updateAt(noticeArticle.getUpdateAt()) + .build(); + } +} diff --git a/src/main/java/HookKiller/server/notice/entity/NoticeArticle.java b/src/main/java/HookKiller/server/notice/entity/NoticeArticle.java index 410bb4b..e055356 100644 --- a/src/main/java/HookKiller/server/notice/entity/NoticeArticle.java +++ b/src/main/java/HookKiller/server/notice/entity/NoticeArticle.java @@ -1,59 +1,65 @@ package HookKiller.server.notice.entity; +import HookKiller.server.common.AbstractTimeStamp; +import HookKiller.server.common.type.ArticleStatus; import HookKiller.server.common.type.LanguageType; -import HookKiller.server.common.type.NoticeArticleStatus; -import jakarta.persistence.*; +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; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; -import java.sql.Timestamp; +import java.util.ArrayList; import java.util.List; -/** - * orgArticleLanguage : 원본으로 작성된 언어 타입. KOR:한국어, ENG:영어, CHI:중국어, JPN:일본어 - * status : 공지글 상태. PUBLIC:공개상태, DELETE:삭제처리 - * createdAt : 공지글 생성일 - * createdUser : 공지글 작성 사용자 ID입력. - * updatedAt : 공지글 정보 업데이트 일자 - * updatedUser : 마지막에 수정한 사용자 ID입력. - */ - @Entity @Getter +@Setter @Table(name = "tbl_notice_article") @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class NoticeArticle { +public class NoticeArticle extends AbstractTimeStamp { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToMany - private List content; + @OneToMany(mappedBy = "noticeArticle", fetch = FetchType.LAZY) + private List content = new ArrayList<>(); @Enumerated(EnumType.STRING) private LanguageType language; @Enumerated(EnumType.STRING) - private NoticeArticleStatus status; + private ArticleStatus status; + + @ManyToOne(fetch = FetchType.EAGER) + private User createdUser; - private Timestamp createdAt; - private Long createdUser; - private Timestamp updatedAt; - private Long updatedUser; + @ManyToOne(fetch = FetchType.EAGER) + private User updatedUser; @Builder - public NoticeArticle(Long id, List content, LanguageType language, - NoticeArticleStatus noticeArticleStatus, Timestamp createdAt, Long createdUser, Timestamp updatedAt, Long updatedUser) { + public NoticeArticle(Long id, LanguageType language, ArticleStatus status, User createdUser, + User updatedUser) { this.id = id; - this.content = content; this.language = language; - this.status = noticeArticleStatus; - this.createdAt = createdAt; + this.status = status; this.createdUser = createdUser; - this.updatedAt = updatedAt; this.updatedUser = updatedUser; } + + public void updateStatus(ArticleStatus status) { + this.status = status; + } } diff --git a/src/main/java/HookKiller/server/notice/entity/NoticeContent.java b/src/main/java/HookKiller/server/notice/entity/NoticeContent.java index 994646f..f88ff7b 100644 --- a/src/main/java/HookKiller/server/notice/entity/NoticeContent.java +++ b/src/main/java/HookKiller/server/notice/entity/NoticeContent.java @@ -1,17 +1,28 @@ package HookKiller.server.notice.entity; import HookKiller.server.common.type.LanguageType; -import jakarta.persistence.*; -import lombok.*; - -/** - * language : title, content가 적용된 언어 - * title : 공지사항 제목 - * content : 공지사항 내용 - */ +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; @Entity @Getter +@Setter +@ToString @Table(name = "tbl_notice_content") @NoArgsConstructor(access = AccessLevel.PROTECTED) public class NoticeContent { @@ -29,13 +40,11 @@ public class NoticeContent { private String title; - @Column @Lob private String content; @Builder - public NoticeContent(Long id, NoticeArticle noticeArticle, - LanguageType language, String title, String content) { + public NoticeContent(Long id, NoticeArticle noticeArticle,LanguageType language, String title, String content) { this.noticeArticle = noticeArticle; this.language = language; this.title = title; diff --git a/src/main/java/HookKiller/server/notice/exception/NoticeException.java b/src/main/java/HookKiller/server/notice/exception/NoticeException.java new file mode 100644 index 0000000..30b56e5 --- /dev/null +++ b/src/main/java/HookKiller/server/notice/exception/NoticeException.java @@ -0,0 +1,25 @@ +package HookKiller.server.notice.exception; + +import HookKiller.server.common.dto.ErrorDetail; +import HookKiller.server.common.exception.BaseErrorCode; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.NOT_FOUND; + +@Getter +@AllArgsConstructor +public enum NoticeException implements BaseErrorCode { + NOTICE_NOT_FOUND(NOT_FOUND.value(), "404-1", "요청한 공지사항 게시물이 존재하지 않습니다."), + NOTICE_NOT_AUTH(FORBIDDEN.value(), "404-2", "권한이 없습니다."); + + private final Integer statusCode; + private final String errorCode; + private final String reason; + + @Override + public ErrorDetail getErrorDetail() { + return ErrorDetail.of(statusCode, errorCode, reason); + } +} diff --git a/src/main/java/HookKiller/server/notice/exception/NoticeNotAdminForbiddenException.java b/src/main/java/HookKiller/server/notice/exception/NoticeNotAdminForbiddenException.java new file mode 100644 index 0000000..fbf7060 --- /dev/null +++ b/src/main/java/HookKiller/server/notice/exception/NoticeNotAdminForbiddenException.java @@ -0,0 +1,13 @@ +package HookKiller.server.notice.exception; + +import HookKiller.server.common.exception.BaseException; + +import static HookKiller.server.notice.exception.NoticeException.NOTICE_NOT_AUTH; + +public class NoticeNotAdminForbiddenException extends BaseException { + public static final BaseException EXCEPTION = new NoticeNotAdminForbiddenException(); + + private NoticeNotAdminForbiddenException() { + super(NOTICE_NOT_AUTH); + } +} diff --git a/src/main/java/HookKiller/server/notice/exception/NoticeNotFoundException.java b/src/main/java/HookKiller/server/notice/exception/NoticeNotFoundException.java new file mode 100644 index 0000000..cd29776 --- /dev/null +++ b/src/main/java/HookKiller/server/notice/exception/NoticeNotFoundException.java @@ -0,0 +1,13 @@ +package HookKiller.server.notice.exception; + +import HookKiller.server.common.exception.BaseException; + +import static HookKiller.server.notice.exception.NoticeException.NOTICE_NOT_FOUND; + +public class NoticeNotFoundException extends BaseException { + public static final BaseException EXCEPTION = new NoticeNotFoundException(); + + private NoticeNotFoundException() { + super(NOTICE_NOT_FOUND); + } +} diff --git a/src/main/java/HookKiller/server/notice/repository/NoticeArticleRepository.java b/src/main/java/HookKiller/server/notice/repository/NoticeArticleRepository.java new file mode 100644 index 0000000..276f93a --- /dev/null +++ b/src/main/java/HookKiller/server/notice/repository/NoticeArticleRepository.java @@ -0,0 +1,19 @@ +package HookKiller.server.notice.repository; + +import HookKiller.server.common.type.ArticleStatus; +import HookKiller.server.notice.entity.NoticeArticle; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +public interface NoticeArticleRepository extends JpaRepository { + + List findAllByStatusOrderByCreateAtDesc(ArticleStatus status); + + Optional findByIdAndStatus(Long id, ArticleStatus status); + + Page findAllByStatusOrderByCreateAtDesc(ArticleStatus status, Pageable pageable); +} diff --git a/src/main/java/HookKiller/server/repository/NoticeContentRepository.java b/src/main/java/HookKiller/server/notice/repository/NoticeContentRepository.java similarity index 75% rename from src/main/java/HookKiller/server/repository/NoticeContentRepository.java rename to src/main/java/HookKiller/server/notice/repository/NoticeContentRepository.java index 64ccbd4..7875ad4 100644 --- a/src/main/java/HookKiller/server/repository/NoticeContentRepository.java +++ b/src/main/java/HookKiller/server/notice/repository/NoticeContentRepository.java @@ -1,13 +1,15 @@ -package HookKiller.server.repository; +package HookKiller.server.notice.repository; import HookKiller.server.common.type.LanguageType; import HookKiller.server.notice.entity.NoticeArticle; import HookKiller.server.notice.entity.NoticeContent; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; public interface NoticeContentRepository extends JpaRepository { Optional findByNoticeArticleAndLanguage(NoticeArticle noticeArticle, LanguageType languageType); + + List findAllByNoticeArticle(NoticeArticle noticeArticle); } diff --git a/src/main/java/HookKiller/server/notice/service/NoticeService.java b/src/main/java/HookKiller/server/notice/service/NoticeService.java new file mode 100644 index 0000000..6a1c8f0 --- /dev/null +++ b/src/main/java/HookKiller/server/notice/service/NoticeService.java @@ -0,0 +1,237 @@ +package HookKiller.server.notice.service; + +import HookKiller.server.common.service.TranslateService; +import HookKiller.server.common.type.LanguageType; +import HookKiller.server.common.util.UserUtils; +import HookKiller.server.notice.dto.AddNoticeRequest; +import HookKiller.server.notice.dto.EditNoticeRequest; +import HookKiller.server.notice.dto.NoticeArticleDto; +import HookKiller.server.notice.entity.NoticeArticle; +import HookKiller.server.notice.entity.NoticeContent; +import HookKiller.server.notice.exception.NoticeNotAdminForbiddenException; +import HookKiller.server.notice.exception.NoticeNotFoundException; +import HookKiller.server.notice.repository.NoticeArticleRepository; +import HookKiller.server.notice.repository.NoticeContentRepository; +import HookKiller.server.user.entity.User; +import HookKiller.server.user.type.UserRole; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +import static HookKiller.server.common.type.ArticleStatus.DELETE; +import static HookKiller.server.common.type.ArticleStatus.PUBLIC; + +@Slf4j +@Service +@RequiredArgsConstructor +public class NoticeService { + private final TranslateService translateService; + private final NoticeArticleRepository noticeArticleRepository; + private final NoticeContentRepository noticeContentRepository; + private final UserUtils userUtils; + + /** + * 단건 조회 + * + * @param noticeArticleId + * @param languageType + * @return + */ + @Transactional(readOnly = true) + public NoticeArticleDto getNoticeArticleByArticleId(Long noticeArticleId, LanguageType languageType) { + NoticeArticle article = noticeArticleRepository.findByIdAndStatus(noticeArticleId, PUBLIC) + .orElseThrow(() -> NoticeNotFoundException.EXCEPTION); + NoticeContent content = noticeContentRepository.findByNoticeArticleAndLanguage(article, languageType) + .orElseThrow(() -> NoticeNotFoundException.EXCEPTION); + return NoticeArticleDto.of(article, content); + } + + /** + * 리스트 조회 - 사용자가 요청한 languageType에 맞춰서 List조회 + * 1. ArticleStatus가 공개중(PUBLIC)인 상태 + * 2. 생성일이 최신 순서로 + * 3. Content에서 선택한 언어로 번역된 데이터가 존재하는 경우 + * TODO : 페이지네이션 + * + * @return + */ + @Transactional(readOnly = true) + public List getNoticeList(int page, int articleLimit, LanguageType languageType) { + return noticeArticleRepository.findAllByStatusOrderByCreateAtDesc(PUBLIC, PageRequest.of(page, articleLimit)) + .stream() + .filter(noticeArticle -> noticeArticle.getContent().stream().anyMatch(noticeContent -> noticeContent.getLanguage().equals(languageType))) + .map(noticeArticle -> { + //그래봐야 Filter로 존재하는 애들만 걸러져서 의미없음 + NoticeContent noticeContent = noticeArticle.getContent() + .stream() + .filter(content -> content.getLanguage().equals(languageType)) + .findFirst() + .orElseThrow(() -> NoticeNotFoundException.EXCEPTION); + return NoticeArticleDto.builder() + .id(noticeArticle.getId()) + .language(noticeArticle.getLanguage()) + .status(noticeArticle.getStatus()) + .createdUser(noticeArticle.getCreatedUser()) + .updatedUser(noticeArticle.getUpdatedUser()) + .title(noticeContent.getTitle()) + .build(); + }) + .toList(); + } + + /** + * 공지사항 게시물 등록 + * 1. 사용자가 로그인을 하지 않은 경우 → UserNotFoundException이 발생한다. + * 2. 사용자가 로그인을 하였지만 관리자가 아닌 경우 → NoticeNotAdminForbiddenException이 발생한다. + * 3. 번역이 실패한 경우 → NaverErrorException이 발생한다. + * + * @param addNoticeRequest + */ + @Transactional + public void saveNotice(AddNoticeRequest addNoticeRequest) { + //로그인한 사용자 획득 + User user = userUtils.getUser(); + + //관리자 권한 확인 + if(user.getRole().equals(UserRole.ADMIN)) + throw NoticeNotAdminForbiddenException.EXCEPTION; + + NoticeArticle noticeArticle = noticeArticleRepository.save( + NoticeArticle.builder() + .language(addNoticeRequest.getLanguage()) + .status(PUBLIC) + .createdUser(user) + .updatedUser(user) + .build() + ); + + List contentsList = new ArrayList<>(); + contentsList.add( + NoticeContent.builder() + .noticeArticle(noticeArticle) + .language(addNoticeRequest.getLanguage()) + .title(addNoticeRequest.getTitle()) + .content(addNoticeRequest.getContent()) + .build() + ); + + addNoticeRequest + .getLanguage() + .getTranslateTargetLanguage() + .forEach(targetLanguage -> + contentsList.add( + NoticeContent + .builder() + .noticeArticle(noticeArticle) + .language(targetLanguage) + .title( + translateService.naverPapagoTextTranslate( + addNoticeRequest.getLanguage(), targetLanguage, addNoticeRequest.getTitle() + ) + ).content( + translateService.naverPapagoHtmlTranslate( + addNoticeRequest.getLanguage(), targetLanguage, addNoticeRequest.getContent() + ) + ).build() + ) + ); + + noticeContentRepository.saveAll(contentsList); + } + + /** + * 게시물 수정 + * 1. 사용자가 로그인을 하지 않은 경우 → UserNotFoundException이 발생한다. + * 2. 사용자가 로그인을 하였지만 관리자가 아닌 경우 → NoticeNotAdminForbiddenException이 발생한다. + * 3. 공지사항 게시물이 NoticeArticleId와 공개상태인지로 조회시 존재하지 않는 경우 → NoticeNotFoundException이 발생한다. + * 4. 요청한 언어가 DB에 없는 경우 → NoticeNotFoundException이 발생한다 + * 5. 번역이 실패한 경우 → NaverErrorException이 발생한다. + * + * 어떤 경우도 Exception이 발생하면 수정이 적용되지 않고 Rollback된다. + * + * @param request + */ + @Transactional + public void updateNotice(EditNoticeRequest request) { + //로그인한 사용자 획득 + User user = userUtils.getUser(); + + //관리자 권한 확인 + if(user.getRole().equals(UserRole.ADMIN)) + throw NoticeNotAdminForbiddenException.EXCEPTION; + + // 변경여부 확인을 위한 변수 + boolean chgTitle = false; + boolean chgContent = false; + + //게시물이 공개중이어야 수정가능함 + NoticeArticle article = noticeArticleRepository.findByIdAndStatus(request.getNoticeArticleId(), PUBLIC) + .orElseThrow(() -> NoticeNotFoundException.EXCEPTION); + List contents = noticeContentRepository.findAllByNoticeArticle(article); + + + article.setUpdatedUser(user); + //다른경우 변경 + if (!request.getLanguage().equals(article.getLanguage())) + article.setLanguage(request.getLanguage()); + + NoticeContent choiceContent = contents.stream() + .filter(content -> request.getLanguage().equals(content.getLanguage())) + .findFirst() + .orElseThrow(() -> NoticeNotFoundException.EXCEPTION); + + if (request.getNewTitle() != null && !request.getNewTitle().equals(request.getOrgTitle())) { + chgTitle = true; + choiceContent.setTitle(request.getNewTitle()); + } + if (request.getNewContent() != null && !request.getNewContent().equals(request.getOrgContent())) { + chgContent = true; + choiceContent.setContent(request.getNewContent()); + } + + if (chgTitle || chgContent) { + //Lambda에서 활용하기 위한 final변수 변환 + final boolean finalChgTitle = chgTitle; + final boolean finalChgContent = chgContent; + contents.stream() + .filter(content -> choiceContent != content) + .forEach(content -> { + if (finalChgTitle) { + translateService.naverPapagoTextTranslate(choiceContent.getLanguage(), content.getLanguage(), choiceContent.getTitle()); + } + if (finalChgContent) { + translateService.naverPapagoHtmlTranslate(choiceContent.getLanguage(), content.getLanguage(), choiceContent.getContent()); + } + } + ); + } + + } + + /** + * 공지사항 게시물 삭제 + * 1. 사용자가 로그인을 하지 않은 경우 → UserNotFoundException이 발생한다. + * 2. 사용자가 로그인을 하였지만 관리자가 아닌 경우 → NoticeNotAdminForbiddenException이 발생한다. + * + * @param id + */ + @Transactional + public void deleteNotice(Long id) { + //로그인한 사용자 획득 + User user = userUtils.getUser(); + + //관리자 권한 확인 + if(user.getRole().equals(UserRole.ADMIN)) + throw NoticeNotAdminForbiddenException.EXCEPTION; + + noticeArticleRepository.findById(id).orElseThrow(() -> + NoticeNotFoundException.EXCEPTION).updateStatus(DELETE); + } + +} diff --git a/src/main/java/HookKiller/server/repository/NoticeArticleRepository.java b/src/main/java/HookKiller/server/repository/NoticeArticleRepository.java deleted file mode 100644 index 5dc2cb3..0000000 --- a/src/main/java/HookKiller/server/repository/NoticeArticleRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package HookKiller.server.repository; - -import HookKiller.server.notice.entity.NoticeArticle; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface NoticeArticleRepository extends JpaRepository { - NoticeArticle findAllById(NoticeArticle noticeArticle); - -} diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 2ecc533..d7e07c8 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -7,7 +7,7 @@ hook: password: hooklocal1234! port: 3306 -# Test용 (Mr.재운DB) +# Test용 spring: diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 24496ed..03e9625 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -9,6 +9,206 @@ select 1 from dual; insert into tbl_user (email, password, nick_name, role) values ("admin@test.com", "1111", "관리자", "ADMIN"); - insert into tbl_user (email, password, nick_name, role) values ("user@test.com", "1111", "사용자", "USER"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-09-20 10:00:00", 1, "2023-09-21 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (1, "KO", "title1", "content1"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-09-21 10:00:00", 1, "2023-09-22 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (2, "KO", "title2", "content2"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-09-22 10:00:00", 1, "2023-09-23 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (3, "KO", "title3", "content3"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-09-23 10:00:00", 1, "2023-09-24 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (4, "KO", "title4", "content4"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-09-24 10:00:00", 1, "2023-09-25 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (5, "KO", "title5", "content5"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-09-25 10:00:00", 1, "2023-09-26 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (6, "KO", "title6", "content6"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-09-26 10:00:00", 1, "2023-09-27 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (7, "KO", "title7", "content7"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-09-27 10:00:00", 1, "2023-09-28 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (8, "KO", "title8", "content8"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-09-28 10:00:00", 1, "2023-09-28 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (9, "KO", "title9", "content9"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-09-29 10:00:00", 1, "2023-09-30 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (10, "KO", "title10", "content10"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-01 10:00:00", 1, "2023-10-02 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (11, "KO", "title11", "content11"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-02 10:00:00", 1, "2023-10-03 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (12, "KO", "title12", "content12"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-03 10:00:00", 1, "2023-10-04 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (13, "KO", "title13", "content13"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-04 10:00:00", 1, "2023-10-05 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (14, "KO", "title14", "content14"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-05 10:00:00", 1, "2023-10-06 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (15, "KO", "title15", "content15"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-06 10:00:00", 1, "2023-10-07 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (16, "KO", "title16", "content16"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-08 10:00:00", 1, "2023-10-09 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (17, "KO", "title17", "content17"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-10 10:00:00", 1, "2023-10-11 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (18, "KO", "title18", "content18"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-12 10:00:00", 1, "2023-10-13 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (19, "KO", "title19", "content19"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-13 10:00:00", 1, "2023-10-14 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (20, "KO", "title20", "content20"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-15 10:00:00", 1, "2023-10-16 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (21, "KO", "title21", "content21"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-17 10:00:00", 1, "2023-10-18 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (22, "KO", "title22", "content22"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-19 10:00:00", 1, "2023-10-20 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (23, "KO", "title23", "content23"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-21 10:00:00", 1, "2023-10-22 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (24, "KO", "title24", "content24"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-23 10:00:00", 1, "2023-10-24 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (25, "KO", "title25", "content25"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-25 10:00:00", 1, "2023-10-26 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (26, "KO", "title26", "content26"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-27 10:00:00", 1, "2023-10-28 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (27, "KO", "title27", "content27"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-29 10:00:00", 1, "2023-10-30 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (28, "KO", "title28", "content28"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-10-31 10:00:00", 1, "2023-11-01 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (29, "KO", "title29", "content29"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-02 10:00:00", 1, "2023-11-03 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (30, "KO", "title30", "content30"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-04 10:00:00", 1, "2023-11-05 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (31, "KO", "title31", "content31"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-06 10:00:00", 1, "2023-11-07 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (32, "KO", "title32", "content32"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-08 10:00:00", 1, "2023-11-09 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (33, "KO", "title33", "content33"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-10 10:00:00", 1, "2023-11-11 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (34, "KO", "title34", "content34"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-12 10:00:00", 1, "2023-11-13 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (35, "KO", "title35", "content35"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-14 10:00:00", 1, "2023-11-15 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (36, "KO", "title36", "content36"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-16 10:00:00", 1, "2023-11-17 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (37, "KO", "title37", "content37"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-18 10:00:00", 1, "2023-11-19 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (38, "KO", "title38", "content38"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-20 10:00:00", 1, "2023-11-21 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (39, "KO", "title39", "content39"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-22 10:00:00", 1, "2023-11-23 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (40, "KO", "title40", "content40"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-24 10:00:00", 1, "2023-11-25 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (41, "KO", "title41", "content41"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-26 10:00:00", 1, "2023-11-27 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (42, "KO", "title42", "content42"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-11-28 10:00:00", 1, "2023-11-29 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (43, "KO", "title43", "content43"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-12-01 10:00:00", 1, "2023-12-02 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (44, "KO", "title44", "content44"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-12-02 10:00:00", 1, "2023-12-03 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (45, "KO", "title45", "content45"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-12-04 10:00:00", 1, "2023-12-05 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (46, "KO", "title46", "content46"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-12-06 10:00:00", 1, "2023-12-07 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (47, "KO", "title47", "content47"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-12-08 10:00:00", 1, "2023-12-09 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (48, "KO", "title48", "content48"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-12-10 10:00:00", 1, "2023-12-11 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (49, "KO", "title49", "content49"); + +insert into tbl_notice_article (language, status, created_at, created_user_id, update_at, updated_user_id) values ("KO", "PUBLIC", "2023-12-12 10:00:00", 1, "2023-12-13 10:00:00", 1); + +insert into tbl_notice_content (notice_id, language, title, content) values (50, "KO", "title50", "content50"); +