PypiArtifactController extends BaseArtifactController { @ApiOperation(value = "This end point will be used to upload/deploy python package.") @ApiResponses(value = { @ApiResponse(code = HttpURLConnection.HTTP_OK, message = "python package was deployed successfully."), @ApiResponse(code = HttpURLConnection.HTTP_INTERNAL_ERROR, message = "An error occurred while executing request."), @ApiResponse(code = HttpURLConnection.HTTP_UNAVAILABLE, message = "Service Unavailable.") }) @PreAuthorize("hasAuthority('ARTIFACTS_DEPLOY')") @RequestMapping(path = "/{storageId}/{repositoryId}", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA) public ResponseEntity<String> uploadPackage( @RepositoryMapping Repository repository, @RequestPart(name = "comment", required = false) String comment, @RequestPart(name = "metadata_version", required = true) String metadataVersion, @RequestPart(name = "filetype", required = true) String filetype, @RequestPart(name = "protcol_version", required = false) String protcolVersion, @RequestPart(name = "author", required = false) String author, @RequestPart(name = "home_page", required = false) String homePage, @RequestPart(name = "download_url", required = false) String downloadUrl, @RequestPart(name = "platform", required = false) String platform, @RequestPart(name = "version", required = false) String version, @RequestPart(name = "description", required = false) String description, @RequestPart(name = "md5_digest", required = false) String md5Digest, @RequestPart(name = ":action", required = true) String action, @RequestPart(name = "name", required = true) String name, @RequestPart(name = "license", required = false) String license, @RequestPart(name = "pyversion", required = false) String pyversion, @RequestPart(name = "summary", required = false) String summary, @RequestPart(name = "author_email", required = false) String authorEmail, @RequestPart(name = "content", required = true) MultipartFile file, HttpServletRequest request) { logger.info("python package upload request for storageId -> [{}] , repositoryId -> [{}]", repository.getStorage().getId(), repository.getId()); try { if (!isValidAction(action)) { return ResponseEntity.status(HttpURLConnection.HTTP_BAD_REQUEST) .body("Invalid value for \":action\" parameter. Valid action values are " + VALID_ACTIONS); } PypiArtifactMetadata pypiArtifactMetadata = new PypiArtifactMetadata().withAction(action) .withAuthor(author) .withAuthorEmail(authorEmail) .withComment(comment) .withDescription(description) .withDownloadUrl(downloadUrl) .withFileType(filetype) .withHomePage(homePage) .withLicense(license) .withMd5Digest(md5Digest) .withMetdataVersion(metadataVersion) .withName(name) .withPlatform(platform) .withProtcolVersion(protcolVersion) .withPyVersion(pyversion) .withSummary(summary) .withVersion(version); return validateAndUploadPackage(pypiArtifactMetadata, file, repository.getStorage().getId(), repository.getId()); } catch (Exception e) { logger.error("Failed to process pypi upload request for storageId -> [{}] , repositoryId -> [{}]", repository.getStorage().getId(), repository.getId(), e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage()); } }  @ApiOperation(value = "This end point will be used to upload/deploy python package.") @ApiResponses(value = { @ApiResponse(code = HttpURLConnection.HTTP_OK, message = "python package was deployed successfully."), @ApiResponse(code = HttpURLConnection.HTTP_INTERNAL_ERROR, message = "An error occurred while executing request."), @ApiResponse(code = HttpURLConnection.HTTP_UNAVAILABLE, message = "Service Unavailable.") }) @PreAuthorize("hasAuthority('ARTIFACTS_DEPLOY')") @RequestMapping(path = "/{storageId}/{repositoryId}", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA) ResponseEntity<String> uploadPackage(
                                                @RepositoryMapping Repository repository,
                                                @RequestPart(name = "comment", required = false) String comment,
                                                @RequestPart(name = "metadata_version", required = true) String metadataVersion,
                                                @RequestPart(name = "filetype", required = true) String filetype,
                                                @RequestPart(name = "protcol_version", required = false) String protcolVersion,
                                                @RequestPart(name = "author", required = false) String author,
                                                @RequestPart(name = "home_page", required = false) String homePage,
                                                @RequestPart(name = "download_url", required = false) String downloadUrl,
                                                @RequestPart(name = "platform", required = false) String platform,
                                                @RequestPart(name = "version", required = false) String version,
                                                @RequestPart(name = "description", required = false) String description,
                                                @RequestPart(name = "md5_digest", required = false) String md5Digest,
                                                @RequestPart(name = ":action", required = true) String action,
                                                @RequestPart(name = "name", required = true) String name,
                                                @RequestPart(name = "license", required = false) String license,
                                                @RequestPart(name = "pyversion", required = false) String pyversion,
                                                @RequestPart(name = "summary", required = false) String summary,
                                                @RequestPart(name = "author_email", required = false) String authorEmail,
                                                @RequestPart(name = "content", required = true) MultipartFile file,
                                                HttpServletRequest request); @ApiOperation(value = "This Endpoint will be used for download/install pypi package") @ApiResponses(value = { @ApiResponse(code = HttpURLConnection.HTTP_OK, message = "Success"), @ApiResponse(code = HttpURLConnection.HTTP_SEE_OTHER, message = "See Other Location"), @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND, message = "Request Url Not Found"), @ApiResponse(code = HttpURLConnection.HTTP_INTERNAL_ERROR, message = "An error occurred while executing download request."), @ApiResponse(code = HttpURLConnection.HTTP_UNAVAILABLE, message = "Service Unavailable.") }) @PreAuthorize("hasAuthority('ARTIFACTS_RESOLVE')") @RequestMapping(path = "/{storageId}/{repositoryId}/{packageName}", method = RequestMethod.GET) ResponseEntity<String> downloadPackage(@RepositoryMapping Repository repository,
                                                  @PathVariable(name = "packageName") String packageName,
                                                  HttpServletRequest request); @ApiOperation(value = "This Endpoint will be used to retreive pypi artifact/.whl file") @ApiResponses(value = { @ApiResponse(code = HttpURLConnection.HTTP_OK, message = "Success"), @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND, message = "Request Url Not Found"), @ApiResponse(code = HttpURLConnection.HTTP_INTERNAL_ERROR, message = "An error occurred while executing download request."), @ApiResponse(code = HttpURLConnection.HTTP_UNAVAILABLE, message = "Service Unavailable.") }) @PreAuthorize("hasAuthority('ARTIFACTS_RESOLVE')") @RequestMapping(path = "/{storageId}/{repositoryId}/packages/{artifactName}", method = RequestMethod.GET) void downloadPackage(@RepositoryMapping Repository repository,
                                @PathVariable(name = "artifactName") String artifactName,
                                HttpServletRequest request,
                                HttpServletResponse response,
                                @RequestHeader HttpHeaders headers); @ApiOperation(value = "This Endpoint will be used to retreive all the versions of packages present in artifactory.") @ApiResponses(value = { @ApiResponse(code = HttpURLConnection.HTTP_OK, message = "Success"), @ApiResponse(code = HttpURLConnection.HTTP_NOT_FOUND, message = "Request Url Not Found"), @ApiResponse(code = HttpURLConnection.HTTP_INTERNAL_ERROR, message = "An error occurred while executing download request."), @ApiResponse(code = HttpURLConnection.HTTP_UNAVAILABLE, message = "Service Unavailable.") }) @PreAuthorize("hasAuthority('ARTIFACTS_RESOLVE')") @RequestMapping(path = "/{storageId}/{repositoryId}/simple/{packageName}", method = RequestMethod.GET, produces = MediaType.TEXT_HTML) ResponseEntity<String> browsePackage(@RepositoryMapping Repository repository,
                                                @PathVariable(name = "packageName") String packageName,
                                                HttpServletRequest request,
                                                HttpServletResponse response,
                                                @RequestHeader HttpHeaders headers);  }
