Skip to content

Commit

Permalink
Merge pull request #100 from Nexters/feature/74-delete-editor
Browse files Browse the repository at this point in the history
코스 멤버 삭제 api 추가
  • Loading branch information
haeun-i authored Feb 22, 2024
2 parents 2aab6d5 + 2b60979 commit 548a4cc
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,4 @@ include::{snippets}/course-controller-test/멤버_course_전체_조회/auto-sect

include::{snippets}/editor-controller-test/editor_저장/auto-section.adoc[]
include::{snippets}/editor-controller-test/editor_역할_수정/auto-section.adoc[]
include::{snippets}/editor-controller-test/editor_역할_삭제/auto-section.adoc[]
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
package com.pcb.audy.domain.editor.controller;

import com.pcb.audy.domain.editor.dto.request.EditorDeleteReq;
import com.pcb.audy.domain.editor.dto.request.EditorRoleUpdateReq;
import com.pcb.audy.domain.editor.dto.request.EditorSaveReq;
import com.pcb.audy.domain.editor.dto.response.EditorDeleteRes;
import com.pcb.audy.domain.editor.dto.response.EditorRoleUpdateRes;
import com.pcb.audy.domain.editor.dto.response.EditorSaveRes;
import com.pcb.audy.domain.editor.service.EditorService;
import com.pcb.audy.global.auth.PrincipalDetails;
import com.pcb.audy.global.response.BasicResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.PatchMapping;
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 org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/v1/editors")
Expand All @@ -36,4 +34,12 @@ public BasicResponse<EditorRoleUpdateRes> updateEditorRole(
editorRoleUpdateReq.setUserId(principalDetails.getUser().getUserId());
return BasicResponse.success(editorService.updateRoleEditor(editorRoleUpdateReq));
}

