From e89d80e66da2309b7bc88e8ae9033715101e8288 Mon Sep 17 00:00:00 2001 From: gs97ahn Date: Tue, 13 Feb 2024 23:42:19 +0900 Subject: [PATCH] [FEAT] add team leader position in updateTeam API request --- .../api/controller/team/TeamController.java | 24 +-- .../dto/team/request/TeamCreateRequest.java | 6 +- .../dto/team/request/TeamUpdateRequest.java | 22 ++- .../api/service/team/TeamService.java | 3 +- .../gabojaitspring/common/code/ErrorCode.java | 3 + .../domain/team/TeamMember.java | 8 + .../controller/team/TeamControllerTest.java | 172 ++++++++++++------ .../api/service/team/TeamServiceTest.java | 5 + .../domain/team/TeamMemberTest.java | 65 ++++++- 9 files changed, 227 insertions(+), 81 deletions(-) diff --git a/src/main/java/com/gabojait/gabojaitspring/api/controller/team/TeamController.java b/src/main/java/com/gabojait/gabojaitspring/api/controller/team/TeamController.java index be2ac048..a4318fb9 100644 --- a/src/main/java/com/gabojait/gabojaitspring/api/controller/team/TeamController.java +++ b/src/main/java/com/gabojait/gabojaitspring/api/controller/team/TeamController.java @@ -47,12 +47,13 @@ public class TeamController { @ApiOperation(value = "팀 생성", notes = "<응답 코드>\n" + "- 201 = TEAM_CREATED\n" + - "- 400 = DESIGNER_MAX_CNT_FIELD_REQUIRED || BACKEND_MAX_CNT_FIELD_REQUIRED || " + - "FRONTEND_MAX_CNT_FIELD_REQUIRED || MANAGER_MAX_CNT_FIELD_REQUIRED || " + - "PROJECT_NAME_LENGTH_INVALID || PROJECT_DESCRIPTION_LENGTH_INVALID || " + + "- 400 = PROJECT_NAME_LENGTH_INVALID || PROJECT_DESCRIPTION_LENGTH_INVALID || " + "EXPECTATION_LENGTH_INVALID || OPEN_CHAT_URL_LENGTH_INVALID || OPEN_CHAT_URL_FORMAT_INVALID || " + - "DESIGNER_MAX_CNT_POSITIVE_OR_ZERO_ONLY || BACKEND_MAX_CNT_POSITIVE_OR_ZERO_ONLY || " + - "FRONTEND_MAX_CNT_POSITIVE_OR_ZERO_ONLY || MANAGER_MAX_CNT_POSITIVE_OR_ZERO_ONLY\n" + + "LEADER_POSITION_FIELD_REQUIRED || LEADER_POSITION_TYPE_INVALID || " + + "DESIGNER_MAX_CNT_FIELD_REQUIRED || DESIGNER_MAX_CNT_POSITIVE_OR_ZERO_ONLY || " + + "BACKEND_MAX_CNT_FIELD_REQUIRED || BACKEND_MAX_CNT_POSITIVE_OR_ZERO_ONLY || " + + "FRONTEND_MAX_CNT_FIELD_REQUIRED || FRONTEND_MAX_CNT_POSITIVE_OR_ZERO_ONLY || " + + "MANAGER_MAX_CNT_FIELD_REQUIRED || MANAGER_MAX_CNT_POSITIVE_OR_ZERO_ONLY\n" + "- 401 = TOKEN_UNAUTHENTICATED\n" + "- 403 = TOKEN_UNAUTHORIZED\n" + "- 404 = USER_NOT_FOUND\n" + @@ -91,17 +92,18 @@ public ResponseEntity> createTeam( @ApiOperation(value = "팀 수정", notes = "<응답 코드>\n" + "- 200 = TEAM_UPDATED\n" + - "- 400 = DESIGNER_MAX_CNT_FIELD_REQUIRED || BACKEND_MAX_CNT_FIELD_REQUIRED || " + - "FRONTEND_MAX_CNT_FIELD_REQUIRED || MANAGER_MAX_CNT_FIELD_REQUIRED || " + - "PROJECT_NAME_LENGTH_INVALID || PROJECT_DESCRIPTION_LENGTH_INVALID || " + + "- 400 = PROJECT_NAME_LENGTH_INVALID || PROJECT_DESCRIPTION_LENGTH_INVALID || " + "EXPECTATION_LENGTH_INVALID || OPEN_CHAT_URL_LENGTH_INVALID || OPEN_CHAT_URL_FORMAT_INVALID || " + - "DESIGNER_MAX_CNT_POSITIVE_OR_ZERO_ONLY || BACKEND_MAX_CNT_POSITIVE_OR_ZERO_ONLY || " + - "FRONTEND_MAX_CNT_POSITIVE_OR_ZERO_ONLY || MANAGER_MAX_CNT_POSITIVE_OR_ZERO_ONLY\n" + + "LEADER_POSITION_FIELD_REQUIRED || LEADER_POSITION_TYPE_INVALID || " + + "DESIGNER_MAX_CNT_FIELD_REQUIRED || DESIGNER_MAX_CNT_POSITIVE_OR_ZERO_ONLY || " + + "BACKEND_MAX_CNT_FIELD_REQUIRED || BACKEND_MAX_CNT_POSITIVE_OR_ZERO_ONLY || " + + "FRONTEND_MAX_CNT_FIELD_REQUIRED || FRONTEND_MAX_CNT_POSITIVE_OR_ZERO_ONLY || " + + "MANAGER_MAX_CNT_FIELD_REQUIRED || MANAGER_MAX_CNT_POSITIVE_OR_ZERO_ONLY\n" + "- 401 = TOKEN_UNAUTHENTICATED\n" + "- 403 = TOKEN_UNAUTHORIZED || REQUEST_FORBIDDEN\n" + "- 404 = USER_NOT_FOUND || CURRENT_TEAM_NOT_FOUND\n" + "- 409 = DESIGNER_CNT_UPDATE_UNAVAILABLE || BACKEND_CNT_UPDATE_UNAVAILABLE || " + - "FRONTEND_CNT_UPDATE_UNAVAILABLE || MANAGER_CNT_UPDATE_AVAILABLE\n" + + "FRONTEND_CNT_UPDATE_UNAVAILABLE || MANAGER_CNT_UPDATE_AVAILABLE || TEAM_POSITION_UNAVAILABLE\n" + "- 500 = SERVER_ERROR\n" + "- 503 = ONGOING_INSPECTION") @ApiResponses(value = { diff --git a/src/main/java/com/gabojait/gabojaitspring/api/dto/team/request/TeamCreateRequest.java b/src/main/java/com/gabojait/gabojaitspring/api/dto/team/request/TeamCreateRequest.java index 9f3473c5..83d8eccf 100644 --- a/src/main/java/com/gabojait/gabojaitspring/api/dto/team/request/TeamCreateRequest.java +++ b/src/main/java/com/gabojait/gabojaitspring/api/dto/team/request/TeamCreateRequest.java @@ -8,10 +8,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.*; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.PositiveOrZero; -import javax.validation.constraints.Size; +import javax.validation.constraints.*; @Getter @Setter @@ -39,6 +36,7 @@ public class TeamCreateRequest { @ApiModelProperty(position = 5, required = true, value = "팀장 포지션", example = "MANAGER", allowableValues = "DESIGNER, BACKEND, FRONTEND, MANAGER") + @NotBlank(message = "팀장 포지션은 필수 입력입니다.") @Pattern(regexp = "^(DESIGNER|BACKEND|FRONTEND|MANAGER)", message = "팀장 포지션은 'DESIGNER', 'BACKEND', 'FRONTEND', 또는 'MANAGER' 중 하나여야 됩니다.") private String leaderPosition; diff --git a/src/main/java/com/gabojait/gabojaitspring/api/dto/team/request/TeamUpdateRequest.java b/src/main/java/com/gabojait/gabojaitspring/api/dto/team/request/TeamUpdateRequest.java index 3d8ed932..63199233 100644 --- a/src/main/java/com/gabojait/gabojaitspring/api/dto/team/request/TeamUpdateRequest.java +++ b/src/main/java/com/gabojait/gabojaitspring/api/dto/team/request/TeamUpdateRequest.java @@ -4,10 +4,7 @@ import io.swagger.annotations.ApiModelProperty; import lombok.*; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.PositiveOrZero; -import javax.validation.constraints.Size; +import javax.validation.constraints.*; @Getter @Setter @@ -33,22 +30,29 @@ public class TeamUpdateRequest { @Pattern(regexp = "^https\\:\\/\\/open\\.kakao\\.com\\/.+$", message = "오픈 채팅 URL은 카카오 오픈 채팅 형식만 가능합니다.") private String openChatUrl; - @ApiModelProperty(position = 5, required = true, value = "디자이너 최대 수") + @ApiModelProperty(position = 5, required = true, value = "팀장 포지션", example = "MANAGER", + allowableValues = "DESIGNER, BACKEND, FRONTEND, MANAGER") + @NotBlank(message = "팀장 포지션은 필수 입력입니다.") + @Pattern(regexp = "^(DESIGNER|BACKEND|FRONTEND|MANAGER)", + message = "팀장 포지션은 'DESIGNER', 'BACKEND', 'FRONTEND', 또는 'MANAGER' 중 하나여야 됩니다.") + private String leaderPosition; + + @ApiModelProperty(position = 6, required = true, value = "디자이너 최대 수") @NotNull(message = "디자이너 최대 수는 필수 입력입니다.") @PositiveOrZero(message = "디자이너 최대 수는 0 또는 양수만 가능합니다.") private Byte designerMaxCnt; - @ApiModelProperty(position = 6, required = true, value = "백엔드 최대 수") + @ApiModelProperty(position = 7, required = true, value = "백엔드 최대 수") @NotNull(message = "백엔드 최대 수는 필수 입력입니다.") @PositiveOrZero(message = "백엔드 최대 수는 0 또는 양수만 가능합니다.") private Byte backendMaxCnt; - @ApiModelProperty(position = 7, required = true, value = "프런트 최대 수") + @ApiModelProperty(position = 8, required = true, value = "프런트 최대 수") @NotNull(message = "프런트 최대 수는 필수 입력입니다.") @PositiveOrZero(message = "프런트 최대 수는 0 또는 양수만 가능합니다.") private Byte frontendMaxCnt; - @ApiModelProperty(position = 8, required = true, value = "매니저 최대 수") + @ApiModelProperty(position = 9, required = true, value = "매니저 최대 수") @NotNull(message = "매니저 최대 수는 필수 입력입니다.") @PositiveOrZero(message = "매니저 최대 수는 0 또는 양수만 가능합니다.") private Byte managerMaxCnt; @@ -58,6 +62,7 @@ private TeamUpdateRequest(String projectName, String projectDescription, String expectation, String openChatUrl, + String leaderPosition, byte designerMaxCnt, byte backendMaxCnt, byte frontendMaxCnt, @@ -66,6 +71,7 @@ private TeamUpdateRequest(String projectName, this.projectDescription = projectDescription; this.expectation = expectation; this.openChatUrl = openChatUrl; + this.leaderPosition = leaderPosition; this.designerMaxCnt = designerMaxCnt; this.backendMaxCnt = backendMaxCnt; this.frontendMaxCnt = frontendMaxCnt; diff --git a/src/main/java/com/gabojait/gabojaitspring/api/service/team/TeamService.java b/src/main/java/com/gabojait/gabojaitspring/api/service/team/TeamService.java index 483e35e6..0c9fc871 100644 --- a/src/main/java/com/gabojait/gabojaitspring/api/service/team/TeamService.java +++ b/src/main/java/com/gabojait/gabojaitspring/api/service/team/TeamService.java @@ -78,8 +78,9 @@ public TeamCreateResponse createTeam(long userId, TeamCreateRequest request) { public TeamUpdateResponse updateTeam(long userId, TeamUpdateRequest request) { TeamMember teamMember = findCurrentTeamMemberFetchTeam(userId); validateLeader(teamMember); - Team team = teamMember.getTeam(); + teamMember.updatePosition(Position.valueOf(request.getLeaderPosition())); + Team team = teamMember.getTeam(); team.update(request.getProjectName(), request.getProjectDescription(), request.getExpectation(), request.getDesignerMaxCnt(), request.getBackendMaxCnt(), request.getFrontendMaxCnt(), request.getManagerMaxCnt()); diff --git a/src/main/java/com/gabojait/gabojaitspring/common/code/ErrorCode.java b/src/main/java/com/gabojait/gabojaitspring/common/code/ErrorCode.java index 01e210fb..3f18e411 100644 --- a/src/main/java/com/gabojait/gabojaitspring/common/code/ErrorCode.java +++ b/src/main/java/com/gabojait/gabojaitspring/common/code/ErrorCode.java @@ -4,6 +4,8 @@ import lombok.Getter; import org.springframework.http.HttpStatus; +import javax.validation.constraints.NotBlank; + import static org.springframework.http.HttpStatus.*; @Getter @@ -24,6 +26,7 @@ public enum ErrorCode { IS_EXPERIENCED_FIELD_REQUIRED(BAD_REQUEST, "경험 여부는 필수 입력입니다."), STARTED_AT_FIELD_REQUIRED(BAD_REQUEST, "시작일은 필수 입력입니다."), IS_CURRENT_FIELD_REQUIRED(BAD_REQUEST, "현재 여부는 필수 입력입니다."), + LEADER_POSITION_FIELD_REQUIRED(BAD_REQUEST, "팀장 포지션은 필수 입력입니다."), DESIGNER_MAX_CNT_FIELD_REQUIRED(BAD_REQUEST, "디자이너 최대 수는 필수 입력입니다."), BACKEND_MAX_CNT_FIELD_REQUIRED(BAD_REQUEST, "백엔드 최대 수는 필수 입력입니다."), FRONTEND_MAX_CNT_FIELD_REQUIRED(BAD_REQUEST, "프런트 최대 수는 필수 입력입니다."), diff --git a/src/main/java/com/gabojait/gabojaitspring/domain/team/TeamMember.java b/src/main/java/com/gabojait/gabojaitspring/domain/team/TeamMember.java index 4bb4cd74..d316db81 100644 --- a/src/main/java/com/gabojait/gabojaitspring/domain/team/TeamMember.java +++ b/src/main/java/com/gabojait/gabojaitspring/domain/team/TeamMember.java @@ -52,6 +52,14 @@ private TeamMember(Position position, boolean isLeader, User user, Team team) { user.updateIsSeekingTeam(false); } + public void updatePosition(Position position) { + team.leave(this.position); + + this.position = position; + + team.join(position); + } + public void complete(String projectUrl, LocalDateTime completedAt) { this.teamMemberStatus = TeamMemberStatus.COMPLETE; diff --git a/src/test/java/com/gabojait/gabojaitspring/api/controller/team/TeamControllerTest.java b/src/test/java/com/gabojait/gabojaitspring/api/controller/team/TeamControllerTest.java index 22ebf3a0..629511e3 100644 --- a/src/test/java/com/gabojait/gabojaitspring/api/controller/team/TeamControllerTest.java +++ b/src/test/java/com/gabojait/gabojaitspring/api/controller/team/TeamControllerTest.java @@ -180,7 +180,30 @@ void givenGreaterThan100SizeOpenChatUrl_whenCreateTeam_thenReturn400() throws Ex void givenBlankLeaderPosition_whenCreateTeam_thenReturn400() throws Exception { // given TeamCreateRequest request = createValidTeamCreateRequest(); - request.setLeaderPosition(""); + request.setLeaderPosition(null); + + // when + ResultActions actions = mockMvc.perform( + post("/api/v1/team") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ); + + // then + actions.andDo(print()) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.responseCode") + .value(LEADER_POSITION_FIELD_REQUIRED.name())) + .andExpect(jsonPath("$.responseMessage") + .value(LEADER_POSITION_FIELD_REQUIRED.getMessage())); + } + + @Test + @DisplayName("잘못된 팀장 포지션 타입으로 팀 생성을 하면 400을 반환한다") + void givenTypeLeaderPosition_whenCreateTeam_thenReturn400() throws Exception { + // given + TeamCreateRequest request = createValidTeamCreateRequest(); + request.setLeaderPosition("ABC"); // when ResultActions actions = mockMvc.perform( @@ -404,11 +427,11 @@ void givenValid_whenUpdateTeam_thenReturn200() throws Exception { } @Test - @DisplayName("디자이너 최대 수 미입력시 팀 수정을 하면 400을 반환한다.") - void givenBlankDesignerMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { + @DisplayName("프로젝트명 20자 초과일시 팀 수정을 하면 400을 반환한다.") + void givenGreaterThan20SizeProjectName_whenUpdateTeam_thenReturn400() throws Exception { // given TeamUpdateRequest request = createValidTeamUpdateRequest(); - request.setDesignerMaxCnt(null); + request.setProjectName("가".repeat(21)); // when ResultActions actions = mockMvc.perform( @@ -421,17 +444,17 @@ void givenBlankDesignerMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { actions.andDo(print()) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.responseCode") - .value(DESIGNER_MAX_CNT_FIELD_REQUIRED.name())) + .value(PROJECT_NAME_LENGTH_INVALID.name())) .andExpect(jsonPath("$.responseMessage") - .value(DESIGNER_MAX_CNT_FIELD_REQUIRED.getMessage())); + .value(PROJECT_NAME_LENGTH_INVALID.getMessage())); } @Test - @DisplayName("백엔드 최대 수 미입력시 팀 수정을 하면 400을 반환한다.") - void givenBlankBackendMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { + @DisplayName("프로젝트 설명 500자 초과일시 팀 수정을 하면 400을 반환한다.") + void givenGreaterThan500SizeProjectDescription_whenUpdateTeam_thenReturn400() throws Exception { // given TeamUpdateRequest request = createValidTeamUpdateRequest(); - request.setBackendMaxCnt(null); + request.setProjectDescription("가".repeat(501)); // when ResultActions actions = mockMvc.perform( @@ -444,17 +467,17 @@ void givenBlankBackendMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { actions.andDo(print()) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.responseCode") - .value(BACKEND_MAX_CNT_FIELD_REQUIRED.name())) + .value(PROJECT_DESCRIPTION_LENGTH_INVALID.name())) .andExpect(jsonPath("$.responseMessage") - .value(BACKEND_MAX_CNT_FIELD_REQUIRED.getMessage())); + .value(PROJECT_DESCRIPTION_LENGTH_INVALID.getMessage())); } @Test - @DisplayName("프런트 최대 수 미입력시 팀 수정을 하면 400을 반환한다.") - void givenBlankFrontendMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { + @DisplayName("바라는 점 200자 초과일시 팀 수정을 하면 400을 반환한다.") + void givenGreaterThan200SizeExpectation_whenUpdateTeam_thenReturn400() throws Exception { // given TeamUpdateRequest request = createValidTeamUpdateRequest(); - request.setFrontendMaxCnt(null); + request.setExpectation("가".repeat(201)); // when ResultActions actions = mockMvc.perform( @@ -467,17 +490,17 @@ void givenBlankFrontendMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { actions.andDo(print()) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.responseCode") - .value(FRONTEND_MAX_CNT_FIELD_REQUIRED.name())) + .value(EXPECTATION_LENGTH_INVALID.name())) .andExpect(jsonPath("$.responseMessage") - .value(FRONTEND_MAX_CNT_FIELD_REQUIRED.getMessage())); + .value(EXPECTATION_LENGTH_INVALID.getMessage())); } @Test - @DisplayName("매니저 최대 수 미입력시 팀 수정을 하면 400을 반환한다.") - void givenBlankManagerMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { + @DisplayName("오픈 채팅 링크 26자 미만일시 팀 수정을 하면 400을 반환한다.") + void givenLessThan26SizeOpenChatUrl_whenUpdateTeam_thenReturn400() throws Exception { // given TeamUpdateRequest request = createValidTeamUpdateRequest(); - request.setManagerMaxCnt(null); + request.setOpenChatUrl("https://open.kakao.com/o/"); // when ResultActions actions = mockMvc.perform( @@ -490,17 +513,17 @@ void givenBlankManagerMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { actions.andDo(print()) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.responseCode") - .value(MANAGER_MAX_CNT_FIELD_REQUIRED.name())) + .value(OPEN_CHAT_URL_LENGTH_INVALID.name())) .andExpect(jsonPath("$.responseMessage") - .value(MANAGER_MAX_CNT_FIELD_REQUIRED.getMessage())); + .value(OPEN_CHAT_URL_LENGTH_INVALID.getMessage())); } @Test - @DisplayName("프로젝트명 20자 초과일시 팀 수정을 하면 400을 반환한다.") - void givenGreaterThan20SizeProjectName_whenUpdateTeam_thenReturn400() throws Exception { + @DisplayName("오픈 채팅 링크 100자 초과일시 팀 수정을 하면 400을 반환한다.") + void givenGreaterThan100SizeOpenChatUrl_whenUpdateTeam_thenReturn400() throws Exception { // given TeamUpdateRequest request = createValidTeamUpdateRequest(); - request.setProjectName("가".repeat(21)); + request.setOpenChatUrl("https://open.kakao.com/o/" + "a".repeat(76)); // when ResultActions actions = mockMvc.perform( @@ -513,17 +536,17 @@ void givenGreaterThan20SizeProjectName_whenUpdateTeam_thenReturn400() throws Exc actions.andDo(print()) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.responseCode") - .value(PROJECT_NAME_LENGTH_INVALID.name())) + .value(OPEN_CHAT_URL_LENGTH_INVALID.name())) .andExpect(jsonPath("$.responseMessage") - .value(PROJECT_NAME_LENGTH_INVALID.getMessage())); + .value(OPEN_CHAT_URL_LENGTH_INVALID.getMessage())); } @Test - @DisplayName("프로젝트 설명 500자 초과일시 팀 수정을 하면 400을 반환한다.") - void givenGreaterThan500SizeProjectDescription_whenUpdateTeam_thenReturn400() throws Exception { + @DisplayName("팀장 포지션 미입력시 팀 수정을 하면 400을 반환한다") + void givenBlankLeaderPosition_whenUpdateTeam_thenReturn400() throws Exception { // given TeamUpdateRequest request = createValidTeamUpdateRequest(); - request.setProjectDescription("가".repeat(501)); + request.setLeaderPosition(null); // when ResultActions actions = mockMvc.perform( @@ -536,17 +559,17 @@ void givenGreaterThan500SizeProjectDescription_whenUpdateTeam_thenReturn400() th actions.andDo(print()) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.responseCode") - .value(PROJECT_DESCRIPTION_LENGTH_INVALID.name())) + .value(LEADER_POSITION_FIELD_REQUIRED.name())) .andExpect(jsonPath("$.responseMessage") - .value(PROJECT_DESCRIPTION_LENGTH_INVALID.getMessage())); + .value(LEADER_POSITION_FIELD_REQUIRED.getMessage())); } @Test - @DisplayName("바라는 점 200자 초과일시 팀 수정을 하면 400을 반환한다.") - void givenGreaterThan200SizeExpectation_whenUpdateTeam_thenReturn400() throws Exception { + @DisplayName("잘못된 팀장 포지션 타입으로 팀 수정을 하면 400을 반환한다") + void givenTypeLeaderPosition_whenUpdateTeam_thenReturn400() throws Exception { // given TeamUpdateRequest request = createValidTeamUpdateRequest(); - request.setExpectation("가".repeat(201)); + request.setLeaderPosition("ABC"); // when ResultActions actions = mockMvc.perform( @@ -559,17 +582,17 @@ void givenGreaterThan200SizeExpectation_whenUpdateTeam_thenReturn400() throws Ex actions.andDo(print()) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.responseCode") - .value(EXPECTATION_LENGTH_INVALID.name())) + .value(LEADER_POSITION_TYPE_INVALID.name())) .andExpect(jsonPath("$.responseMessage") - .value(EXPECTATION_LENGTH_INVALID.getMessage())); + .value(LEADER_POSITION_TYPE_INVALID.getMessage())); } @Test - @DisplayName("오픈 채팅 링크 26자 미만일시 팀 수정을 하면 400을 반환한다.") - void givenLessThan26SizeOpenChatUrl_whenUpdateTeam_thenReturn400() throws Exception { + @DisplayName("디자이너 최대 수 미입력시 팀 수정을 하면 400을 반환한다.") + void givenBlankDesignerMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { // given TeamUpdateRequest request = createValidTeamUpdateRequest(); - request.setOpenChatUrl("https://open.kakao.com/o/"); + request.setDesignerMaxCnt(null); // when ResultActions actions = mockMvc.perform( @@ -582,17 +605,17 @@ void givenLessThan26SizeOpenChatUrl_whenUpdateTeam_thenReturn400() throws Except actions.andDo(print()) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.responseCode") - .value(OPEN_CHAT_URL_LENGTH_INVALID.name())) + .value(DESIGNER_MAX_CNT_FIELD_REQUIRED.name())) .andExpect(jsonPath("$.responseMessage") - .value(OPEN_CHAT_URL_LENGTH_INVALID.getMessage())); + .value(DESIGNER_MAX_CNT_FIELD_REQUIRED.getMessage())); } @Test - @DisplayName("오픈 채팅 링크 100자 초과일시 팀 수정을 하면 400을 반환한다.") - void givenGreaterThan100SizeOpenChatUrl_whenUpdateTeam_thenReturn400() throws Exception { + @DisplayName("디자이너 최대 수가 음수일시 팀 수정을 하면 400을 반환한다.") + void givenNegativeDesignerMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { // given TeamUpdateRequest request = createValidTeamUpdateRequest(); - request.setOpenChatUrl("https://open.kakao.com/o/" + "a".repeat(76)); + request.setDesignerMaxCnt((byte) -1); // when ResultActions actions = mockMvc.perform( @@ -605,17 +628,17 @@ void givenGreaterThan100SizeOpenChatUrl_whenUpdateTeam_thenReturn400() throws Ex actions.andDo(print()) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.responseCode") - .value(OPEN_CHAT_URL_LENGTH_INVALID.name())) + .value(DESIGNER_MAX_CNT_POSITIVE_OR_ZERO_ONLY.name())) .andExpect(jsonPath("$.responseMessage") - .value(OPEN_CHAT_URL_LENGTH_INVALID.getMessage())); + .value(DESIGNER_MAX_CNT_POSITIVE_OR_ZERO_ONLY.getMessage())); } @Test - @DisplayName("디자이너 최대 수가 음수일시 팀 수정을 하면 400을 반환한다.") - void givenNegativeDesignerMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { + @DisplayName("백엔드 최대 수 미입력시 팀 수정을 하면 400을 반환한다.") + void givenBlankBackendMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { // given TeamUpdateRequest request = createValidTeamUpdateRequest(); - request.setDesignerMaxCnt((byte) -1); + request.setBackendMaxCnt(null); // when ResultActions actions = mockMvc.perform( @@ -628,9 +651,9 @@ void givenNegativeDesignerMaxCnt_whenUpdateTeam_thenReturn400() throws Exception actions.andDo(print()) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.responseCode") - .value(DESIGNER_MAX_CNT_POSITIVE_OR_ZERO_ONLY.name())) + .value(BACKEND_MAX_CNT_FIELD_REQUIRED.name())) .andExpect(jsonPath("$.responseMessage") - .value(DESIGNER_MAX_CNT_POSITIVE_OR_ZERO_ONLY.getMessage())); + .value(BACKEND_MAX_CNT_FIELD_REQUIRED.getMessage())); } @Test @@ -656,6 +679,29 @@ void givenNegativeBackendMaxCnt_whenUpdateTeam_thenReturn400() throws Exception .value(BACKEND_MAX_CNT_POSITIVE_OR_ZERO_ONLY.getMessage())); } + @Test + @DisplayName("프런트 최대 수 미입력시 팀 수정을 하면 400을 반환한다.") + void givenBlankFrontendMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { + // given + TeamUpdateRequest request = createValidTeamUpdateRequest(); + request.setFrontendMaxCnt(null); + + // when + ResultActions actions = mockMvc.perform( + put("/api/v1/team") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ); + + // then + actions.andDo(print()) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.responseCode") + .value(FRONTEND_MAX_CNT_FIELD_REQUIRED.name())) + .andExpect(jsonPath("$.responseMessage") + .value(FRONTEND_MAX_CNT_FIELD_REQUIRED.getMessage())); + } + @Test @DisplayName("프런트 최대 수가 음수일시 팀 수정을 하면 400을 반환한다.") void givenNegativeFrontendMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { @@ -679,6 +725,29 @@ void givenNegativeFrontendMaxCnt_whenUpdateTeam_thenReturn400() throws Exception .value(FRONTEND_MAX_CNT_POSITIVE_OR_ZERO_ONLY.getMessage())); } + @Test + @DisplayName("매니저 최대 수 미입력시 팀 수정을 하면 400을 반환한다.") + void givenBlankManagerMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { + // given + TeamUpdateRequest request = createValidTeamUpdateRequest(); + request.setManagerMaxCnt(null); + + // when + ResultActions actions = mockMvc.perform( + put("/api/v1/team") + .content(objectMapper.writeValueAsString(request)) + .contentType(APPLICATION_JSON) + ); + + // then + actions.andDo(print()) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.responseCode") + .value(MANAGER_MAX_CNT_FIELD_REQUIRED.name())) + .andExpect(jsonPath("$.responseMessage") + .value(MANAGER_MAX_CNT_FIELD_REQUIRED.getMessage())); + } + @Test @DisplayName("매니저 최대 수가 음수일시 팀 수정을 하면 400을 반환한다.") void givenNegativeManagerMaxCnt_whenUpdateTeam_thenReturn400() throws Exception { @@ -1056,6 +1125,7 @@ private TeamUpdateRequest createValidTeamUpdateRequest() { .projectDescription("프로젝트 설명입니다.") .expectation("바라는 점입니다.") .openChatUrl("https://open.kakao.com/o/gabojait") + .leaderPosition(Position.MANAGER.name()) .designerMaxCnt((byte) 2) .backendMaxCnt((byte) 2) .frontendMaxCnt((byte) 2) diff --git a/src/test/java/com/gabojait/gabojaitspring/api/service/team/TeamServiceTest.java b/src/test/java/com/gabojait/gabojaitspring/api/service/team/TeamServiceTest.java index a32f9690..344f4a8a 100644 --- a/src/test/java/com/gabojait/gabojaitspring/api/service/team/TeamServiceTest.java +++ b/src/test/java/com/gabojait/gabojaitspring/api/service/team/TeamServiceTest.java @@ -273,6 +273,7 @@ void givenUnavailableDesignerCnt_whenUpdateTeam_thenThrow() { createdSavedTeamMember(true, user, team, Position.DESIGNER); TeamUpdateRequest request = createValidTeamUpdateRequest(); + request.setLeaderPosition(Position.DESIGNER.name()); request.setDesignerMaxCnt((byte) 0); // when & then @@ -292,6 +293,7 @@ void givenUnavailableBackendCnt_whenUpdateTeam_thenThrow() { createdSavedTeamMember(true, user, team, Position.BACKEND); TeamUpdateRequest request = createValidTeamUpdateRequest(); + request.setLeaderPosition(Position.BACKEND.name()); request.setBackendMaxCnt((byte) 0); // when & then @@ -311,6 +313,7 @@ void givenUnavailableFrontendCnt_whenUpdateTeam_thenThrow() { createdSavedTeamMember(true, user, team, Position.FRONTEND); TeamUpdateRequest request = createValidTeamUpdateRequest(); + request.setLeaderPosition(Position.FRONTEND.name()); request.setFrontendMaxCnt((byte) 0); // when & then @@ -330,6 +333,7 @@ void givenUnavailableManagerCnt_whenUpdateTeam_thenThrow() { createdSavedTeamMember(true, user, team, Position.MANAGER); TeamUpdateRequest request = createValidTeamUpdateRequest(); + request.setLeaderPosition(Position.MANAGER.name()); request.setManagerMaxCnt((byte) 0); // when & then @@ -761,6 +765,7 @@ private TeamUpdateRequest createValidTeamUpdateRequest() { .projectDescription("가볼까잇 설명입니다.") .expectation("열정적인 팀원을 구해요.") .openChatUrl("kakao.com/o/gabojait") + .leaderPosition(Position.MANAGER.name()) .designerMaxCnt((byte) 5) .backendMaxCnt((byte) 5) .frontendMaxCnt((byte) 5) diff --git a/src/test/java/com/gabojait/gabojaitspring/domain/team/TeamMemberTest.java b/src/test/java/com/gabojait/gabojaitspring/domain/team/TeamMemberTest.java index 8d34910c..6a35d677 100644 --- a/src/test/java/com/gabojait/gabojaitspring/domain/team/TeamMemberTest.java +++ b/src/test/java/com/gabojait/gabojaitspring/domain/team/TeamMemberTest.java @@ -16,8 +16,7 @@ import java.time.LocalDateTime; import java.util.stream.Stream; -import static com.gabojait.gabojaitspring.common.code.ErrorCode.TEAM_LEADER_UNAVAILABLE; -import static com.gabojait.gabojaitspring.common.code.ErrorCode.UNREGISTER_UNAVAILABLE; +import static com.gabojait.gabojaitspring.common.code.ErrorCode.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.*; @@ -49,6 +48,60 @@ void givenValid_whenBuilder_thenReturn() { ); } + @Test + @DisplayName("꽉찬 포지션으로 팀원 생성을 하면 예외가 발생한다") + void givenUnavailablePosition_whenBuilder_thenThrow() { + // given + User user = createDefaultUser("tester@gabojait.com", LocalDate.of(1997, 2, 11), LocalDateTime.now()); + Team team = createTeam("가보자잇", (byte) 0, (byte) 0, (byte) 0, (byte) 0); + + Position position = Position.BACKEND; + boolean isLeader = true; + + // when & then + assertThatThrownBy(() -> createTeamMember(position, isLeader, user, team)) + .isInstanceOf(CustomException.class) + .extracting("errorCode") + .isEqualTo(TEAM_POSITION_UNAVAILABLE); + } + + @Test + @DisplayName("팀원 포지션 업데이트가 정상 작동한다") + void givenValid_whenUpdatePosition_thenReturn() { + // given + User user = createDefaultUser("tester@gabojait.com", LocalDate.of(1997, 2, 11), LocalDateTime.now()); + Team team = createTeam("가보자잇", (byte) 2, (byte) 2, (byte) 2, (byte) 2); + boolean isLeader = true; + TeamMember teamMember = createTeamMember(Position.BACKEND, isLeader, user, team); + + Position position = Position.MANAGER; + + // when + teamMember.updatePosition(position); + + // then + assertThat(teamMember) + .extracting("position", "teamMemberStatus", "isLeader", "isDeleted", "user", "team") + .containsExactly(position, TeamMemberStatus.PROGRESS, isLeader, false, user, team); + } + + @Test + @DisplayName("꽉찬 포지션으로 팀원 포지션 업데이트를 하면 예외가 발생한다") + void givenUnavailablePosition_whenUpdatePosition_thenThrow() { + User user = createDefaultUser("tester@gabojait.com", LocalDate.of(1997, 2, 11), LocalDateTime.now()); + Team team = createTeam("가보자잇", (byte) 0, (byte) 1, (byte) 0, (byte) 0); + boolean isLeader = true; + TeamMember teamMember = createTeamMember(Position.BACKEND, isLeader, user, team); + + Position position = Position.MANAGER; + + // when & then + assertThatThrownBy(() -> teamMember.updatePosition(position)) + .isInstanceOf(CustomException.class) + .extracting("errorCode") + .isEqualTo(TEAM_POSITION_UNAVAILABLE); + } + @Test @DisplayName("팀장이 프로젝트 완료를 하면 정상 작동한다") void givenLeader_whenComplete_thenReturn() { @@ -69,8 +122,8 @@ void givenLeader_whenComplete_thenReturn() { // then assertAll( () -> assertThat(teamMember) - .extracting("position", "isLeader", "isDeleted") - .containsExactly(position, isLeader, false), + .extracting("position", "teamMemberStatus", "isLeader", "isDeleted") + .containsExactly(position, TeamMemberStatus.COMPLETE, isLeader, false), () -> assertThat(teamMember.getTeam()) .extracting("projectUrl", "completedAt", "isRecruiting") .containsExactly(projectUrl, completedAt, false), @@ -98,8 +151,8 @@ void givenMember_whenComplete_thenReturn() { // then assertAll( () -> assertThat(teamMember) - .extracting("position", "isLeader", "isDeleted") - .containsExactly(position, isLeader, false), + .extracting("position", "teamMemberStatus", "isLeader", "isDeleted") + .containsExactly(position, TeamMemberStatus.COMPLETE, isLeader, false), () -> assertThat(teamMember.getTeam()) .extracting("projectUrl", "completedAt", "isRecruiting") .containsExactly(null, null, true),