diff --git a/backend/src/main/java/org/sejongisc/backend/board/controller/BoardController.java b/backend/src/main/java/org/sejongisc/backend/board/controller/BoardController.java index 3b270d96..9c1e7c16 100644 --- a/backend/src/main/java/org/sejongisc/backend/board/controller/BoardController.java +++ b/backend/src/main/java/org/sejongisc/backend/board/controller/BoardController.java @@ -160,6 +160,34 @@ public ResponseEntity> getParentBoards( return ResponseEntity.ok(postService.getParentBoards()); } + + // 게시판 생성 + @Operation( + summary = "하위 게시판 목록 조회", + description = "하위 게시판 목록을 조회합니다." + ) + @GetMapping("/childs") + public ResponseEntity> getChildBoards( + @AuthenticationPrincipal CustomUserDetails customUserDetails) { + return ResponseEntity.ok(postService.getChildBoards()); + } + + // 게시글 삭제 + @Operation( + summary = "게시판 삭제", + description = "게시판 ID를 통해 게시판을 삭제합니다." + + "회장만 삭제할 수 있습니다." + + "관련 첨부파일 및 댓글 등도 함께 삭제됩니다." + ) + @DeleteMapping("/{boardId}") + public ResponseEntity deleteBoard( + @PathVariable UUID boardId, + @AuthenticationPrincipal CustomUserDetails customUserDetails) { + UUID userId = customUserDetails.getUserId(); + postService.deleteBoard(boardId, userId); + return ResponseEntity.ok("게시판 삭제가 완료되었습니다."); + } + // 좋아요 토글 @Operation( summary = "좋아요 등록 및 취소", @@ -236,4 +264,7 @@ public void deleteComment( UUID userId = customUserDetails.getUserId(); postInteractionService.deleteComment(commentId, userId); } + + + } diff --git a/backend/src/main/java/org/sejongisc/backend/board/repository/BoardRepository.java b/backend/src/main/java/org/sejongisc/backend/board/repository/BoardRepository.java index 03639b72..8cc568a0 100644 --- a/backend/src/main/java/org/sejongisc/backend/board/repository/BoardRepository.java +++ b/backend/src/main/java/org/sejongisc/backend/board/repository/BoardRepository.java @@ -8,4 +8,7 @@ public interface BoardRepository extends JpaRepository { List findAllByParentBoardIsNull(); + List findAllByParentBoardIsNotNull(); + List findAllByParentBoard_BoardId(UUID parentBoardId); + } diff --git a/backend/src/main/java/org/sejongisc/backend/board/repository/PostRepository.java b/backend/src/main/java/org/sejongisc/backend/board/repository/PostRepository.java index ba03248d..83f292f5 100644 --- a/backend/src/main/java/org/sejongisc/backend/board/repository/PostRepository.java +++ b/backend/src/main/java/org/sejongisc/backend/board/repository/PostRepository.java @@ -1,8 +1,10 @@ package org.sejongisc.backend.board.repository; +import java.util.List; import java.util.UUID; import org.sejongisc.backend.board.entity.Board; import org.sejongisc.backend.board.entity.Post; +import org.sejongisc.backend.board.repository.projection.PostIdUserIdProjection; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -23,4 +25,11 @@ Page searchByBoardAndKeyword( @Param("board") Board board, @Param("keyword") String keyword, Pageable pageable); + + @Query(""" + select p.postId as postId, p.user.userId as userId + from Post p + where p.board.boardId = :boardId + """) + List findPostIdAndUserIdByBoardId(@Param("boardId") UUID boardId); } diff --git a/backend/src/main/java/org/sejongisc/backend/board/repository/projection/PostIdUserIdProjection.java b/backend/src/main/java/org/sejongisc/backend/board/repository/projection/PostIdUserIdProjection.java new file mode 100644 index 00000000..98c514b7 --- /dev/null +++ b/backend/src/main/java/org/sejongisc/backend/board/repository/projection/PostIdUserIdProjection.java @@ -0,0 +1,8 @@ +package org.sejongisc.backend.board.repository.projection; + +import java.util.UUID; + +public interface PostIdUserIdProjection { + UUID getPostId(); + UUID getUserId(); +} diff --git a/backend/src/main/java/org/sejongisc/backend/board/service/PostService.java b/backend/src/main/java/org/sejongisc/backend/board/service/PostService.java index 5af7d3fc..cabdbf9a 100644 --- a/backend/src/main/java/org/sejongisc/backend/board/service/PostService.java +++ b/backend/src/main/java/org/sejongisc/backend/board/service/PostService.java @@ -33,4 +33,7 @@ public interface PostService { // 부모 게시판 목록 조회 List getParentBoards(); + // 하위 게시판 목록 조회 + List getChildBoards(); + void deleteBoard(UUID boardId, UUID boardUserId); } diff --git a/backend/src/main/java/org/sejongisc/backend/board/service/PostServiceImpl.java b/backend/src/main/java/org/sejongisc/backend/board/service/PostServiceImpl.java index a0818442..85ce754f 100644 --- a/backend/src/main/java/org/sejongisc/backend/board/service/PostServiceImpl.java +++ b/backend/src/main/java/org/sejongisc/backend/board/service/PostServiceImpl.java @@ -1,7 +1,11 @@ package org.sejongisc.backend.board.service; import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.sejongisc.backend.board.dto.BoardRequest; @@ -20,10 +24,12 @@ import org.sejongisc.backend.board.repository.PostBookmarkRepository; import org.sejongisc.backend.board.repository.PostLikeRepository; import org.sejongisc.backend.board.repository.PostRepository; +import org.sejongisc.backend.board.repository.projection.PostIdUserIdProjection; import org.sejongisc.backend.common.exception.CustomException; import org.sejongisc.backend.common.exception.ErrorCode; import org.sejongisc.backend.user.dao.UserRepository; import org.sejongisc.backend.user.dto.UserInfoResponse; +import org.sejongisc.backend.user.entity.Role; import org.sejongisc.backend.user.entity.User; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -169,6 +175,28 @@ public void deletePost(UUID postId, UUID userId) { postRepository.delete(post); } + @Transactional + public void deleteBoard(UUID boardId, UUID boardUserId) { + User user = userRepository.findById(boardUserId).orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); + if(!user.getRole().equals(Role.PRESIDENT)){ + throw new CustomException(ErrorCode.INVALID_BOARD_OWNER); + } + //상위 게시판이면 하위 게시판 목록을 조회 + // 1. 부모 + 자식 boardId 목록 만들기 + List targetBoardIds = Stream.concat( + Stream.of(boardId), // 자신 포함 + boardRepository.findAllByParentBoard_BoardId(boardId).stream() + .map(Board::getBoardId) + ).toList(); + + // 2. 각 boardId마다 postId/userId 조회해서 삭제 + targetBoardIds.stream() + .flatMap(id -> postRepository.findPostIdAndUserIdByBoardId(id).stream()) + .forEach(row -> deletePost(row.getPostId(), row.getUserId())); + targetBoardIds.forEach(boardRepository::deleteById); + return; + } + // 게시물 조회 (해당 게시판의 게시물) @Override @Transactional(readOnly = true) @@ -307,6 +335,16 @@ public List getParentBoards() { .toList(); } + // 하위 게시판 조회 + @Transactional(readOnly = true) + public List getChildBoards() { + List childBoards = boardRepository.findAllByParentBoardIsNotNull(); + + return childBoards.stream() + .map(BoardResponse::from) + .toList(); + } + private PostResponse mapToPostResponse(Post post) { return PostResponse.builder() .postId(post.getPostId()) diff --git a/backend/src/main/java/org/sejongisc/backend/common/exception/ErrorCode.java b/backend/src/main/java/org/sejongisc/backend/common/exception/ErrorCode.java index 2a832846..64982b4b 100644 --- a/backend/src/main/java/org/sejongisc/backend/common/exception/ErrorCode.java +++ b/backend/src/main/java/org/sejongisc/backend/common/exception/ErrorCode.java @@ -87,6 +87,8 @@ public enum ErrorCode { POST_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 게시물을 찾을 수 없습니다."), + INVALID_BOARD_OWNER(HttpStatus.FORBIDDEN, "게시판 수정/삭제 권한이 없습니다."), + INVALID_POST_OWNER(HttpStatus.FORBIDDEN, "게시물 수정/삭제 권한이 없습니다."), COMMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 댓글을 찾을 수 없습니다."), @@ -101,6 +103,9 @@ public enum ErrorCode { INVALID_BOARD_TYPE(HttpStatus.BAD_REQUEST, "상위 게시판에는 글을 작성할 수 없습니다."); + + + private final HttpStatus status; private final String message;