@Test @ExtendWith({ RepositoryManagementTestExecutionListener.class, ArtifactManagementTestExecutionListener.class }) public void testUploadPackage(@PypiTestRepository(repositoryId = REPOSITORY_RELEASES, storageId = REPOSITORY_STORAGE) Repository repository, @PypiTestArtifact(id = "hello_world_pypi", versions = "1.3") Path packagePath) { final String storageId = repository.getStorage().getId(); final String repositoryId = repository.getId(); String url = getContextBaseUrl() + "/storages/{storageId}/{repositoryId}"; PypiArtifactCoordinates coordinates = new PypiArtifactCoordinates("hello_world_pypi", "1.3", null, "py3", "none", "any", "whl"); RepositoryPath repositoryPath = repositoryPathResolver.resolve(repository, coordinates); assertThat(Files.exists(repositoryPath)).isFalse(); mockMvc.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) .multiPart("filetype", "sdist") .multiPart(":action", "File_Upload") .multiPart("name", "hello-world-pipy") .multiPart("metadata_version", "1.0") .multiPart("content", packagePath.toFile()) .when() .post(url, storageId, repositoryId) .then() .log() .all() .statusCode(HttpStatus.BAD_REQUEST.value()) .contentType(ContentType.TEXT); mockMvc.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) .multiPart("filetype", "wheel") .multiPart(":action", "file_upload") .multiPart("name", "hello-world-pipy") .multiPart("metadata_version", "1.0") .multiPart("content", packagePath.toFile()) .when() .post(url, storageId, repositoryId) .then() .log() .all() .statusCode(HttpStatus.BAD_REQUEST.value()) .contentType(ContentType.TEXT); mockMvc.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) .multiPart("filetype", "sdist") .multiPart(":action", "file_upload") .multiPart("name", "hello-world-pipy") .multiPart("metadata_version", "1.0") .multiPart("content", packagePath.toFile()) .when() .post(url, storageId, repositoryId) .then() .log() .all() .statusCode(HttpStatus.OK.value()) .contentType(ContentType.TEXT) .body(Matchers.containsString("The artifact was deployed successfully.")); repositoryPath = repositoryPathResolver.resolve(repository, coordinates); assertThat(Files.exists(repositoryPath)).isTrue(); }