Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] TalkRoom Comment 수정, 삭제 API 구현 #39

Merged
merged 4 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/main/java/com/jisungin/api/comment/CommentController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@

import com.jisungin.api.ApiResponse;
import com.jisungin.api.comment.request.CommentCreateRequest;
import com.jisungin.api.comment.request.CommentEditRequest;
import com.jisungin.api.oauth.Auth;
import com.jisungin.api.oauth.AuthContext;
import com.jisungin.application.comment.CommentService;
import com.jisungin.application.comment.response.CommentResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -28,4 +32,22 @@ public ApiResponse<CommentResponse> writeComment(@PathVariable Long talkRoomId,
return ApiResponse.ok(commentService.writeComment(request.toService(), talkRoomId, authContext.getUserId()));
}

@PatchMapping("/talk-rooms/comments/{commentId}")
public ApiResponse<CommentResponse> editComment(@PathVariable Long commentId,
@Valid @RequestBody CommentEditRequest request,
@Auth AuthContext authContext) {
return ApiResponse.ok(commentService.editComment(commentId, request.toService(), authContext.getUserId()));
}

@DeleteMapping("/talk-rooms/comments/{commentId}")
public ApiResponse<Void> deleteComment(@PathVariable Long commentId,
@Auth AuthContext authContext) {
commentService.deleteComment(commentId, authContext.getUserId());

return ApiResponse.<Void>builder()
.message("OK")
.status(HttpStatus.OK)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.jisungin.api.comment.request;

import com.jisungin.application.comment.request.CommentEditServiceRequest;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class CommentEditRequest {

private String content;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 필드 제약 조건이 없는 이유가 있나요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음 아직 PM님께서 제약 조건이 명확하게 정해지지 않았다고 하셔서 아직 설정을 안해놨습니다!


@Builder
private CommentEditRequest(String content) {
this.content = content;
}

public CommentEditServiceRequest toService() {
return CommentEditServiceRequest.builder()
.content(content)
.build();
}

}
34 changes: 34 additions & 0 deletions src/main/java/com/jisungin/application/comment/CommentService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.jisungin.application.comment;

import com.jisungin.application.comment.request.CommentCreateServiceRequest;
import com.jisungin.application.comment.request.CommentEditServiceRequest;
import com.jisungin.application.comment.response.CommentResponse;
import com.jisungin.domain.comment.Comment;
import com.jisungin.domain.comment.repository.CommentRepository;
Expand All @@ -12,7 +13,9 @@
import com.jisungin.exception.ErrorCode;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Transactional(readOnly = true)
@RequiredArgsConstructor
@Service
public class CommentService {
Expand All @@ -21,6 +24,7 @@ public class CommentService {
private final TalkRoomRepository talkRoomRepository;
private final UserRepository userRepository;

@Transactional
public CommentResponse writeComment(CommentCreateServiceRequest request, Long talkRoomId, Long userId) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
Expand All @@ -35,4 +39,34 @@ public CommentResponse writeComment(CommentCreateServiceRequest request, Long ta
return CommentResponse.of(comment.getContent(), user.getName());
}

@Transactional
public CommentResponse editComment(Long commentId, CommentEditServiceRequest request, Long userId) {
Comment comment = commentRepository.findById(commentId)
.orElseThrow(() -> new BusinessException(ErrorCode.COMMENT_NOT_FOUND));

User user = userRepository.findById(userId).orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));

if (!comment.isCommentOwner(user.getId())) {
throw new BusinessException(ErrorCode.UNAUTHORIZED_REQUEST);
}

comment.edit(request.getContent());

return CommentResponse.of(comment.getContent(), user.getName());
}

@Transactional
public void deleteComment(Long commentId, Long userId) {
Comment comment = commentRepository.findById(commentId)
.orElseThrow(() -> new BusinessException(ErrorCode.COMMENT_NOT_FOUND));

User user = userRepository.findById(userId).orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));

if (!comment.isCommentOwner(user.getId())) {
throw new BusinessException(ErrorCode.UNAUTHORIZED_REQUEST);
}