@DeleteMapping
public BasicResponse<EditorDeleteRes> deleteEditor(
@AuthenticationPrincipal PrincipalDetails principalDetails,
@RequestBody EditorDeleteReq editorDeleteReq) {
editorDeleteReq.setUserId(principalDetails.getUser().getUserId());
return BasicResponse.success(editorService.deleteEditor(editorDeleteReq));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.pcb.audy.domain.editor.dto.request;

import lombok.*;

@Setter
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class EditorDeleteReq {
private Long userId;
private Long courseId;
private Long selectedUserId;

@Builder
private EditorDeleteReq(Long userId, Long courseId, Long selectedUserId) {
this.userId = userId;
this.courseId = courseId;
this.selectedUserId = selectedUserId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.pcb.audy.domain.editor.dto.response;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties
public class EditorDeleteRes {}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import com.pcb.audy.domain.course.dto.request.CourseInviteRedisReq;
import com.pcb.audy.domain.course.entity.Course;
import com.pcb.audy.domain.course.repository.CourseRepository;
import com.pcb.audy.domain.editor.dto.request.EditorDeleteReq;
import com.pcb.audy.domain.editor.dto.request.EditorRoleUpdateReq;
import com.pcb.audy.domain.editor.dto.request.EditorSaveReq;
import com.pcb.audy.domain.editor.dto.response.EditorDeleteRes;
import com.pcb.audy.domain.editor.dto.response.EditorRoleUpdateRes;
import com.pcb.audy.domain.editor.dto.response.EditorSaveRes;
import com.pcb.audy.domain.editor.entity.Editor;
Expand Down Expand Up @@ -61,11 +63,6 @@ public EditorSaveRes saveEditor(EditorSaveReq editorSaveReq) {
return EditorServiceMapper.INSTANCE.toEditorSaveRes(savedEditor);
}

private void checkAlreadyExistEditor(User user, Course course) {
Editor editor = editorRepository.findByUserAndCourse(user, course);
EditorValidator.checkAlreadyExist(editor);
}

@Transactional
public EditorRoleUpdateRes updateRoleEditor(EditorRoleUpdateReq editorRoleUpdateReq) {
User user = getUserByUserId(editorRoleUpdateReq.getUserId());
Expand All @@ -83,6 +80,19 @@ public EditorRoleUpdateRes updateRoleEditor(EditorRoleUpdateReq editorRoleUpdate
return new EditorRoleUpdateRes();
}

public EditorDeleteRes deleteEditor(EditorDeleteReq editorDeleteReq) {
User source = getUserByUserId(editorDeleteReq.getUserId());
User target = getUserByUserId(editorDeleteReq.getSelectedUserId());
Course course = getCourseByCourseId(editorDeleteReq.getCourseId());

Editor sourceEditor = getEditor(source, course);
Editor targetEditor = getEditor(target, course);
EditorValidator.checkCanDelete(sourceEditor, targetEditor);

editorRepository.delete(targetEditor);
return new EditorDeleteRes();
}

private User getUserByUserId(Long userId) {
User user = userRepository.findByUserId(userId);
UserValidator.validate(user);
Expand All @@ -100,4 +110,9 @@ private Editor getEditor(User user, Course course) {
EditorValidator.validate(editor);
return editor;
}

private void checkAlreadyExistEditor(User user, Course course) {
Editor editor = editorRepository.findByUserAndCourse(user, course);
EditorValidator.checkAlreadyExist(editor);
}
}
1 change: 1 addition & 0 deletions src/main/java/com/pcb/audy/global/response/ResultCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public enum ResultCode {
NOT_FOUND_EDITOR(5000, "에디터를 찾을 수 없습니다."),
NOT_VALID_KEY(5001, "유효기간이 만료된 링크입니다."),
ALREADY_EXIST_EDITOR(5002, "이미 코스에 포함된 멤버입니다."),
FAILED_DELETE_EDITOR(5003, "해당 유저를 코스에서 내보낼 수 없습니다."),

FAILED_ENCRYPT(6000, "객체 암호화에 실패하였습니다."),
FAILED_DECRYPT(6001, "객체 복호화에 실패하였습니다.");
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/com/pcb/audy/global/validator/EditorValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ public static void checkIsAdminUser(Editor editor) {
}
}

public static void checkCanDelete(Editor source, Editor target) {
if (isAdminEditor(target) || (!isEqualUser(source, target) && !isAdminEditor(source))) {
throw new GlobalException(FAILED_DELETE_EDITOR);
}
}

public static void checkAlreadyExist(Editor editor) {
if (isExistEditor(editor)) {
throw new GlobalException(ALREADY_EXIST_EDITOR);
Expand All @@ -52,8 +58,16 @@ private static boolean isAdminEditor(Editor editor) {
return Role.OWNER.equals(editor.getRole());
}

private static boolean isMemberEditor(Editor editor) {
return Role.MEMBER.equals(editor.getRole());
}

private static boolean isEqualObject(
CourseInviteRedisReq courseInviteRedisReq, CourseInviteRedisReq findByKey) {
return courseInviteRedisReq.equals(findByKey);
}

private static boolean isEqualUser(Editor source, Editor target) {
return source.getUser().getUserId() == target.getUser().getUserId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
import static com.pcb.audy.global.meta.Role.MEMBER;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.pcb.audy.domain.BaseMvcTest;
import com.pcb.audy.domain.editor.dto.request.EditorDeleteReq;
import com.pcb.audy.domain.editor.dto.request.EditorRoleUpdateReq;
import com.pcb.audy.domain.editor.dto.request.EditorSaveReq;
import com.pcb.audy.domain.editor.dto.response.EditorDeleteRes;
import com.pcb.audy.domain.editor.dto.response.EditorRoleUpdateRes;
import com.pcb.audy.domain.editor.dto.response.EditorSaveRes;
import com.pcb.audy.domain.editor.service.EditorService;
Expand Down Expand Up @@ -61,4 +64,25 @@ class EditorControllerTest extends BaseMvcTest implements EditorTest {
.andDo(print())
.andExpect(status().isOk());
}

@Test
@DisplayName("editor 역할 삭제 테스트")
void editor_역할_삭제() throws Exception {
EditorDeleteReq editorDeleteReq =
EditorDeleteReq.builder()
.courseId(TEST_COURSE_ID)
.selectedUserId(TEST_ANOTHER_USER_ID)
.build();
EditorDeleteRes editorDeleteRes = new EditorDeleteRes();

when(editorService.deleteEditor(any())).thenReturn(editorDeleteRes);
this.mockMvc
.perform(
delete("/v1/editors")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(editorDeleteReq))
.principal(this.mockPrincipal))
.andDo(print())
.andExpect(status().isOk());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pcb.audy.domain.course.dto.request.CourseInviteRedisReq;
import com.pcb.audy.domain.course.repository.CourseRepository;
import com.pcb.audy.domain.editor.dto.request.EditorDeleteReq;
import com.pcb.audy.domain.editor.dto.request.EditorRoleUpdateReq;
import com.pcb.audy.domain.editor.dto.request.EditorSaveReq;
import com.pcb.audy.domain.editor.repository.EditorRepository;
Expand Down Expand Up @@ -178,4 +179,95 @@ class editor_역할_수정 {
assertThat(exception.getResultCode()).isEqualTo(NOT_ADMIN_COURSE);
}
}

@Nested
class editor_역할_삭제 {
@Test
@DisplayName("editor 역할 삭제 테스트")
void editor_역할_삭제() {
// given
EditorDeleteReq editorDeleteReq =
EditorDeleteReq.builder()
.userId(TEST_USER_ID)
.selectedUserId(TEST_ANOTHER_USER_ID)
.build();

when(userRepository.findByUserId(any())).thenReturn(TEST_USER).thenReturn(TEST_ANOTHER_USER);
when(courseRepository.findByCourseId(any())).thenReturn(TEST_COURSE);
when(editorRepository.findByUserAndCourse(any(), any()))
.thenReturn(TEST_EDITOR_ADMIN)
.thenReturn(TEST_EDITOR_MEMBER);

// when
editorService.deleteEditor(editorDeleteReq);

// then
verify(userRepository, times(2)).findByUserId(any());
verify(courseRepository).findByCourseId(any());
verify(editorRepository, times(2)).findByUserAndCourse(any(), any());
verify(editorRepository).delete(any());
}

@Test
@DisplayName("editor 역할 수정 실패 테스트 - 관리자가 아닌 사람이 타인을 삭제하려고 할 때")
void editor_MEMBER가_역할_수정_실패() {
// given
EditorDeleteReq editorDeleteReq =
EditorDeleteReq.builder()
.userId(TEST_USER_ID)
.selectedUserId(TEST_ANOTHER_USER_ID)
.build();

when(userRepository.findByUserId(any())).thenReturn(TEST_USER).thenReturn(TEST_ANOTHER_USER);
when(courseRepository.findByCourseId(any())).thenReturn(TEST_COURSE);
when(editorRepository.findByUserAndCourse(any(), any()))
.thenReturn(TEST_EDITOR_MEMBER)
.thenReturn(TEST_ANOTHER_EDITOR_MEMBER);

// when
GlobalException exception =
assertThrows(
GlobalException.class,
() -> {
editorService.deleteEditor(editorDeleteReq);
});

// then
verify(userRepository, times(2)).findByUserId(any());
verify(courseRepository).findByCourseId(any());
verify(editorRepository, times(2)).findByUserAndCourse(any(), any());
assertThat(exception.getResultCode()).isEqualTo(FAILED_DELETE_EDITOR);
}

@Test
@DisplayName("editor 역할 수정 실패 테스트 - 삭제 대상이 admin인 경우")
void editor_처리대상이_ADMIN_역할_수정_실패() {
// given
EditorDeleteReq editorDeleteReq =
EditorDeleteReq.builder()
.userId(TEST_USER_ID)
.selectedUserId(TEST_ANOTHER_USER_ID)
.build();

when(userRepository.findByUserId(any())).thenReturn(TEST_USER).thenReturn(TEST_ANOTHER_USER);
when(courseRepository.findByCourseId(any())).thenReturn(TEST_COURSE);
when(editorRepository.findByUserAndCourse(any(), any()))
.thenReturn(TEST_EDITOR_ADMIN)
.thenReturn(TEST_EDITOR_ADMIN);

// when
GlobalException exception =
assertThrows(
GlobalException.class,
() -> {
editorService.deleteEditor(editorDeleteReq);
});

// then
verify(userRepository, times(2)).findByUserId(any());
verify(courseRepository).findByCourseId(any());
verify(editorRepository, times(2)).findByUserAndCourse(any(), any());
assertThat(exception.getResultCode()).isEqualTo(FAILED_DELETE_EDITOR);
}
}
}
3 changes: 3 additions & 0 deletions src/test/java/com/pcb/audy/test/EditorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ public interface EditorTest extends CourseTest, UserTest {

Editor TEST_EDITOR_MEMBER =
Editor.builder().course(TEST_SECOND_COURSE).user(TEST_USER).role(Role.MEMBER).build();

Editor TEST_ANOTHER_EDITOR_MEMBER =
Editor.builder().course(TEST_SECOND_COURSE).user(TEST_ANOTHER_USER).role(Role.MEMBER).build();
}

0 comments on commit 548a4cc

Please sign in to comment.