diff --git a/src/main/java/edu/cmipt/gcs/constant/ApiPathConstant.java b/src/main/java/edu/cmipt/gcs/constant/ApiPathConstant.java index 9c15c64..26bc661 100644 --- a/src/main/java/edu/cmipt/gcs/constant/ApiPathConstant.java +++ b/src/main/java/edu/cmipt/gcs/constant/ApiPathConstant.java @@ -25,6 +25,8 @@ public class ApiPathConstant { public static final String USER_CHECK_EMAIL_VALIDITY_API_PATH = USER_API_PREFIX + "/email"; public static final String USER_CHECK_USERNAME_VALIDITY_API_PATH = USER_API_PREFIX + "/username"; + public static final String USER_CHECK_USER_PASSWORD_VALIDITY_API_PATH = + USER_API_PREFIX + "/user-password"; public static final String USER_DELETE_USER_API_PATH = USER_API_PREFIX + "/delete"; public static final String USER_PAGE_USER_REPOSITORY_API_PATH = USER_API_PREFIX + "/page/repository"; @@ -36,6 +38,8 @@ public class ApiPathConstant { REPOSITORY_API_PREFIX + "/delete"; public static final String REPOSITORY_UPDATE_REPOSITORY_API_PATH = REPOSITORY_API_PREFIX + "/update"; + public static final String REPOSITORY_CHECK_REPOSITORY_NAME_VALIDITY_API_PATH = + REPOSITORY_API_PREFIX + "/repository-name"; public static final String SSH_KEY_API_PREFIX = ALL_API_PREFIX + "/ssh"; public static final String SSH_KEY_UPLOAD_SSH_KEY_API_PATH = SSH_KEY_API_PREFIX + "/upload"; diff --git a/src/main/java/edu/cmipt/gcs/controller/RepositoryController.java b/src/main/java/edu/cmipt/gcs/controller/RepositoryController.java index 7e61004..fd2a8f7 100644 --- a/src/main/java/edu/cmipt/gcs/controller/RepositoryController.java +++ b/src/main/java/edu/cmipt/gcs/controller/RepositoryController.java @@ -4,6 +4,7 @@ import edu.cmipt.gcs.constant.ApiPathConstant; import edu.cmipt.gcs.constant.HeaderParameter; +import edu.cmipt.gcs.constant.ValidationConstant; import edu.cmipt.gcs.enumeration.ErrorCodeEnum; import edu.cmipt.gcs.exception.GenericException; import edu.cmipt.gcs.pojo.repository.RepositoryDTO; @@ -22,6 +23,9 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,12 +33,14 @@ import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +@Validated @RestController @Tag(name = "Repository", description = "Repository Related APIs") public class RepositoryController { @@ -169,4 +175,43 @@ public ResponseEntity updateRepository( } return ResponseEntity.ok().body(new RepositoryVO(repositoryService.getById(id))); } + + @GetMapping(ApiPathConstant.REPOSITORY_CHECK_REPOSITORY_NAME_VALIDITY_API_PATH) + @Operation( + summary = "Check repository name validity", + description = "Check if the repository name is valid", + tags = {"Repository", "Get Method"}) + @Parameters({ + @Parameter( + name = "userId", + description = "User id", + required = true, + in = ParameterIn.QUERY, + schema = @Schema(implementation = Long.class) + ), + @Parameter( + name = "repositoryName", + description = "Repository name", + required = true, + in = ParameterIn.QUERY, + schema = @Schema(implementation = String.class)) + }) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "Repository name is valid"), + @ApiResponse(responseCode = "400", description = "Repository name is invalid") + }) + public void checkRepositoryNameValidity( + @RequestParam("repositoryName") + @Size(min = ValidationConstant.MIN_REPOSITORY_NAME_LENGTH, max = ValidationConstant.MAX_REPOSITORY_NAME_LENGTH, message ="REPOSITORYDTO_REPOSITORYNAME_SIZE {RepositoryDTO.repositoryName.Size}") + @NotBlank(message = "REPOSITORYDTO_REPOSITORYNAME_NOTBLANK {RepositoryDTO.repositoryName.NotBlank}") + @Pattern(regexp = ValidationConstant.REPOSITORY_NAME_PATTERN, message = "REPOSITORYNAME_PATTERN_MISMATCH {REPOSITORYNAME_PATTERN_MISMATCH}") + String repositoryName, + @RequestParam("userId") Long userId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("user_id", userId); + queryWrapper.eq("repository_name", repositoryName); + if (repositoryService.exists(queryWrapper)) { + throw new GenericException(ErrorCodeEnum.REPOSITORY_ALREADY_EXISTS, repositoryName); + } + } } diff --git a/src/main/java/edu/cmipt/gcs/controller/UserController.java b/src/main/java/edu/cmipt/gcs/controller/UserController.java index 657be29..ad07ef4 100644 --- a/src/main/java/edu/cmipt/gcs/controller/UserController.java +++ b/src/main/java/edu/cmipt/gcs/controller/UserController.java @@ -308,4 +308,36 @@ public void checkUsernameValidity( throw new GenericException(ErrorCodeEnum.USERNAME_ALREADY_EXISTS, username); } } + + @GetMapping(ApiPathConstant.USER_CHECK_USER_PASSWORD_VALIDITY_API_PATH) + @Operation( + summary = "Check password validity", + description = "Check if the password is valid", + tags = {"User", "Get Method"}) + @Parameter( + name = "userPassword", + description = "User's Password", + example = "123456", + required = true, + in = ParameterIn.QUERY, + schema = @Schema(implementation = String.class)) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "Password validity checked successfully"), + @ApiResponse( + responseCode = "400", + description = "Password is not valid", + content = @Content(schema = @Schema(implementation = ErrorVO.class))) + }) + public void checkPasswordValidity( + @RequestParam("userPassword") + @Size( + min = ValidationConstant.MIN_PASSWORD_LENGTH, + max = ValidationConstant.MAX_PASSWORD_LENGTH, + message = "USERDTO_PASSWORD_SIZE {UserDTO.password.Size}") + @NotBlank(message = "USERDTO_PASSWORD_NOTBLANK {UserDTO.password.NotBlank}") + @Pattern( + regexp = ValidationConstant.PASSWORD_PATTERN, + message = "PASSWORD_PATTERN_MISMATCH {PASSWORD_PATTERN_MISMATCH}") + String password) { + } } diff --git a/src/main/java/edu/cmipt/gcs/filter/JwtFilter.java b/src/main/java/edu/cmipt/gcs/filter/JwtFilter.java index e520966..80d6007 100644 --- a/src/main/java/edu/cmipt/gcs/filter/JwtFilter.java +++ b/src/main/java/edu/cmipt/gcs/filter/JwtFilter.java @@ -111,7 +111,9 @@ public BufferedReader getReader() { ApiPathConstant.DEVELOPMENT_GET_API_MAP_API_PATH, ApiPathConstant.DEVELOPMENT_GET_ERROR_MESSAGE_API_PATH, ApiPathConstant.USER_CHECK_EMAIL_VALIDITY_API_PATH, - ApiPathConstant.USER_CHECK_USERNAME_VALIDITY_API_PATH); + ApiPathConstant.USER_CHECK_USERNAME_VALIDITY_API_PATH, + ApiPathConstant.USER_CHECK_USER_PASSWORD_VALIDITY_API_PATH, + ApiPathConstant.REPOSITORY_CHECK_REPOSITORY_NAME_VALIDITY_API_PATH); @Override protected void doFilterInternal( diff --git a/src/main/java/edu/cmipt/gcs/pojo/repository/RepositoryDTO.java b/src/main/java/edu/cmipt/gcs/pojo/repository/RepositoryDTO.java index 17bbbfb..0f1d6bf 100644 --- a/src/main/java/edu/cmipt/gcs/pojo/repository/RepositoryDTO.java +++ b/src/main/java/edu/cmipt/gcs/pojo/repository/RepositoryDTO.java @@ -6,7 +6,6 @@ import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Null; @@ -54,31 +53,4 @@ public record RepositoryDTO( "REPOSITORYDTO_REPOSITORYDESCRIPTION_SIZE" + " {RepositoryDTO.repositoryDescription.Size}") String repositoryDescription, - @Schema(description = "Whether or Not Private Repo", example = "false") Boolean isPrivate, - @Schema(description = "Star Count") - @Null( - groups = CreateGroup.class, - message = "REPOSITORYDTO_STAR_NULL {RepositoryDTO.star.Null}") - @Min( - groups = UpdateGroup.class, - value = 0, - message = "REPOSITORYDTO_STAR_MIN {RepositoryDTO.star.Min}") - Integer star, - @Schema(description = "Fork Count") - @Null( - groups = CreateGroup.class, - message = "REPOSITORYDTO_FORK_NULL {RepositoryDTO.fork.Null}") - @Min( - groups = UpdateGroup.class, - value = 0, - message = "REPOSITORYDTO_FORK_MIN {RepositoryDTO.fork.Min}") - Integer fork, - @Schema(description = "Watcher Count") - @Null( - groups = CreateGroup.class, - message = "REPOSITORYDTO_WATCHER_NULL {RepositoryDTO.watcher.Null}") - @Min( - groups = UpdateGroup.class, - value = 0, - message = "REPOSITORYDTO_WATCHER_MIN {RepositoryDTO.watcher.Min}") - Integer watcher) {} + @Schema(description = "Whether or Not Private Repo", example = "false") Boolean isPrivate) {} diff --git a/src/main/java/edu/cmipt/gcs/pojo/repository/RepositoryPO.java b/src/main/java/edu/cmipt/gcs/pojo/repository/RepositoryPO.java index d9ed0b4..ee00c6e 100644 --- a/src/main/java/edu/cmipt/gcs/pojo/repository/RepositoryPO.java +++ b/src/main/java/edu/cmipt/gcs/pojo/repository/RepositoryPO.java @@ -49,9 +49,6 @@ public RepositoryPO(RepositoryDTO repositoryDTO, String userId, boolean generate } catch (NumberFormatException e) { this.userId = null; } - this.star = repositoryDTO.star(); - this.fork = repositoryDTO.fork(); - this.watcher = repositoryDTO.watcher(); if (generateUrl) { // TODO: https is not supported now this.httpsUrl = ""; diff --git a/src/main/resources/message/message.properties b/src/main/resources/message/message.properties index 8d99034..c81685f 100644 --- a/src/main/resources/message/message.properties +++ b/src/main/resources/message/message.properties @@ -36,12 +36,6 @@ RepositoryDTO.id.NotNull=Repository id cannot be null RepositoryDTO.name.Size=Repository name must be between {min} and {max} characters RepositoryDTO.name.NotBlank=Repository name cannot be blank RepositoryDTO.description.Size=Repository description must be between {min} and {max} characters -RepositoryDTO.star.Null=Start must be null when creating a new repository -RepositoryDTO.star.Min=Star must be greater than or equal to {value} -RepositoryDTO.fork.Null=Fork must be null when creating a new repository -RepositoryDTO.fork.Min=Fork must be greater than or equal to {value} -RepositoryDTO.watcher.Null=Watcher must be null when creating a new repository -RepositoryDTO.watcher.Min=Watcher must be greater than or equal to {value} REPOSITORYNAME_PATTERN_MISMATCH=Repository name can only be alphanumeric, hyphen or underline REPOSITORY_NOT_FOUND=Repository not found: {} diff --git a/src/test/java/edu/cmipt/gcs/controller/RepositoryControllerTest.java b/src/test/java/edu/cmipt/gcs/controller/RepositoryControllerTest.java index 4c8c651..4ac8076 100644 --- a/src/test/java/edu/cmipt/gcs/controller/RepositoryControllerTest.java +++ b/src/test/java/edu/cmipt/gcs/controller/RepositoryControllerTest.java @@ -49,10 +49,11 @@ public void testCreateRepositoryValid() throws Exception { .content( """ { - "repositoryName": "%s" + "repositoryName": "%s", + "isPrivate": %s } """ - .formatted(repositoryName))) + .formatted(repositoryName, i % 2 == 0 ? "false" : "true"))) .andExpect(status().isOk()); } var content = @@ -103,7 +104,6 @@ public void testUpdateRepositoryValid() throws Exception { jsonPath("$.id").value(TestConstant.REPOSITORY_ID), jsonPath("$.repositoryName").value(TestConstant.REPOSITORY_NAME), jsonPath("$.repositoryDescription").value(newDescription), - jsonPath("$.isPrivate").value(false), jsonPath("$.userId").value(TestConstant.ID), jsonPath("$.star").value(0), jsonPath("$.fork").value(0), diff --git a/src/test/java/edu/cmipt/gcs/controller/UserControllerTest.java b/src/test/java/edu/cmipt/gcs/controller/UserControllerTest.java index 1d821cb..f8ae5d5 100644 --- a/src/test/java/edu/cmipt/gcs/controller/UserControllerTest.java +++ b/src/test/java/edu/cmipt/gcs/controller/UserControllerTest.java @@ -282,6 +282,6 @@ public void testPageOtherUserRepositoryValid() throws Exception { .andExpectAll( status().isOk(), jsonPath("$").isArray(), - jsonPath("$.length()").value(TestConstant.REPOSITORY_SIZE)); + jsonPath("$.length()").value(TestConstant.REPOSITORY_SIZE / 2)); } }