Skip to content

Commit

Permalink
feat : Implement board delete API (#147)
Browse files Browse the repository at this point in the history
  • Loading branch information
hwangjokim authored Nov 5, 2024
1 parent 36f1b4c commit 506e516
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import com.gamzabat.algohub.feature.board.exception.BoardValidationExceoption;
import com.gamzabat.algohub.feature.board.exception.BoardValidationException;
import com.gamzabat.algohub.feature.comment.exception.CommentValidationException;
import com.gamzabat.algohub.feature.group.ranking.exception.CannotFoundRankingException;
import com.gamzabat.algohub.feature.group.studygroup.exception.CannotFoundGroupException;
Expand Down Expand Up @@ -101,8 +101,8 @@ protected ResponseEntity<ErrorResponse> handler(SolvedAcApiErrorException e) {
return ResponseEntity.status(e.getCode()).body(new ErrorResponse(e.getCode(), e.getError(), null));
}

@ExceptionHandler(BoardValidationExceoption.class)
protected ResponseEntity<ErrorResponse> handler(BoardValidationExceoption e) {
@ExceptionHandler(BoardValidationException.class)
protected ResponseEntity<ErrorResponse> handler(BoardValidationException e) {
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
.body(new ErrorResponse(HttpStatus.SERVICE_UNAVAILABLE.value(), e.getError(), null));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import org.springframework.http.ResponseEntity;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
Expand Down Expand Up @@ -66,4 +67,11 @@ public ResponseEntity<Void> updateBoard(@AuthedUser User user, @Valid @RequestBo
boardService.updateBoard(user, request);
return ResponseEntity.ok().build();
}

@DeleteMapping
@Operation(summary = "공지 삭제 API")
public ResponseEntity<Void> deleteBoard(@AuthedUser User user, @RequestParam Long boardId) {
boardService.deleteBoard(user, boardId);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import lombok.Getter;

@Getter
public class BoardValidationExceoption extends RuntimeException {
public class BoardValidationException extends RuntimeException {
private final String error;

public BoardValidationExceoption(String error) {
public BoardValidationException(String error) {
this.error = error;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

import com.gamzabat.algohub.feature.board.domain.Board;
import com.gamzabat.algohub.feature.board.domain.BoardComment;

public interface BoardCommentRepository extends JpaRepository<BoardComment, Long> {

List<BoardComment> findAllByBoard(Board board);

@Modifying
@Query("delete from BoardComment c where c.board = :board")
void deleteAllCommentByBoard(Board board);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import com.gamzabat.algohub.feature.board.domain.Board;
import com.gamzabat.algohub.feature.board.domain.BoardComment;
import com.gamzabat.algohub.feature.board.dto.CreateBoardCommentRequest;
import com.gamzabat.algohub.feature.board.exception.BoardValidationExceoption;
import com.gamzabat.algohub.feature.board.exception.BoardValidationException;
import com.gamzabat.algohub.feature.board.repository.BoardCommentRepository;
import com.gamzabat.algohub.feature.board.repository.BoardRepository;
import com.gamzabat.algohub.feature.comment.dto.GetCommentResponse;
Expand Down Expand Up @@ -106,7 +106,7 @@ public void deleteComment(User user, Long commentId) {

private Board validateBoard(User user, Long boardId) {
Board board = boardRepository.findById(boardId)
.orElseThrow(() -> new BoardValidationExceoption("공지사항이 존재하지 않습니다."));
.orElseThrow(() -> new BoardValidationException("공지사항이 존재하지 않습니다."));

StudyGroup group = studyGroupRepository.findById(board.getStudyGroup().getId())
.orElseThrow(() -> new StudyGroupValidationException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
import com.gamzabat.algohub.feature.board.dto.CreateBoardRequest;
import com.gamzabat.algohub.feature.board.dto.GetBoardResponse;
import com.gamzabat.algohub.feature.board.dto.UpdateBoardRequest;
import com.gamzabat.algohub.feature.board.exception.BoardValidationExceoption;
import com.gamzabat.algohub.feature.board.exception.BoardValidationException;
import com.gamzabat.algohub.feature.board.repository.BoardCommentRepository;
import com.gamzabat.algohub.feature.board.repository.BoardRepository;
import com.gamzabat.algohub.feature.group.studygroup.domain.GroupMember;
import com.gamzabat.algohub.feature.group.studygroup.domain.StudyGroup;
Expand All @@ -24,7 +25,6 @@
import com.gamzabat.algohub.feature.group.studygroup.repository.GroupMemberRepository;
import com.gamzabat.algohub.feature.group.studygroup.repository.StudyGroupRepository;
import com.gamzabat.algohub.feature.user.domain.User;
import com.gamzabat.algohub.feature.user.repository.UserRepository;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -35,7 +35,7 @@

public class BoardService {
private final BoardRepository boardRepository;
private final UserRepository userRepository;
private final BoardCommentRepository boardCommentRepository;
private final StudyGroupRepository studyGroupRepository;
private final GroupMemberRepository groupMemberRepository;

Expand Down Expand Up @@ -63,7 +63,7 @@ public void createBoard(@AuthedUser User user, CreateBoardRequest request) {
@Transactional(readOnly = true)
public GetBoardResponse getBoard(@AuthedUser User user, Long boardId) {
Board board = boardRepository.findById(boardId)
.orElseThrow(() -> new BoardValidationExceoption("존재하지 않는 공지입니다"));
.orElseThrow(() -> new BoardValidationException("존재하지 않는 게시글입니다"));
if (!groupMemberRepository.existsByUserAndStudyGroup(user, board.getStudyGroup()))
throw new StudyGroupValidationException(HttpStatus.FORBIDDEN.value(), "참여하지 않은 스터디 그룹 입니다.");

Expand Down Expand Up @@ -93,13 +93,32 @@ public List<GetBoardResponse> getBoardList(@AuthedUser User user, Long studyGrou
@Transactional
public void updateBoard(User user, UpdateBoardRequest request) {
Board board = boardRepository.findById(request.boardId())
.orElseThrow(() -> new BoardValidationExceoption("존재하지 않는 게시글입니다"));
StudyGroup studyGroup = studyGroupRepository.findById(board.getStudyGroup().getId())
.orElseThrow(() -> new StudyGroupValidationException(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 스터디 그룹입니다"));
.orElseThrow(() -> new BoardValidationException("존재하지 않는 게시글입니다"));
validateStudyGroupExists(board);
if (!user.getId().equals(board.getAuthor().getId()))
throw new UserValidationException("공지를 수정할 수 있는 권한이 없습니다");

board.updateBoard(request.title(), request.content());
}

@Transactional
public void deleteBoard(User user, Long boardId) {
Board board = boardRepository.findById(boardId)
.orElseThrow(() -> new BoardValidationException("존재하지 않는 게시글입니다"));
validateStudyGroupExists(board);

if (!user.getId().equals(board.getAuthor().getId()))
throw new UserValidationException("공지를 삭제할 수 있는 권한이 없습니다");

boardCommentRepository.deleteAllCommentByBoard(board);
boardRepository.delete(board);

log.info("success to delete board. userId: {}, boardId: {}", user.getId(), boardId);
}

private void validateStudyGroupExists(Board board) {
studyGroupRepository.findById(board.getStudyGroup().getId())
.orElseThrow(() -> new StudyGroupValidationException(HttpStatus.BAD_REQUEST.value(), "존재하지 않는 스터디 그룹입니다"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import com.gamzabat.algohub.feature.board.domain.Board;
import com.gamzabat.algohub.feature.board.domain.BoardComment;
import com.gamzabat.algohub.feature.board.dto.CreateBoardCommentRequest;
import com.gamzabat.algohub.feature.board.exception.BoardValidationExceoption;
import com.gamzabat.algohub.feature.board.exception.BoardValidationException;
import com.gamzabat.algohub.feature.board.repository.BoardCommentRepository;
import com.gamzabat.algohub.feature.board.repository.BoardRepository;
import com.gamzabat.algohub.feature.comment.domain.Comment;
Expand Down Expand Up @@ -109,7 +109,7 @@ void createComment_1() {
when(studyGroupRepository.findById(30L)).thenReturn(Optional.ofNullable(studyGroup));
when(groupMemberRepository.existsByUserAndStudyGroup(user2, studyGroup)).thenReturn(true);
when(commentRepository.save(any(BoardComment.class))).thenReturn(comment);

// when
commentService.createComment(user2, request);
// then
Expand All @@ -132,7 +132,7 @@ void createCommentFailed_1() {
when(boardRepository.findById(10L)).thenReturn(Optional.empty());
// when, then
assertThatThrownBy(() -> commentService.createComment(user, request))
.isInstanceOf(BoardValidationExceoption.class)
.isInstanceOf(BoardValidationException.class)
.hasFieldOrPropertyWithValue("error", "공지사항이 존재하지 않습니다.");
verify(notificationService, never()).send(any(), any(), any(), any());
}
Expand Down Expand Up @@ -225,7 +225,7 @@ void getCommentListFailed_1() {
when(boardRepository.findById(10L)).thenReturn(Optional.empty());
// when, then
assertThatThrownBy(() -> commentService.getCommentList(user, 10L))
.isInstanceOf(BoardValidationExceoption.class)
.isInstanceOf(BoardValidationException.class)
.hasFieldOrPropertyWithValue("error", "공지사항이 존재하지 않습니다.");
}

Expand Down Expand Up @@ -300,7 +300,7 @@ void deleteCommentFailed_3() {
when(commentRepository.findById(40L)).thenReturn(Optional.ofNullable(comment));
// when, then
assertThatThrownBy(() -> commentService.deleteComment(user, 40L))
.isInstanceOf(BoardValidationExceoption.class)
.isInstanceOf(BoardValidationException.class)
.hasFieldOrPropertyWithValue("error", "공지사항이 존재하지 않습니다.");
}

Expand Down
60 changes: 56 additions & 4 deletions src/test/java/com/gamzabat/algohub/service/BoardServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
import com.gamzabat.algohub.feature.board.dto.CreateBoardRequest;
import com.gamzabat.algohub.feature.board.dto.GetBoardResponse;
import com.gamzabat.algohub.feature.board.dto.UpdateBoardRequest;
import com.gamzabat.algohub.feature.board.exception.BoardValidationExceoption;
import com.gamzabat.algohub.feature.board.exception.BoardValidationException;
import com.gamzabat.algohub.feature.board.repository.BoardCommentRepository;
import com.gamzabat.algohub.feature.board.repository.BoardRepository;
import com.gamzabat.algohub.feature.board.service.BoardService;
import com.gamzabat.algohub.feature.group.studygroup.domain.GroupMember;
Expand All @@ -49,6 +50,8 @@ public class BoardServiceTest {
private BoardRepository boardRepository;
@Mock
GroupMemberRepository groupMemberRepository;
@Mock
private BoardCommentRepository boardCommentRepository;
@Captor
private ArgumentCaptor<Board> boardCaptor;

Expand Down Expand Up @@ -187,8 +190,8 @@ void getBoardFailed_1() {

//when, then
assertThatThrownBy(() -> boardService.getBoard(user, 1001L))
.isInstanceOf(BoardValidationExceoption.class)
.hasFieldOrPropertyWithValue("error", "존재하지 않는 공지입니다");
.isInstanceOf(BoardValidationException.class)
.hasFieldOrPropertyWithValue("error", "존재하지 않는 게시글입니다");

}

Expand Down Expand Up @@ -288,7 +291,7 @@ void updateBoardFailed_1() {
when(boardRepository.findById(1001L)).thenReturn(Optional.empty());
//when,then
assertThatThrownBy(() -> boardService.updateBoard(user, updateBoardRequest))
.isInstanceOf(BoardValidationExceoption.class)
.isInstanceOf(BoardValidationException.class)
.hasFieldOrPropertyWithValue("error", "존재하지 않는 게시글입니다");
}

Expand Down Expand Up @@ -320,4 +323,53 @@ void updateBoardFailed_3() {
.hasFieldOrPropertyWithValue("errors", "공지를 수정할 수 있는 권한이 없습니다");
}

@Test
@DisplayName("공지 삭제 성공")
void deleteBoardSuccess() {
//given
when(boardRepository.findById(1000L)).thenReturn(Optional.ofNullable(board));
when(studyGroupRepository.findById(30L)).thenReturn(Optional.ofNullable(studyGroup));
doNothing().when(boardCommentRepository).deleteAllCommentByBoard(board);
//when
boardService.deleteBoard(user, 1000L);
//then
verify(boardRepository, times(1)).delete(board);
}

@Test
@DisplayName("공지 삭제 실패(존재하지 않는 게시글)")
void deleteBoardFailed_1() {
//given
when(boardRepository.findById(1001L)).thenReturn(Optional.empty());
//when,then
assertThatThrownBy(() -> boardService.deleteBoard(user, 1001L))
.isInstanceOf(BoardValidationException.class)
.hasFieldOrPropertyWithValue("error", "존재하지 않는 게시글입니다");
}

@Test
@DisplayName("공지 삭제 실패(존재하지 않는 스터디 그룹)")
void deleteBoardFailed_2() {
//given
when(boardRepository.findById(1000L)).thenReturn(Optional.ofNullable(board));
when(studyGroupRepository.findById(30L)).thenReturn(Optional.empty());
//when,then
assertThatThrownBy(() -> boardService.deleteBoard(user, 1000L))
.isInstanceOf(StudyGroupValidationException.class)
.hasFieldOrPropertyWithValue("code", HttpStatus.BAD_REQUEST.value())
.hasFieldOrPropertyWithValue("error", "존재하지 않는 스터디 그룹입니다");
}

@Test
@DisplayName("공지 삭제 실패(게시글 작성자가 아님)")
void deleteBoardFailed_3() {
//given
when(boardRepository.findById(1000L)).thenReturn(Optional.ofNullable(board));
when(studyGroupRepository.findById(30L)).thenReturn(Optional.ofNullable(studyGroup));
//when, then
assertThatThrownBy(() -> boardService.deleteBoard(user4, 1000L))
.isInstanceOf(UserValidationException.class)
.hasFieldOrPropertyWithValue("errors", "공지를 삭제할 수 있는 권한이 없습니다");
}

}

0 comments on commit 506e516

Please sign in to comment.