commentRepository.delete(comment);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.jisungin.application.comment.request;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class CommentEditServiceRequest {

private String content;

@Builder
private CommentEditServiceRequest(String content) {
this.content = content;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public TalkRoomResponse editTalkRoom(TalkRoomEditServiceRequest request, Long us
throw new BusinessException(ErrorCode.UNAUTHORIZED_REQUEST);
}

talkRoom.edit(request);
talkRoom.edit(request.getTitle(), request.getContent());

talkRoomRoleRepository.deleteAllByTalkRoom(talkRoom);

Expand Down
18 changes: 17 additions & 1 deletion src/main/java/com/jisungin/domain/comment/Comment.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@
import com.jisungin.domain.BaseEntity;
import com.jisungin.domain.talkroom.TalkRoom;
import com.jisungin.domain.user.User;
import jakarta.persistence.*;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
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 lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
Expand Down Expand Up @@ -47,4 +55,12 @@ public static Comment create(CommentCreateServiceRequest request, User user, Tal
.build();
}

public boolean isCommentOwner(Long userId) {
return user.isMe(userId);
}

public void edit(String requestContent) {
this.content = requestContent != null ? requestContent : content;
}

}
7 changes: 3 additions & 4 deletions src/main/java/com/jisungin/domain/talkroom/TalkRoom.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.jisungin.domain.talkroom;

import com.jisungin.application.talkroom.request.TalkRoomEditServiceRequest;
import com.jisungin.domain.BaseEntity;
import com.jisungin.domain.book.Book;
import com.jisungin.domain.user.User;
Expand Down Expand Up @@ -60,9 +59,9 @@ public static TalkRoom create(String title, String content, Book book, User user
.build();
}

public void edit(TalkRoomEditServiceRequest request) {
this.title = request.getTitle() != null ? request.getTitle() : title;
this.content = request.getContent() != null ? request.getContent() : content;
public void edit(String requestTitle, String requestContent) {
this.title = requestTitle != null ? requestTitle : title;
this.content = requestContent != null ? requestContent : content;
}

public boolean isTalkRoomOwner(Long userId) {
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/jisungin/exception/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public enum ErrorCode {
PARTICIPATION_CONDITION_ERROR(400, "참가 조건은 1개 이상이어야 합니다."),
OAUTH_TYPE_NOT_FOUND(404, "지원하지 않는 소셜 로그인입니다."),
TALK_ROOM_NOT_FOUND(400, "토크방을 찾을 수 없습니다."),
UNAUTHORIZED_REQUEST(400, "권한이 없는 사용자입니다.");
UNAUTHORIZED_REQUEST(400, "권한이 없는 사용자입니다."),
COMMENT_NOT_FOUND(404, "의견을 찾을 수 없습니다.");


private final int code;
Expand Down
37 changes: 37 additions & 0 deletions src/test/java/com/jisungin/api/comment/CommentControllerTest.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.jisungin.api.comment;

import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.jisungin.ControllerTestSupport;
import com.jisungin.api.comment.request.CommentCreateRequest;
import com.jisungin.api.comment.request.CommentEditRequest;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -51,4 +54,38 @@ void writeCommentWithEmptyContent() throws Exception {
.andExpect(jsonPath("$.message").value("내용은 필수 입니다."));
}

@Test
@DisplayName("의견을 작성한 유저가 자신의 의견을 수정한다.")
void editComment() throws Exception {
// given
CommentEditRequest request = CommentEditRequest.builder()
.content("의견 수정")
.build();

// when // then
mockMvc.perform(patch("/v1/talk-rooms/comments/1")
.content(objectMapper.writeValueAsString(request))
.contentType(APPLICATION_JSON)
)
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value("200"))
.andExpect(jsonPath("$.status").value("OK"))
.andExpect(jsonPath("$.message").value("OK"));
}

@Test
@DisplayName("의견을 작성한 유저가 자신의 의견을 삭제한다.")
void deleteComment() throws Exception {
// when // then
mockMvc.perform(delete("/v1/talk-rooms/comments/1")
.contentType(APPLICATION_JSON)
)
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value("200"))
.andExpect(jsonPath("$.status").value("OK"))
.andExpect(jsonPath("$.message").value("OK"));
}

}
Loading
Loading