From 445a3aa2ea3c6b36f0819563cce21bfb920151aa Mon Sep 17 00:00:00 2001 From: Khanh Nguyen <119989010+ndkhanh-axonivy@users.noreply.github.com> Date: Thu, 18 Jul 2024 17:29:50 +0700 Subject: [PATCH] Feature/MARP-357 fix sonar (#39) --- marketplace-service/README.md | 17 +- marketplace-service/pom.xml | 6 +- .../market/MarketplaceServiceApplication.java | 2 +- .../assembler/FeedbackModelAssembler.java | 6 +- .../ProductDetailModelAssembler.java | 6 +- .../ArchivedArtifactsComparator.java | 10 +- .../comparator/LatestVersionComparator.java | 46 ++--- .../config/MarketApiDocumentConfig.java | 10 +- .../axonivy/market/config/MongoConfig.java | 70 ++++---- .../com/axonivy/market/config/WebConfig.java | 9 +- .../market/constants/EntityConstants.java | 10 +- .../market/constants/MavenConstants.java | 3 +- .../NonStandardProductPackageConstants.java | 3 +- .../constants/ProductJsonConstants.java | 3 +- .../market/controller/AppController.java | 3 +- .../market/controller/FeedbackController.java | 29 ++-- .../market/controller/OAuth2Controller.java | 9 +- .../market/controller/ProductController.java | 15 +- .../controller/ProductDetailsController.java | 18 +- .../com/axonivy/market/entity/Feedback.java | 13 -- .../market/entity/MavenArtifactModel.java | 38 ++--- .../market/entity/MavenArtifactVersion.java | 12 +- .../com/axonivy/market/entity/Product.java | 21 ++- .../java/com/axonivy/market/entity/User.java | 40 ++--- .../com/axonivy/market/enums/ErrorCode.java | 15 +- .../com/axonivy/market/enums/SortOption.java | 5 +- .../com/axonivy/market/enums/TypeOption.java | 3 +- .../market/exceptions/ExceptionHandlers.java | 6 +- .../model/Oauth2ExchangeCodeException.java | 8 +- .../market/factory/ProductFactory.java | 31 ++-- .../market/github/model/ArchivedArtifact.java | 8 +- .../market/github/model/MavenArtifact.java | 20 +-- .../service/GHAxonIvyMarketRepoService.java | 8 +- .../service/GHAxonIvyProductRepoService.java | 1 - .../market/github/service/GitHubService.java | 4 +- .../impl/GHAxonIvyMarketRepoServiceImpl.java | 9 +- .../impl/GHAxonIvyProductRepoServiceImpl.java | 32 ++-- .../service/impl/GitHubServiceImpl.java | 108 +++++++----- .../market/github/util/GitHubUtils.java | 129 +++++++------- .../axonivy/market/model/DisplayValue.java | 39 +++-- .../axonivy/market/model/FeedbackModel.java | 53 +++--- .../model/GitHubAccessTokenResponse.java | 22 +++ .../model/MavenArtifactVersionModel.java | 4 +- .../market/model/Oauth2AuthorizationCode.java | 2 +- .../axonivy/market/model/ProductModel.java | 34 ++-- .../market/repository/UserRepository.java | 2 +- .../market/schedulingtask/ScheduledTasks.java | 2 +- .../market/service/FeedbackService.java | 7 +- .../axonivy/market/service/JwtService.java | 2 + .../axonivy/market/service/UserService.java | 2 + .../market/service/VersionService.java | 10 +- .../service/impl/FeedbackServiceImpl.java | 58 ++++--- .../market/service/impl/JwtServiceImpl.java | 8 +- .../service/impl/ProductServiceImpl.java | 158 +++++++++--------- .../market/service/impl/UserServiceImpl.java | 3 +- .../service/impl/VersionServiceImpl.java | 53 +++--- .../axonivy/market/util/XmlReaderUtils.java | 3 +- .../controller/FeedbackControllerTest.java | 14 +- .../controller/OAuth2ControllerTest.java | 9 +- .../controller/ProductControllerTest.java | 9 - .../ProductDetailsControllerTest.java | 47 +++--- .../market/factory/ProductFactoryTest.java | 26 ++- .../service/FeedbackServiceImplTest.java | 65 ++++--- .../GHAxonIvyMarketRepoServiceImplTest.java | 6 +- .../GHAxonIvyProductRepoServiceImplTest.java | 44 +++-- .../market/service/GitHubServiceImplTest.java | 4 +- .../market/service/JwtServiceImplTest.java | 153 ++++++++--------- .../service/ProductServiceImplTest.java | 118 +++++++------ .../market/service/SchedulingTasksTest.java | 2 +- .../service/VersionServiceImplTest.java | 102 +++++------ .../src/test/resources/meta.json | 8 +- 71 files changed, 989 insertions(+), 866 deletions(-) create mode 100644 marketplace-service/src/main/java/com/axonivy/market/model/GitHubAccessTokenResponse.java diff --git a/marketplace-service/README.md b/marketplace-service/README.md index 4d546f33a..d85b7f861 100644 --- a/marketplace-service/README.md +++ b/marketplace-service/README.md @@ -1,6 +1,7 @@ # Getting Started ### Reference Documentation + For further reference, please consider the following sections: * [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) @@ -9,9 +10,11 @@ For further reference, please consider the following sections: * [Spring Web](https://docs.spring.io/spring-boot/docs/3.2.5/reference/htmlsingle/index.html#web) ### Guides + The following guides illustrate how to use some features concretely: -* Installing mongodb, and access it as Url mongodb://localhost:27017/, and you can create and name whatever you want ,then you should put them to application.properties +* Installing mongodb, and access it as Url mongodb://localhost:27017/, and you can create and name whatever you want + ,then you should put them to application.properties * You can change the MongoDB configuration in file `application.properties` ``` spring.data.mongodb.host= @@ -21,14 +24,18 @@ The following guides illustrate how to use some features concretely: * Run mvn clean install to build project * Run mvn test to test all tests - ### Access Swagger URL: http://{your-host}/swagger-ui/index.html ### Install Lombok for Eclipse IDE + * Download lombok here https://projectlombok.org/download -* run command "java -jar lombok.jar" then you can access file “eclipse.ini“ in eclipse folder where you install → there is a text like this: -javaagent:C:\Users\tvtphuc\eclipse\jee-2024-032\eclipse\lombok.jar → it means you are successful +* run command "java -jar lombok.jar" then you can access file “eclipse.ini“ in eclipse folder where you install → there + is a text like this: -javaagent:C:\Users\tvtphuc\eclipse\jee-2024-032\eclipse\lombok.jar → it means you are + successful * Start eclipse * Import the project then in the eclipse , you should run the command “mvn clean install“ -* After that you go to class MarketplaceServiceApplication → right click to main method → click run as → choose Java Application +* After that you go to class MarketplaceServiceApplication → right click to main method → click run as → choose Java + Application * Then you can send a request in postman -* If you want to run single test in class UserServiceImplTest. You can right-click to method testFindAllUser and right click → select Run as → choose JUnit Test \ No newline at end of file +* If you want to run single test in class UserServiceImplTest. You can right-click to method testFindAllUser and right + click → select Run as → choose JUnit Test \ No newline at end of file diff --git a/marketplace-service/pom.xml b/marketplace-service/pom.xml index d6a0d9a67..44d55027e 100644 --- a/marketplace-service/pom.xml +++ b/marketplace-service/pom.xml @@ -1,13 +1,13 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.springframework.boot spring-boot-starter-parent 3.2.5 - + com.axonivy.market marketplace-service diff --git a/marketplace-service/src/main/java/com/axonivy/market/MarketplaceServiceApplication.java b/marketplace-service/src/main/java/com/axonivy/market/MarketplaceServiceApplication.java index 52cdb27d9..74c7b12d4 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/MarketplaceServiceApplication.java +++ b/marketplace-service/src/main/java/com/axonivy/market/MarketplaceServiceApplication.java @@ -17,7 +17,7 @@ @SpringBootApplication public class MarketplaceServiceApplication { - private ProductService productService; + private final ProductService productService; public MarketplaceServiceApplication(ProductService productService) { this.productService = productService; diff --git a/marketplace-service/src/main/java/com/axonivy/market/assembler/FeedbackModelAssembler.java b/marketplace-service/src/main/java/com/axonivy/market/assembler/FeedbackModelAssembler.java index a981b099a..154abbe99 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/assembler/FeedbackModelAssembler.java +++ b/marketplace-service/src/main/java/com/axonivy/market/assembler/FeedbackModelAssembler.java @@ -28,8 +28,7 @@ public FeedbackModelAssembler(UserService userService) { @Override public FeedbackModel toModel(Feedback feedback) { FeedbackModel resource = new FeedbackModel(); - resource.add(linkTo(methodOn(FeedbackController.class).findFeedback(feedback.getId())) - .withSelfRel()); + resource.add(linkTo(methodOn(FeedbackController.class).findFeedback(feedback.getId())).withSelfRel()); return createResource(resource, feedback); } @@ -37,8 +36,7 @@ private FeedbackModel createResource(FeedbackModel model, Feedback feedback) { User user; try { user = userService.findUser(feedback.getUserId()); - } - catch (NotFoundException e) { + } catch (NotFoundException e) { log.warn(e.getMessage()); user = new User(); } diff --git a/marketplace-service/src/main/java/com/axonivy/market/assembler/ProductDetailModelAssembler.java b/marketplace-service/src/main/java/com/axonivy/market/assembler/ProductDetailModelAssembler.java index ff9ade568..e72ab8034 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/assembler/ProductDetailModelAssembler.java +++ b/marketplace-service/src/main/java/com/axonivy/market/assembler/ProductDetailModelAssembler.java @@ -1,8 +1,5 @@ package com.axonivy.market.assembler; -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; -import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; - import com.axonivy.market.controller.ProductDetailsController; import com.axonivy.market.entity.Product; import com.axonivy.market.entity.ProductModuleContent; @@ -14,6 +11,9 @@ import java.util.List; +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn; + @Component public class ProductDetailModelAssembler extends RepresentationModelAssemblerSupport { diff --git a/marketplace-service/src/main/java/com/axonivy/market/comparator/ArchivedArtifactsComparator.java b/marketplace-service/src/main/java/com/axonivy/market/comparator/ArchivedArtifactsComparator.java index 7a27d7718..d5c553ed2 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/comparator/ArchivedArtifactsComparator.java +++ b/marketplace-service/src/main/java/com/axonivy/market/comparator/ArchivedArtifactsComparator.java @@ -5,10 +5,10 @@ import java.util.Comparator; public class ArchivedArtifactsComparator implements Comparator { - private final LatestVersionComparator comparator = new LatestVersionComparator(); + private final LatestVersionComparator comparator = new LatestVersionComparator(); - @Override - public int compare(ArchivedArtifact artifact1, ArchivedArtifact artifact2) { - return comparator.compare(artifact1.getLastVersion(), artifact2.getLastVersion()); - } + @Override + public int compare(ArchivedArtifact artifact1, ArchivedArtifact artifact2) { + return comparator.compare(artifact1.getLastVersion(), artifact2.getLastVersion()); + } } \ No newline at end of file diff --git a/marketplace-service/src/main/java/com/axonivy/market/comparator/LatestVersionComparator.java b/marketplace-service/src/main/java/com/axonivy/market/comparator/LatestVersionComparator.java index 9419b411f..17d90e397 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/comparator/LatestVersionComparator.java +++ b/marketplace-service/src/main/java/com/axonivy/market/comparator/LatestVersionComparator.java @@ -4,29 +4,29 @@ public class LatestVersionComparator implements Comparator { - @Override - public int compare(String v1, String v2) { - // Split by "." - String[] parts1 = v1.split("\\."); - String[] parts2 = v2.split("\\."); + @Override + public int compare(String v1, String v2) { + // Split by "." + String[] parts1 = v1.split("\\."); + String[] parts2 = v2.split("\\."); - // Compare up to the shorter length - int length = Math.min(parts1.length, parts2.length); - for (int i = 0; i < length; i++) { - try { - int num1 = Integer.parseInt(parts1[i]); - int num2 = Integer.parseInt(parts2[i]); - // Return difference for numeric parts - if (num1 != num2) { - return num2 - num1; - } - // Handle non-numeric parts (e.g., "m229") - } catch (NumberFormatException e) { - return parts2[i].replaceAll("\\D", "").compareTo(parts1[i].replaceAll("\\D", "")); - } - } + // Compare up to the shorter length + int length = Math.min(parts1.length, parts2.length); + for (int i = 0; i < length; i++) { + try { + int num1 = Integer.parseInt(parts1[i]); + int num2 = Integer.parseInt(parts2[i]); + // Return difference for numeric parts + if (num1 != num2) { + return num2 - num1; + } + // Handle non-numeric parts (e.g., "m229") + } catch (NumberFormatException e) { + return parts2[i].replaceAll("\\D", "").compareTo(parts1[i].replaceAll("\\D", "")); + } + } - // Versions with more parts are considered larger - return parts2.length - parts1.length; - } + // Versions with more parts are considered larger + return parts2.length - parts1.length; + } } diff --git a/marketplace-service/src/main/java/com/axonivy/market/config/MarketApiDocumentConfig.java b/marketplace-service/src/main/java/com/axonivy/market/config/MarketApiDocumentConfig.java index 805f30120..0fb1dc852 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/config/MarketApiDocumentConfig.java +++ b/marketplace-service/src/main/java/com/axonivy/market/config/MarketApiDocumentConfig.java @@ -20,18 +20,14 @@ public class MarketApiDocumentConfig { @Bean public GroupedOpenApi buildMarketCustomHeader() { - return GroupedOpenApi.builder() - .group(DEFAULT_DOC_GROUP) - .addOpenApiCustomizer(customMarketHeaders()) - .pathsToMatch(PATH_PATTERN) - .build(); + return GroupedOpenApi.builder().group(DEFAULT_DOC_GROUP).addOpenApiCustomizer(customMarketHeaders()) + .pathsToMatch(PATH_PATTERN).build(); } private OpenApiCustomizer customMarketHeaders() { return openApi -> openApi.getPaths().values().forEach((PathItem pathItem) -> { for (Operation operation : pathItem.readOperations()) { - Parameter headerParameter = new Parameter().in(HEADER_PARAM) - .schema(new StringSchema()).name(REQUESTED_BY) + Parameter headerParameter = new Parameter().in(HEADER_PARAM).schema(new StringSchema()).name(REQUESTED_BY) .description(DEFAULT_PARAM).required(true); operation.addParametersItem(headerParameter); } diff --git a/marketplace-service/src/main/java/com/axonivy/market/config/MongoConfig.java b/marketplace-service/src/main/java/com/axonivy/market/config/MongoConfig.java index 7f558f1cc..315b7384c 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/config/MongoConfig.java +++ b/marketplace-service/src/main/java/com/axonivy/market/config/MongoConfig.java @@ -22,39 +22,39 @@ @EnableMongoAuditing public class MongoConfig extends AbstractMongoClientConfiguration { - @Value("${spring.data.mongodb.host}") - private String host; - - @Value("${spring.data.mongodb.database}") - private String databaseName; - - @Override - protected String getDatabaseName() { - return databaseName; - } - - @Override - public MongoClient mongoClient() { - ConnectionString connectionString = new ConnectionString(host); - MongoClientSettings mongoClientSettings = MongoClientSettings.builder().applyConnectionString(connectionString) - .build(); - - return MongoClients.create(mongoClientSettings); - } - - /** - * By default, the key in hash map is not allow to contain dot character (.) we - * need to escape it by define a replacement to that char - **/ - @Override - @Bean - public MappingMongoConverter mappingMongoConverter(MongoDatabaseFactory databaseFactory, - MongoCustomConversions customConversions, MongoMappingContext mappingContext) { - DbRefResolver dbRefResolver = new DefaultDbRefResolver(databaseFactory); - MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mappingContext); - converter.setCustomConversions(customConversions); - converter.setCodecRegistryProvider(databaseFactory); - converter.setMapKeyDotReplacement("_"); - return converter; - } + @Value("${spring.data.mongodb.host}") + private String host; + + @Value("${spring.data.mongodb.database}") + private String databaseName; + + @Override + protected String getDatabaseName() { + return databaseName; + } + + @Override + public MongoClient mongoClient() { + ConnectionString connectionString = new ConnectionString(host); + MongoClientSettings mongoClientSettings = MongoClientSettings.builder().applyConnectionString(connectionString) + .build(); + + return MongoClients.create(mongoClientSettings); + } + + /** + * By default, the key in hash map is not allow to contain dot character (.) we need to escape it by define a + * replacement to that char + **/ + @Override + @Bean + public MappingMongoConverter mappingMongoConverter(MongoDatabaseFactory databaseFactory, + MongoCustomConversions customConversions, MongoMappingContext mappingContext) { + DbRefResolver dbRefResolver = new DefaultDbRefResolver(databaseFactory); + MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mappingContext); + converter.setCustomConversions(customConversions); + converter.setCodecRegistryProvider(databaseFactory); + converter.setMapKeyDotReplacement("_"); + return converter; + } } diff --git a/marketplace-service/src/main/java/com/axonivy/market/config/WebConfig.java b/marketplace-service/src/main/java/com/axonivy/market/config/WebConfig.java index b9d75afa3..a781aa8ea 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/config/WebConfig.java +++ b/marketplace-service/src/main/java/com/axonivy/market/config/WebConfig.java @@ -11,7 +11,7 @@ public class WebConfig implements WebMvcConfigurer { private static final String[] EXCLUDE_PATHS = { "/", "/swagger-ui/**", "/api-docs/**" }; private static final String[] ALLOWED_HEADERS = { "Accept-Language", "Content-Type", "Authorization", - "X-Requested-By", "x-requested-with", "X-Forwarded-Host" }; + "X-Requested-By", "x-requested-with", "X-Forwarded-Host", "x-xsrf-token" }; private static final String[] ALLOWED_METHODS = { "GET", "POST", "PUT", "DELETE", "OPTIONS" }; private final MarketHeaderInterceptor headerInterceptor; @@ -33,10 +33,7 @@ public void addInterceptors(InterceptorRegistry registry) { @Override public void addCorsMappings(CorsRegistry registry) { - registry.addMapping("/**") - .allowedOriginPatterns(marketCorsAllowedOriginPatterns) - .allowedMethods(ALLOWED_METHODS) - .allowedHeaders(ALLOWED_HEADERS) - .maxAge(marketCorsAllowedOriginMaxAge); + registry.addMapping("/**").allowedOriginPatterns(marketCorsAllowedOriginPatterns).allowedMethods(ALLOWED_METHODS) + .allowedHeaders(ALLOWED_HEADERS).maxAge(marketCorsAllowedOriginMaxAge); } } \ No newline at end of file diff --git a/marketplace-service/src/main/java/com/axonivy/market/constants/EntityConstants.java b/marketplace-service/src/main/java/com/axonivy/market/constants/EntityConstants.java index 0d9752cb9..d6bd38fbd 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/constants/EntityConstants.java +++ b/marketplace-service/src/main/java/com/axonivy/market/constants/EntityConstants.java @@ -5,9 +5,9 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class EntityConstants { - public static final String USER = "User"; - public static final String PRODUCT = "Product"; - public static final String MAVEN_ARTIFACT_VERSION = "MavenArtifactVersion"; - public static final String GH_REPO_META = "GitHubRepoMeta"; - public static final String FEEDBACK = "Feedback"; + public static final String USER = "User"; + public static final String PRODUCT = "Product"; + public static final String MAVEN_ARTIFACT_VERSION = "MavenArtifactVersion"; + public static final String GH_REPO_META = "GitHubRepoMeta"; + public static final String FEEDBACK = "Feedback"; } diff --git a/marketplace-service/src/main/java/com/axonivy/market/constants/MavenConstants.java b/marketplace-service/src/main/java/com/axonivy/market/constants/MavenConstants.java index 4ba05471d..71cdb72ee 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/constants/MavenConstants.java +++ b/marketplace-service/src/main/java/com/axonivy/market/constants/MavenConstants.java @@ -1,7 +1,8 @@ package com.axonivy.market.constants; public class MavenConstants { - private MavenConstants() {} + private MavenConstants() { + } public static final String SNAPSHOT_RELEASE_POSTFIX = "-SNAPSHOT"; public static final String SPRINT_RELEASE_POSTFIX = "-m"; diff --git a/marketplace-service/src/main/java/com/axonivy/market/constants/NonStandardProductPackageConstants.java b/marketplace-service/src/main/java/com/axonivy/market/constants/NonStandardProductPackageConstants.java index 133ff55ff..dec20303d 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/constants/NonStandardProductPackageConstants.java +++ b/marketplace-service/src/main/java/com/axonivy/market/constants/NonStandardProductPackageConstants.java @@ -1,7 +1,8 @@ package com.axonivy.market.constants; public class NonStandardProductPackageConstants { - private NonStandardProductPackageConstants() {} + private NonStandardProductPackageConstants() { + } public static final String PORTAL = "portal"; public static final String MICROSOFT_REPO_NAME = "msgraph-connector"; diff --git a/marketplace-service/src/main/java/com/axonivy/market/constants/ProductJsonConstants.java b/marketplace-service/src/main/java/com/axonivy/market/constants/ProductJsonConstants.java index 96c6eb5e1..8d3aa03a2 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/constants/ProductJsonConstants.java +++ b/marketplace-service/src/main/java/com/axonivy/market/constants/ProductJsonConstants.java @@ -17,5 +17,6 @@ public class ProductJsonConstants { public static final String MAVEN_DROPIN_INSTALLER_ID = "maven-dropins"; public static final String MAVEN_DEPENDENCY_INSTALLER_ID = "maven-dependency"; - private ProductJsonConstants() {} + private ProductJsonConstants() { + } } diff --git a/marketplace-service/src/main/java/com/axonivy/market/controller/AppController.java b/marketplace-service/src/main/java/com/axonivy/market/controller/AppController.java index 45f712d2d..536b348cf 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/controller/AppController.java +++ b/marketplace-service/src/main/java/com/axonivy/market/controller/AppController.java @@ -23,8 +23,7 @@ public ResponseEntity root() { var message = new Message(); message.setHelpCode(ErrorCode.SUCCESSFUL.getCode()); message.setMessageDetails( - "Marketplace API is a REST APIs for Marketplace website. Try with %s" - .formatted(extractSwaggerUrl())); + "Marketplace API is a REST APIs for Marketplace website. Try with %s".formatted(extractSwaggerUrl())); message.setHelpText(ErrorCode.SUCCESSFUL.getHelpText()); return new ResponseEntity<>(message, HttpStatus.OK); } diff --git a/marketplace-service/src/main/java/com/axonivy/market/controller/FeedbackController.java b/marketplace-service/src/main/java/com/axonivy/market/controller/FeedbackController.java index 233c94b4e..4d04faa3c 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/controller/FeedbackController.java +++ b/marketplace-service/src/main/java/com/axonivy/market/controller/FeedbackController.java @@ -16,7 +16,14 @@ import org.springframework.hateoas.PagedModel; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +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.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import java.net.URI; @@ -34,7 +41,8 @@ public class FeedbackController { private final PagedResourcesAssembler pagedResourcesAssembler; - public FeedbackController(FeedbackService feedbackService, JwtService jwtService, FeedbackModelAssembler feedbackModelAssembler, PagedResourcesAssembler pagedResourcesAssembler) { + public FeedbackController(FeedbackService feedbackService, JwtService jwtService, + FeedbackModelAssembler feedbackModelAssembler, PagedResourcesAssembler pagedResourcesAssembler) { this.feedbackService = feedbackService; this.jwtService = jwtService; this.feedbackModelAssembler = feedbackModelAssembler; @@ -43,7 +51,8 @@ public FeedbackController(FeedbackService feedbackService, JwtService jwtService @Operation(summary = "Find all feedbacks by product id") @GetMapping("/product/{productId}") - public ResponseEntity> findFeedbacks(@PathVariable("productId") String productId, Pageable pageable) { + public ResponseEntity> findFeedbacks(@PathVariable("productId") String productId, + Pageable pageable) { Page results = feedbackService.findFeedbacks(productId, pageable); if (results.isEmpty()) { return generateEmptyPagedModel(); @@ -61,15 +70,15 @@ public ResponseEntity findFeedback(@PathVariable("id") String id) @Operation(summary = "Find all feedbacks by user id and product id") @GetMapping() - public ResponseEntity findFeedbackByUserIdAndProductId( - @RequestParam String userId, + public ResponseEntity findFeedbackByUserIdAndProductId(@RequestParam String userId, @RequestParam String productId) { Feedback feedback = feedbackService.findFeedbackByUserIdAndProductId(userId, productId); return ResponseEntity.ok(feedbackModelAssembler.toModel(feedback)); } @PostMapping - public ResponseEntity createFeedback(@RequestBody @Valid Feedback feedback, @RequestHeader(value = "Authorization", required = false) String authorizationHeader) { + public ResponseEntity createFeedback(@RequestBody @Valid FeedbackModel feedback, + @RequestHeader(value = "Authorization", required = false) String authorizationHeader) { String token = null; if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { token = authorizationHeader.substring(7); // Remove "Bearer " prefix @@ -84,9 +93,7 @@ public ResponseEntity createFeedback(@RequestBody @Valid Feedback feedback feedback.setUserId(claims.getSubject()); Feedback newFeedback = feedbackService.upsertFeedback(feedback); - URI location = ServletUriComponentsBuilder.fromCurrentRequest() - .path("/{id}") - .buildAndExpand(newFeedback.getId()) + URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(newFeedback.getId()) .toUri(); return ResponseEntity.created(location).build(); @@ -100,8 +107,8 @@ public ResponseEntity> getProductRating(@PathVariable("produ @SuppressWarnings("unchecked") private ResponseEntity> generateEmptyPagedModel() { - var emptyPagedModel = (PagedModel) pagedResourcesAssembler - .toEmptyModel(Page.empty(), FeedbackModel.class); + var emptyPagedModel = (PagedModel) pagedResourcesAssembler.toEmptyModel(Page.empty(), + FeedbackModel.class); return new ResponseEntity<>(emptyPagedModel, HttpStatus.OK); } } diff --git a/marketplace-service/src/main/java/com/axonivy/market/controller/OAuth2Controller.java b/marketplace-service/src/main/java/com/axonivy/market/controller/OAuth2Controller.java index a3ebbca64..611b6a860 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/controller/OAuth2Controller.java +++ b/marketplace-service/src/main/java/com/axonivy/market/controller/OAuth2Controller.java @@ -3,6 +3,7 @@ import com.axonivy.market.constants.GitHubConstants; import com.axonivy.market.entity.User; import com.axonivy.market.github.service.GitHubService; +import com.axonivy.market.model.GitHubAccessTokenResponse; import com.axonivy.market.model.Oauth2AuthorizationCode; import com.axonivy.market.service.JwtService; import org.springframework.beans.factory.annotation.Value; @@ -13,7 +14,6 @@ import org.springframework.web.bind.annotation.RestController; import java.util.Collections; -import java.util.Map; @RestController @RequestMapping("/auth") @@ -35,9 +35,10 @@ public OAuth2Controller(GitHubService gitHubService, JwtService jwtService) { } @PostMapping("/github/login") - public ResponseEntity gitHubLogin(@RequestBody Oauth2AuthorizationCode oauth2AuthorizationCode) { - Map tokenResponse = gitHubService.getAccessToken(oauth2AuthorizationCode.getCode(), clientId, clientSecret); - String accessToken = (String) tokenResponse.get(GitHubConstants.Json.ACCESS_TOKEN); + public ResponseEntity gitHubLogin(@RequestBody Oauth2AuthorizationCode oauth2AuthorizationCode) { + GitHubAccessTokenResponse tokenResponse = gitHubService.getAccessToken(oauth2AuthorizationCode.getCode(), clientId, + clientSecret); + String accessToken = tokenResponse.getAccessToken(); User user = gitHubService.getAndUpdateUser(accessToken); diff --git a/marketplace-service/src/main/java/com/axonivy/market/controller/ProductController.java b/marketplace-service/src/main/java/com/axonivy/market/controller/ProductController.java index 6dbd73c4d..498424e11 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/controller/ProductController.java +++ b/marketplace-service/src/main/java/com/axonivy/market/controller/ProductController.java @@ -15,7 +15,11 @@ import org.springframework.hateoas.PagedModel; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; import static com.axonivy.market.constants.RequestMappingConstants.PRODUCT; import static com.axonivy.market.constants.RequestMappingConstants.SYNC; @@ -29,7 +33,7 @@ public class ProductController { private final PagedResourcesAssembler pagedResourcesAssembler; public ProductController(ProductService productService, ProductModelAssembler assembler, - PagedResourcesAssembler pagedResourcesAssembler) { + PagedResourcesAssembler pagedResourcesAssembler) { this.productService = productService; this.assembler = assembler; this.pagedResourcesAssembler = pagedResourcesAssembler; @@ -37,8 +41,7 @@ public ProductController(ProductService productService, ProductModelAssembler as @Operation(summary = "Find all products", description = "Be default system will finds product by type as 'all'") @GetMapping() - public ResponseEntity> findProducts( - @RequestParam(name = "type") String type, + public ResponseEntity> findProducts(@RequestParam(name = "type") String type, @RequestParam(required = false, name = "keyword") String keyword, @RequestParam(name = "language") String language, Pageable pageable) { Page results = productService.findProducts(type, keyword, language, pageable); @@ -69,8 +72,8 @@ public ResponseEntity syncProducts() { @SuppressWarnings("unchecked") private ResponseEntity> generateEmptyPagedModel() { - var emptyPagedModel = - (PagedModel) pagedResourcesAssembler.toEmptyModel(Page.empty(), ProductModel.class); + var emptyPagedModel = (PagedModel) pagedResourcesAssembler.toEmptyModel(Page.empty(), + ProductModel.class); return new ResponseEntity<>(emptyPagedModel, HttpStatus.OK); } } diff --git a/marketplace-service/src/main/java/com/axonivy/market/controller/ProductDetailsController.java b/marketplace-service/src/main/java/com/axonivy/market/controller/ProductDetailsController.java index 87fa6b218..b57f80e0f 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/controller/ProductDetailsController.java +++ b/marketplace-service/src/main/java/com/axonivy/market/controller/ProductDetailsController.java @@ -1,9 +1,11 @@ package com.axonivy.market.controller; -import static com.axonivy.market.constants.RequestMappingConstants.PRODUCT_DETAILS; - -import java.util.List; - +import com.axonivy.market.assembler.ProductDetailModelAssembler; +import com.axonivy.market.model.MavenArtifactVersionModel; +import com.axonivy.market.model.ProductDetailModel; +import com.axonivy.market.service.ProductService; +import com.axonivy.market.service.VersionService; +import io.swagger.v3.oas.annotations.Operation; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -13,13 +15,9 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import com.axonivy.market.assembler.ProductDetailModelAssembler; -import com.axonivy.market.model.MavenArtifactVersionModel; -import com.axonivy.market.model.ProductDetailModel; -import com.axonivy.market.service.ProductService; -import com.axonivy.market.service.VersionService; +import java.util.List; -import io.swagger.v3.oas.annotations.Operation; +import static com.axonivy.market.constants.RequestMappingConstants.PRODUCT_DETAILS; @RestController @RequestMapping(PRODUCT_DETAILS) diff --git a/marketplace-service/src/main/java/com/axonivy/market/entity/Feedback.java b/marketplace-service/src/main/java/com/axonivy/market/entity/Feedback.java index 166da0c23..fea74af1b 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/entity/Feedback.java +++ b/marketplace-service/src/main/java/com/axonivy/market/entity/Feedback.java @@ -1,9 +1,5 @@ package com.axonivy.market.entity; -import jakarta.validation.constraints.Max; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.Size; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -29,18 +25,9 @@ public class Feedback implements Serializable { @Id private String id; - private String userId; - - @NotBlank(message = "Product id cannot be blank") private String productId; - - @NotBlank(message = "Content cannot be blank") - @Size(max = 5, message = "Content length must be up to 250 characters") private String content; - - @Min(value = 1, message = "Rating should not be less than 1") - @Max(value = 5, message = "Rating should not be greater than 5") private Integer rating; @CreatedDate diff --git a/marketplace-service/src/main/java/com/axonivy/market/entity/MavenArtifactModel.java b/marketplace-service/src/main/java/com/axonivy/market/entity/MavenArtifactModel.java index 2d48d4c6a..1c9ad87ec 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/entity/MavenArtifactModel.java +++ b/marketplace-service/src/main/java/com/axonivy/market/entity/MavenArtifactModel.java @@ -14,25 +14,25 @@ @Setter @Getter public class MavenArtifactModel implements Serializable { - private static final long serialVersionUID = 1L; - private String name; - private String downloadUrl; - @Transient - private Boolean isProductArtifact; + private static final long serialVersionUID = 1L; + private String name; + private String downloadUrl; + @Transient + private Boolean isProductArtifact; - @Override - public boolean equals(Object object) { - if (this == object) - return true; - if (object == null || getClass() != object.getClass()) { - return false; - } - MavenArtifactModel reference = (MavenArtifactModel) object; - return Objects.equals(name, reference.getName()) && Objects.equals(downloadUrl, reference.getDownloadUrl()); - } + @Override + public boolean equals(Object object) { + if (this == object) + return true; + if (object == null || getClass() != object.getClass()) { + return false; + } + MavenArtifactModel reference = (MavenArtifactModel) object; + return Objects.equals(name, reference.getName()) && Objects.equals(downloadUrl, reference.getDownloadUrl()); + } - @Override - public int hashCode() { - return Objects.hash(name, downloadUrl); - } + @Override + public int hashCode() { + return Objects.hash(name, downloadUrl); + } } \ No newline at end of file diff --git a/marketplace-service/src/main/java/com/axonivy/market/entity/MavenArtifactVersion.java b/marketplace-service/src/main/java/com/axonivy/market/entity/MavenArtifactVersion.java index 8c8820579..8f2e87291 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/entity/MavenArtifactVersion.java +++ b/marketplace-service/src/main/java/com/axonivy/market/entity/MavenArtifactVersion.java @@ -24,11 +24,11 @@ public class MavenArtifactVersion implements Serializable { private static final long serialVersionUID = -6492612804634492078L; @Id - private String productId; - private List versions = new ArrayList<>(); - private Map> productArtifactWithVersionReleased = new HashMap<>(); + private String productId; + private List versions = new ArrayList<>(); + private Map> productArtifactWithVersionReleased = new HashMap<>(); - public MavenArtifactVersion(String productId) { - this.productId = productId; - } + public MavenArtifactVersion(String productId) { + this.productId = productId; + } } \ No newline at end of file diff --git a/marketplace-service/src/main/java/com/axonivy/market/entity/Product.java b/marketplace-service/src/main/java/com/axonivy/market/entity/Product.java index b1a135c31..a6d4c39df 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/entity/Product.java +++ b/marketplace-service/src/main/java/com/axonivy/market/entity/Product.java @@ -1,21 +1,24 @@ package com.axonivy.market.entity; -import static com.axonivy.market.constants.EntityConstants.PRODUCT; - -import java.io.Serializable; -import java.util.Date; -import java.util.List; - - +import com.axonivy.market.github.model.MavenArtifact; import com.axonivy.market.model.MultilingualismValue; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.*; -import com.axonivy.market.github.model.MavenArtifact; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import static com.axonivy.market.constants.EntityConstants.PRODUCT; + @Getter @Setter @AllArgsConstructor diff --git a/marketplace-service/src/main/java/com/axonivy/market/entity/User.java b/marketplace-service/src/main/java/com/axonivy/market/entity/User.java index 0f8e7b612..65c996981 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/entity/User.java +++ b/marketplace-service/src/main/java/com/axonivy/market/entity/User.java @@ -19,30 +19,30 @@ @NoArgsConstructor @Document(USER) public class User implements Serializable { - @Serial - private static final long serialVersionUID = -1244486023332931059L; + @Serial + private static final long serialVersionUID = -1244486023332931059L; - @Id - private String id; + @Id + private String id; - @Indexed(unique = true) - private String gitHubId; + @Indexed(unique = true) + private String gitHubId; - private String provider; - private String username; - private String name; - private String avatarUrl; + private String provider; + private String username; + private String name; + private String avatarUrl; - @Override - public int hashCode() { - return new HashCodeBuilder().append(id).hashCode(); - } + @Override + public int hashCode() { + return new HashCodeBuilder().append(id).hashCode(); + } - @Override - public boolean equals(Object obj) { - if (obj == null || this.getClass() != obj.getClass()) { - return false; - } - return new EqualsBuilder().append(id, ((User) obj).getId()).isEquals(); + @Override + public boolean equals(Object obj) { + if (obj == null || this.getClass() != obj.getClass()) { + return false; } + return new EqualsBuilder().append(id, ((User) obj).getId()).isEquals(); + } } diff --git a/marketplace-service/src/main/java/com/axonivy/market/enums/ErrorCode.java b/marketplace-service/src/main/java/com/axonivy/market/enums/ErrorCode.java index 7aef2b47c..650463ef5 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/enums/ErrorCode.java +++ b/marketplace-service/src/main/java/com/axonivy/market/enums/ErrorCode.java @@ -4,12 +4,9 @@ import lombok.Getter; import lombok.NoArgsConstructor; - /** - * @fo {@link ErrorCode} is a presentation for a system code during proceeding - * data It has format cseo - 0000 c present for controller s present for - * service e present for entity o present for other And 0000 is a successful - * code + * @fo {@link ErrorCode} is a presentation for a system code during proceeding data It has format cseo - 0000 c present + * for controller s present for service e present for entity o present for other And 0000 is a successful code */ @Getter @@ -17,12 +14,10 @@ @NoArgsConstructor public enum ErrorCode { SUCCESSFUL("0000", "SUCCESSFUL"), PRODUCT_FILTER_INVALID("1101", "PRODUCT_FILTER_INVALID"), - PRODUCT_SORT_INVALID("1102", "PRODUCT_SORT_INVALID"), - PRODUCT_NOT_FOUND("1103", "PRODUCT_NOT_FOUND"), + PRODUCT_SORT_INVALID("1102", "PRODUCT_SORT_INVALID"), PRODUCT_NOT_FOUND("1103", "PRODUCT_NOT_FOUND"), GH_FILE_STATUS_INVALID("0201", "GIT_HUB_FILE_STATUS_INVALID"), - GH_FILE_TYPE_INVALID("0202", "GIT_HUB_FILE_TYPE_INVALID"), - USER_NOT_FOUND("2103", "USER_NOT_FOUND"), - FEEDBACK_NOT_FOUND("3103", "FEEDBACK_NOT_FOUND"), + GH_FILE_TYPE_INVALID("0202", "GIT_HUB_FILE_TYPE_INVALID"), USER_NOT_FOUND("2103", "USER_NOT_FOUND"), + GITHUB_USER_NOT_FOUND("2204", "GITHUB_USER_NOT_FOUND"), FEEDBACK_NOT_FOUND("3103", "FEEDBACK_NOT_FOUND"), ARGUMENT_BAD_REQUEST("4000", "ARGUMENT_BAD_REQUEST"); String code; diff --git a/marketplace-service/src/main/java/com/axonivy/market/enums/SortOption.java b/marketplace-service/src/main/java/com/axonivy/market/enums/SortOption.java index c3e9714e3..303c57b2b 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/enums/SortOption.java +++ b/marketplace-service/src/main/java/com/axonivy/market/enums/SortOption.java @@ -25,8 +25,7 @@ public static SortOption of(String option) { } public String getCode(String language) { - return StringUtils.isNotBlank(language) && ALPHABETICALLY.option.equalsIgnoreCase(option) - ? String.format("%s.%s", ALPHABETICALLY.code, language) - : code; + return StringUtils.isNotBlank(language) && ALPHABETICALLY.option.equalsIgnoreCase(option) ? String.format("%s.%s", + ALPHABETICALLY.code, language) : code; } } diff --git a/marketplace-service/src/main/java/com/axonivy/market/enums/TypeOption.java b/marketplace-service/src/main/java/com/axonivy/market/enums/TypeOption.java index 1c30aca92..3176a7ba9 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/enums/TypeOption.java +++ b/marketplace-service/src/main/java/com/axonivy/market/enums/TypeOption.java @@ -6,7 +6,8 @@ @Getter public enum TypeOption { - ALL("all", ""), CONNECTORS("connectors", "connector"), UTILITIES("utilities", "util"), SOLUTIONS("solutions", "solution"), DEMOS("demos", "demo"); + ALL("all", ""), CONNECTORS("connectors", "connector"), UTILITIES("utilities", "util"), + SOLUTIONS("solutions", "solution"), DEMOS("demos", "demo"); private String option; private String code; diff --git a/marketplace-service/src/main/java/com/axonivy/market/exceptions/ExceptionHandlers.java b/marketplace-service/src/main/java/com/axonivy/market/exceptions/ExceptionHandlers.java index d9b1ab725..948d28fc3 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/exceptions/ExceptionHandlers.java +++ b/marketplace-service/src/main/java/com/axonivy/market/exceptions/ExceptionHandlers.java @@ -25,7 +25,8 @@ public class ExceptionHandlers extends ResponseEntityExceptionHandler { @Override - protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { + protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, + HttpStatusCode status, WebRequest request) { BindingResult bindingResult = ex.getBindingResult(); List errors = new ArrayList<>(); if (bindingResult.hasErrors()) { @@ -66,7 +67,8 @@ public ResponseEntity handleInvalidException(InvalidParamException inval } @ExceptionHandler(Oauth2ExchangeCodeException.class) - public ResponseEntity handleOauth2ExchangeCodeException(Oauth2ExchangeCodeException oauth2ExchangeCodeException) { + public ResponseEntity handleOauth2ExchangeCodeException( + Oauth2ExchangeCodeException oauth2ExchangeCodeException) { var errorMessage = new Message(); errorMessage.setHelpCode(oauth2ExchangeCodeException.getError()); errorMessage.setMessageDetails(oauth2ExchangeCodeException.getErrorDescription()); diff --git a/marketplace-service/src/main/java/com/axonivy/market/exceptions/model/Oauth2ExchangeCodeException.java b/marketplace-service/src/main/java/com/axonivy/market/exceptions/model/Oauth2ExchangeCodeException.java index d48a88770..09448e2bb 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/exceptions/model/Oauth2ExchangeCodeException.java +++ b/marketplace-service/src/main/java/com/axonivy/market/exceptions/model/Oauth2ExchangeCodeException.java @@ -11,9 +11,9 @@ @AllArgsConstructor public class Oauth2ExchangeCodeException extends RuntimeException { - @Serial - private static final long serialVersionUID = 6778659816121728814L; + @Serial + private static final long serialVersionUID = 6778659816121728814L; - private String error; - private String errorDescription; + private final String error; + private final String errorDescription; } diff --git a/marketplace-service/src/main/java/com/axonivy/market/factory/ProductFactory.java b/marketplace-service/src/main/java/com/axonivy/market/factory/ProductFactory.java index 38e16a438..b7c4580ec 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/factory/ProductFactory.java +++ b/marketplace-service/src/main/java/com/axonivy/market/factory/ProductFactory.java @@ -1,31 +1,30 @@ package com.axonivy.market.factory; -import static com.axonivy.market.constants.CommonConstants.LOGO_FILE; -import static com.axonivy.market.constants.CommonConstants.SLASH; -import static com.axonivy.market.constants.MetaConstants.*; -import static org.apache.commons.lang3.StringUtils.EMPTY; - +import com.axonivy.market.entity.Product; import com.axonivy.market.enums.Language; +import com.axonivy.market.github.model.Meta; import com.axonivy.market.github.util.GitHubUtils; import com.axonivy.market.model.DisplayValue; import com.axonivy.market.model.MultilingualismValue; -import org.apache.commons.lang3.BooleanUtils; - -import java.io.IOException; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; -import org.kohsuke.github.GHContent; - -import com.axonivy.market.entity.Product; -import com.axonivy.market.github.model.Meta; import com.fasterxml.jackson.databind.ObjectMapper; - import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.log4j.Log4j2; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.kohsuke.github.GHContent; import org.springframework.util.CollectionUtils; +import java.io.IOException; +import java.util.List; + +import static com.axonivy.market.constants.CommonConstants.LOGO_FILE; +import static com.axonivy.market.constants.CommonConstants.SLASH; +import static com.axonivy.market.constants.MetaConstants.DEFAULT_VENDOR_NAME; +import static com.axonivy.market.constants.MetaConstants.DEFAULT_VENDOR_URL; +import static com.axonivy.market.constants.MetaConstants.META_FILE; +import static org.apache.commons.lang3.StringUtils.EMPTY; + @Log4j2 @NoArgsConstructor(access = AccessLevel.PRIVATE) public class ProductFactory { diff --git a/marketplace-service/src/main/java/com/axonivy/market/github/model/ArchivedArtifact.java b/marketplace-service/src/main/java/com/axonivy/market/github/model/ArchivedArtifact.java index f9ff5a69f..0bd450349 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/github/model/ArchivedArtifact.java +++ b/marketplace-service/src/main/java/com/axonivy/market/github/model/ArchivedArtifact.java @@ -16,8 +16,8 @@ @JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonIgnoreProperties(ignoreUnknown = true) public class ArchivedArtifact implements Serializable { - private static final long serialVersionUID = 1L; - private String lastVersion; - private String groupId; - private String artifactId; + private static final long serialVersionUID = 1L; + private String lastVersion; + private String groupId; + private String artifactId; } \ No newline at end of file diff --git a/marketplace-service/src/main/java/com/axonivy/market/github/model/MavenArtifact.java b/marketplace-service/src/main/java/com/axonivy/market/github/model/MavenArtifact.java index 811b7917b..5c7cf3a37 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/github/model/MavenArtifact.java +++ b/marketplace-service/src/main/java/com/axonivy/market/github/model/MavenArtifact.java @@ -18,14 +18,14 @@ @JsonInclude(JsonInclude.Include.NON_EMPTY) @JsonIgnoreProperties(ignoreUnknown = true) public class MavenArtifact implements Serializable { - private static final long serialVersionUID = 1L; - private String repoUrl; - private String name; - private String groupId; - private String artifactId; - private String type; - private Boolean isDependency; - @Transient - private Boolean isProductArtifact; - private List archivedArtifacts; + private static final long serialVersionUID = 1L; + private String repoUrl; + private String name; + private String groupId; + private String artifactId; + private String type; + private Boolean isDependency; + @Transient + private Boolean isProductArtifact; + private List archivedArtifacts; } diff --git a/marketplace-service/src/main/java/com/axonivy/market/github/service/GHAxonIvyMarketRepoService.java b/marketplace-service/src/main/java/com/axonivy/market/github/service/GHAxonIvyMarketRepoService.java index 8a3cb88f3..a75787bd1 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/github/service/GHAxonIvyMarketRepoService.java +++ b/marketplace-service/src/main/java/com/axonivy/market/github/service/GHAxonIvyMarketRepoService.java @@ -10,11 +10,11 @@ public interface GHAxonIvyMarketRepoService { - public Map> fetchAllMarketItems(); + Map> fetchAllMarketItems(); - public GHCommit getLastCommit(long lastCommitTime); + GHCommit getLastCommit(long lastCommitTime); - public List fetchMarketItemsBySHA1Range(String fromSHA1, String toSHA1); + List fetchMarketItemsBySHA1Range(String fromSHA1, String toSHA1); - public GHRepository getRepository(); + GHRepository getRepository(); } diff --git a/marketplace-service/src/main/java/com/axonivy/market/github/service/GHAxonIvyProductRepoService.java b/marketplace-service/src/main/java/com/axonivy/market/github/service/GHAxonIvyProductRepoService.java index 46afa0f0c..2f26df9c6 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/github/service/GHAxonIvyProductRepoService.java +++ b/marketplace-service/src/main/java/com/axonivy/market/github/service/GHAxonIvyProductRepoService.java @@ -3,7 +3,6 @@ import com.axonivy.market.entity.Product; import com.axonivy.market.entity.ProductModuleContent; import com.axonivy.market.github.model.MavenArtifact; - import org.kohsuke.github.GHContent; import org.kohsuke.github.GHRepository; import org.kohsuke.github.GHTag; diff --git a/marketplace-service/src/main/java/com/axonivy/market/github/service/GitHubService.java b/marketplace-service/src/main/java/com/axonivy/market/github/service/GitHubService.java index 5cf1a9d01..6e4a19ff5 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/github/service/GitHubService.java +++ b/marketplace-service/src/main/java/com/axonivy/market/github/service/GitHubService.java @@ -1,6 +1,7 @@ package com.axonivy.market.github.service; import com.axonivy.market.entity.User; +import com.axonivy.market.model.GitHubAccessTokenResponse; import org.kohsuke.github.GHContent; import org.kohsuke.github.GHOrganization; import org.kohsuke.github.GHRepository; @@ -8,7 +9,6 @@ import java.io.IOException; import java.util.List; -import java.util.Map; public interface GitHubService { @@ -22,7 +22,7 @@ public interface GitHubService { GHContent getGHContent(GHRepository ghRepository, String path, String ref) throws IOException; - Map getAccessToken(String code, String clientId, String clientSecret); + GitHubAccessTokenResponse getAccessToken(String code, String clientId, String clientSecret); User getAndUpdateUser(String accessToken); } diff --git a/marketplace-service/src/main/java/com/axonivy/market/github/service/impl/GHAxonIvyMarketRepoServiceImpl.java b/marketplace-service/src/main/java/com/axonivy/market/github/service/impl/GHAxonIvyMarketRepoServiceImpl.java index 61aca55a9..1d3f286eb 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/github/service/impl/GHAxonIvyMarketRepoServiceImpl.java +++ b/marketplace-service/src/main/java/com/axonivy/market/github/service/impl/GHAxonIvyMarketRepoServiceImpl.java @@ -8,7 +8,12 @@ import com.axonivy.market.github.service.GitHubService; import com.axonivy.market.github.util.GitHubUtils; import lombok.extern.log4j.Log4j2; -import org.kohsuke.github.*; +import org.kohsuke.github.GHCommit; +import org.kohsuke.github.GHCommitQueryBuilder; +import org.kohsuke.github.GHCompare; +import org.kohsuke.github.GHContent; +import org.kohsuke.github.GHOrganization; +import org.kohsuke.github.GHRepository; import org.springframework.stereotype.Service; import java.io.IOException; @@ -64,7 +69,7 @@ private void extractFileInDirectoryContent(GHContent content, Map convertProductJsonToMavenProductInfo(GHContent conten JsonNode dataNode = mavenNode.path(ProductJsonConstants.DATA); // Not convert to artifact if id of node is not maven-import or maven-dependency - List installerIdsToDisplay = - List.of(ProductJsonConstants.MAVEN_DEPENDENCY_INSTALLER_ID, ProductJsonConstants.MAVEN_IMPORT_INSTALLER_ID); + List installerIdsToDisplay = List.of(ProductJsonConstants.MAVEN_DEPENDENCY_INSTALLER_ID, + ProductJsonConstants.MAVEN_IMPORT_INSTALLER_ID); if (!installerIdsToDisplay.contains(mavenNode.path(ProductJsonConstants.ID).asText())) { continue; } @@ -200,7 +202,8 @@ public String updateImagesWithDownloadUrl(Product product, List conte } for (Map.Entry entry : imageUrls.entrySet()) { String imageUrlPattern = String.format(README_IMAGE_FORMAT, Pattern.quote(entry.getKey())); - readmeContents = readmeContents.replaceAll(imageUrlPattern, String.format(IMAGE_DOWNLOAD_URL_FORMAT,entry.getValue())); + readmeContents = readmeContents.replaceAll(imageUrlPattern, + String.format(IMAGE_DOWNLOAD_URL_FORMAT, entry.getValue())); } return readmeContents; @@ -255,8 +258,7 @@ private List getProductFolderContents(Product product, GHRepository g throws IOException { String productFolderPath = ghRepository.getDirectoryContent(CommonConstants.SLASH, tag).stream() .filter(GHContent::isDirectory).map(GHContent::getName) - .filter(content -> content.endsWith(MavenConstants.PRODUCT_ARTIFACT_POSTFIX)).findFirst() - .orElse(null); + .filter(content -> content.endsWith(MavenConstants.PRODUCT_ARTIFACT_POSTFIX)).findFirst().orElse(null); if (StringUtils.isBlank(productFolderPath) || hasChildConnector(ghRepository)) { productFolderPath = GitHubUtils.getNonStandardProductFilePath(product.getId()); } diff --git a/marketplace-service/src/main/java/com/axonivy/market/github/service/impl/GitHubServiceImpl.java b/marketplace-service/src/main/java/com/axonivy/market/github/service/impl/GitHubServiceImpl.java index 6af97d1fa..ba63635ad 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/github/service/impl/GitHubServiceImpl.java +++ b/marketplace-service/src/main/java/com/axonivy/market/github/service/impl/GitHubServiceImpl.java @@ -2,12 +2,24 @@ import com.axonivy.market.constants.GitHubConstants; import com.axonivy.market.entity.User; +import com.axonivy.market.enums.ErrorCode; +import com.axonivy.market.exceptions.model.NotFoundException; import com.axonivy.market.exceptions.model.Oauth2ExchangeCodeException; import com.axonivy.market.github.service.GitHubService; +import com.axonivy.market.model.GitHubAccessTokenResponse; import com.axonivy.market.repository.UserRepository; -import org.kohsuke.github.*; +import org.kohsuke.github.GHContent; +import org.kohsuke.github.GHOrganization; +import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GitHub; +import org.kohsuke.github.GitHubBuilder; import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.http.*; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import org.springframework.util.LinkedMultiValueMap; @@ -64,56 +76,62 @@ public GHContent getGHContent(GHRepository ghRepository, String path, String ref return ghRepository.getFileContent(path, ref); } - @Override - public Map getAccessToken(String code, String clientId, String clientSecret) throws Oauth2ExchangeCodeException { - MultiValueMap params = new LinkedMultiValueMap<>(); - params.add(GitHubConstants.Json.CLIENT_ID, clientId); - params.add(GitHubConstants.Json.CLIENT_SECRET, clientSecret); - params.add(GitHubConstants.Json.CODE, code); - - HttpHeaders headers = new HttpHeaders(); - headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); - HttpEntity> request = new HttpEntity<>(params, headers); - - ResponseEntity response = restTemplate.postForEntity(GitHubConstants.GITHUB_GET_ACCESS_TOKEN_URL, request, Map.class); - if (response.getBody().containsKey(GitHubConstants.Json.ERROR)) { - throw new Oauth2ExchangeCodeException(response.getBody().get(GitHubConstants.Json.ERROR).toString(), response.getBody().get(GitHubConstants.Json.ERROR_DESCRIPTION).toString()); - } - return response.getBody(); + @Override + public GitHubAccessTokenResponse getAccessToken(String code, String clientId, String clientSecret) + throws Oauth2ExchangeCodeException { + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add(GitHubConstants.Json.CLIENT_ID, clientId); + params.add(GitHubConstants.Json.CLIENT_SECRET, clientSecret); + params.add(GitHubConstants.Json.CODE, code); + + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + HttpEntity> request = new HttpEntity<>(params, headers); + + ResponseEntity responseEntity = restTemplate.postForEntity( + GitHubConstants.GITHUB_GET_ACCESS_TOKEN_URL, request, GitHubAccessTokenResponse.class); + GitHubAccessTokenResponse response = responseEntity.getBody(); + + if (response != null && response.getError() != null && !response.getError().isBlank()) { + throw new Oauth2ExchangeCodeException(response.getError(), response.getErrorDescription()); } - @Override - public User getAndUpdateUser(String accessToken) { - HttpHeaders headers = new HttpHeaders(); - headers.setBearerAuth(accessToken); - HttpEntity entity = new HttpEntity<>(headers); - - ResponseEntity response = restTemplate.exchange( - "https://api.github.com/user", HttpMethod.GET, entity, Map.class); + return response; + } - Map userDetails = response.getBody(); + @Override + public User getAndUpdateUser(String accessToken) { + HttpHeaders headers = new HttpHeaders(); + headers.setBearerAuth(accessToken); + HttpEntity entity = new HttpEntity<>(headers); - if (userDetails == null) { - throw new RuntimeException("Failed to fetch user details from GitHub"); - } + ResponseEntity> response = restTemplate.exchange("https://api.github.com/user", HttpMethod.GET, + entity, new ParameterizedTypeReference<>() { + }); - String gitHubId = userDetails.get(GitHubConstants.Json.USER_ID).toString(); - String name = (String) userDetails.get(GitHubConstants.Json.USER_NAME); - String avatarUrl = (String) userDetails.get(GitHubConstants.Json.USER_AVATAR_URL); - String username = (String) userDetails.get(GitHubConstants.Json.USER_LOGIN_NAME); + Map userDetails = response.getBody(); - User user = userRepository.searchByGitHubId(gitHubId); - if (user == null) { - user = new User(); - } - user.setGitHubId(gitHubId); - user.setName(name); - user.setUsername(username); - user.setAvatarUrl(avatarUrl); - user.setProvider(GitHubConstants.GITHUB_PROVIDER_NAME); + if (userDetails == null) { + throw new NotFoundException(ErrorCode.GITHUB_USER_NOT_FOUND, "Failed to fetch user details from GitHub"); + } - userRepository.save(user); + String gitHubId = userDetails.get(GitHubConstants.Json.USER_ID).toString(); + String name = (String) userDetails.get(GitHubConstants.Json.USER_NAME); + String avatarUrl = (String) userDetails.get(GitHubConstants.Json.USER_AVATAR_URL); + String username = (String) userDetails.get(GitHubConstants.Json.USER_LOGIN_NAME); - return user; + User user = userRepository.searchByGitHubId(gitHubId); + if (user == null) { + user = new User(); } + user.setGitHubId(gitHubId); + user.setName(name); + user.setUsername(username); + user.setAvatarUrl(avatarUrl); + user.setProvider(GitHubConstants.GITHUB_PROVIDER_NAME); + + userRepository.save(user); + + return user; + } } \ No newline at end of file diff --git a/marketplace-service/src/main/java/com/axonivy/market/github/util/GitHubUtils.java b/marketplace-service/src/main/java/com/axonivy/market/github/util/GitHubUtils.java index 4ccd7f1d4..c3b172014 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/github/util/GitHubUtils.java +++ b/marketplace-service/src/main/java/com/axonivy/market/github/util/GitHubUtils.java @@ -1,20 +1,19 @@ package com.axonivy.market.github.util; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - import com.axonivy.market.constants.CommonConstants; import com.axonivy.market.constants.NonStandardProductPackageConstants; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.kohsuke.github.GHCommit; import org.kohsuke.github.GHContent; import org.kohsuke.github.PagedIterable; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import lombok.extern.log4j.Log4j2; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; @Log4j2 @NoArgsConstructor(access = AccessLevel.PRIVATE) @@ -24,7 +23,7 @@ public class GitHubUtils { private static String pathToImageFolder; public static long getGHCommitDate(GHCommit commit) { - long commitTime = 0l; + long commitTime = 0L; if (commit != null) { try { commitTime = commit.getCommitDate().getTime(); @@ -66,68 +65,68 @@ public static String convertArtifactIdToName(String artifactId) { public static String getNonStandardProductFilePath(String productId) { switch (productId) { - case NonStandardProductPackageConstants.PORTAL: - pathToProductFolderFromTagContent = "AxonIvyPortal/portal-product"; - break; - case NonStandardProductPackageConstants.CONNECTIVITY_FEATURE: - pathToProductFolderFromTagContent = "connectivity/connectivity-demos-product"; - break; - case NonStandardProductPackageConstants.ERROR_HANDLING: - pathToProductFolderFromTagContent = "error-handling/error-handling-demos-product"; - break; - case NonStandardProductPackageConstants.WORKFLOW_DEMO: - pathToProductFolderFromTagContent = "workflow/workflow-demos-product"; - break; - case NonStandardProductPackageConstants.MICROSOFT_365: - pathToProductFolderFromTagContent = "msgraph-connector-product/products/msgraph-connector"; - break; - case NonStandardProductPackageConstants.MICROSOFT_CALENDAR: - pathToProductFolderFromTagContent = "msgraph-connector-product/products/msgraph-calendar"; - break; - case NonStandardProductPackageConstants.MICROSOFT_TEAMS: - pathToProductFolderFromTagContent = "msgraph-connector-product/products/msgraph-chat"; - break; - case NonStandardProductPackageConstants.MICROSOFT_MAIL: - pathToProductFolderFromTagContent = "msgraph-connector-product/products/msgraph-mail"; - break; - case NonStandardProductPackageConstants.MICROSOFT_TODO: - pathToProductFolderFromTagContent = "msgraph-connector-product/products/msgraph-todo"; - break; - case NonStandardProductPackageConstants.HTML_DIALOG_DEMO: - pathToProductFolderFromTagContent = "html-dialog/html-dialog-demos-product"; - break; - case NonStandardProductPackageConstants.RULE_ENGINE_DEMOS: - pathToProductFolderFromTagContent = "rule-engine/rule-engine-demos-product"; - break; - case NonStandardProductPackageConstants.OPENAI_CONNECTOR: - pathToProductFolderFromTagContent = "openai-connector-product"; - break; - case NonStandardProductPackageConstants.OPENAI_ASSISTANT: - pathToProductFolderFromTagContent = "openai-assistant-product"; - break; - default: - break; + case NonStandardProductPackageConstants.PORTAL: + pathToProductFolderFromTagContent = "AxonIvyPortal/portal-product"; + break; + case NonStandardProductPackageConstants.CONNECTIVITY_FEATURE: + pathToProductFolderFromTagContent = "connectivity/connectivity-demos-product"; + break; + case NonStandardProductPackageConstants.ERROR_HANDLING: + pathToProductFolderFromTagContent = "error-handling/error-handling-demos-product"; + break; + case NonStandardProductPackageConstants.WORKFLOW_DEMO: + pathToProductFolderFromTagContent = "workflow/workflow-demos-product"; + break; + case NonStandardProductPackageConstants.MICROSOFT_365: + pathToProductFolderFromTagContent = "msgraph-connector-product/products/msgraph-connector"; + break; + case NonStandardProductPackageConstants.MICROSOFT_CALENDAR: + pathToProductFolderFromTagContent = "msgraph-connector-product/products/msgraph-calendar"; + break; + case NonStandardProductPackageConstants.MICROSOFT_TEAMS: + pathToProductFolderFromTagContent = "msgraph-connector-product/products/msgraph-chat"; + break; + case NonStandardProductPackageConstants.MICROSOFT_MAIL: + pathToProductFolderFromTagContent = "msgraph-connector-product/products/msgraph-mail"; + break; + case NonStandardProductPackageConstants.MICROSOFT_TODO: + pathToProductFolderFromTagContent = "msgraph-connector-product/products/msgraph-todo"; + break; + case NonStandardProductPackageConstants.HTML_DIALOG_DEMO: + pathToProductFolderFromTagContent = "html-dialog/html-dialog-demos-product"; + break; + case NonStandardProductPackageConstants.RULE_ENGINE_DEMOS: + pathToProductFolderFromTagContent = "rule-engine/rule-engine-demos-product"; + break; + case NonStandardProductPackageConstants.OPENAI_CONNECTOR: + pathToProductFolderFromTagContent = "openai-connector-product"; + break; + case NonStandardProductPackageConstants.OPENAI_ASSISTANT: + pathToProductFolderFromTagContent = "openai-assistant-product"; + break; + default: + break; } return pathToProductFolderFromTagContent; } public static String getNonStandardImageFolder(String productId) { switch (productId) { - case NonStandardProductPackageConstants.EXCEL_IMPORTER: - pathToImageFolder = "doc"; - break; - case NonStandardProductPackageConstants.EXPRESS_IMPORTER, NonStandardProductPackageConstants.DEEPL_CONNECTOR: - pathToImageFolder = "img"; - break; - case NonStandardProductPackageConstants.GRAPHQL_DEMO: - pathToImageFolder = "assets"; - break; - case NonStandardProductPackageConstants.OPENAI_ASSISTANT: - pathToImageFolder = "docs"; - break; - default: - pathToImageFolder = "images"; - break; + case NonStandardProductPackageConstants.EXCEL_IMPORTER: + pathToImageFolder = "doc"; + break; + case NonStandardProductPackageConstants.EXPRESS_IMPORTER, NonStandardProductPackageConstants.DEEPL_CONNECTOR: + pathToImageFolder = "img"; + break; + case NonStandardProductPackageConstants.GRAPHQL_DEMO: + pathToImageFolder = "assets"; + break; + case NonStandardProductPackageConstants.OPENAI_ASSISTANT: + pathToImageFolder = "docs"; + break; + default: + pathToImageFolder = "images"; + break; } return pathToImageFolder; } diff --git a/marketplace-service/src/main/java/com/axonivy/market/model/DisplayValue.java b/marketplace-service/src/main/java/com/axonivy/market/model/DisplayValue.java index 70d54b588..96236820f 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/model/DisplayValue.java +++ b/marketplace-service/src/main/java/com/axonivy/market/model/DisplayValue.java @@ -17,26 +17,25 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class DisplayValue { - private String locale; - private String value; + private String locale; + private String value; - @Override - public boolean equals(Object obj) { - if (!(obj instanceof DisplayValue)) { - return false; - } - DisplayValue other = (DisplayValue) obj; - EqualsBuilder builder = new EqualsBuilder(); - builder.append(value, other.getValue()); - builder.append(locale, other.locale); - return builder.isEquals(); - } + @Override + public boolean equals(Object obj) { + if (!(obj instanceof DisplayValue other)) { + return false; + } + EqualsBuilder builder = new EqualsBuilder(); + builder.append(value, other.getValue()); + builder.append(locale, other.locale); + return builder.isEquals(); + } - @Override - public int hashCode() { - HashCodeBuilder builder = new HashCodeBuilder(); - builder.append(getValue()); - builder.append(getLocale()); - return builder.hashCode(); - } + @Override + public int hashCode() { + HashCodeBuilder builder = new HashCodeBuilder(); + builder.append(getValue()); + builder.append(getLocale()); + return builder.hashCode(); + } } diff --git a/marketplace-service/src/main/java/com/axonivy/market/model/FeedbackModel.java b/marketplace-service/src/main/java/com/axonivy/market/model/FeedbackModel.java index 5eb1769ce..663fab1dc 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/model/FeedbackModel.java +++ b/marketplace-service/src/main/java/com/axonivy/market/model/FeedbackModel.java @@ -1,6 +1,10 @@ package com.axonivy.market.model; import com.fasterxml.jackson.annotation.JsonInclude; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -17,26 +21,35 @@ @Relation(collectionRelation = "feedbacks", itemRelation = "feedback") @JsonInclude(JsonInclude.Include.NON_NULL) public class FeedbackModel extends RepresentationModel { - private String id; - private String username; - private String userAvatarUrl; - private String userProvider; - private String productId; - private String content; - private Integer rating; - private Date createdAt; - private Date updatedAt; - - @Override - public int hashCode() { - return new HashCodeBuilder().append(id).hashCode(); - } + private String id; + private String userId; + private String username; + private String userAvatarUrl; + private String userProvider; + + @NotBlank(message = "Product id cannot be blank") + private String productId; + + @NotBlank(message = "Content cannot be blank") + @Size(max = 5, message = "Content length must be up to 250 characters") + private String content; + + @Min(value = 1, message = "Rating should not be less than 1") + @Max(value = 5, message = "Rating should not be greater than 5") + private Integer rating; + private Date createdAt; + private Date updatedAt; + + @Override + public int hashCode() { + return new HashCodeBuilder().append(id).hashCode(); + } - @Override - public boolean equals(Object obj) { - if (obj == null || this.getClass() != obj.getClass()) { - return false; - } - return new EqualsBuilder().append(id, ((FeedbackModel) obj).getId()).isEquals(); + @Override + public boolean equals(Object obj) { + if (obj == null || this.getClass() != obj.getClass()) { + return false; } + return new EqualsBuilder().append(id, ((FeedbackModel) obj).getId()).isEquals(); + } } diff --git a/marketplace-service/src/main/java/com/axonivy/market/model/GitHubAccessTokenResponse.java b/marketplace-service/src/main/java/com/axonivy/market/model/GitHubAccessTokenResponse.java new file mode 100644 index 000000000..be3e89bd7 --- /dev/null +++ b/marketplace-service/src/main/java/com/axonivy/market/model/GitHubAccessTokenResponse.java @@ -0,0 +1,22 @@ +package com.axonivy.market.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class GitHubAccessTokenResponse { + @JsonProperty("error") + private String error; + + @JsonProperty("error_description") + private String errorDescription; + + @JsonProperty("access_token") + private String accessToken; +} diff --git a/marketplace-service/src/main/java/com/axonivy/market/model/MavenArtifactVersionModel.java b/marketplace-service/src/main/java/com/axonivy/market/model/MavenArtifactVersionModel.java index 3cb4ee1d7..4acdc23ad 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/model/MavenArtifactVersionModel.java +++ b/marketplace-service/src/main/java/com/axonivy/market/model/MavenArtifactVersionModel.java @@ -13,6 +13,6 @@ @AllArgsConstructor @NoArgsConstructor public class MavenArtifactVersionModel { - private String version; - private List artifactsByVersion; + private String version; + private List artifactsByVersion; } \ No newline at end of file diff --git a/marketplace-service/src/main/java/com/axonivy/market/model/Oauth2AuthorizationCode.java b/marketplace-service/src/main/java/com/axonivy/market/model/Oauth2AuthorizationCode.java index 56706c4c1..b73f8dc66 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/model/Oauth2AuthorizationCode.java +++ b/marketplace-service/src/main/java/com/axonivy/market/model/Oauth2AuthorizationCode.java @@ -8,5 +8,5 @@ @Setter @NoArgsConstructor public class Oauth2AuthorizationCode { - public String code; + private String code; } diff --git a/marketplace-service/src/main/java/com/axonivy/market/model/ProductModel.java b/marketplace-service/src/main/java/com/axonivy/market/model/ProductModel.java index 0984f8765..79ea5b5bf 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/model/ProductModel.java +++ b/marketplace-service/src/main/java/com/axonivy/market/model/ProductModel.java @@ -18,23 +18,23 @@ @Relation(collectionRelation = "products", itemRelation = "product") @JsonInclude(Include.NON_NULL) public class ProductModel extends RepresentationModel { - private String id; - private MultilingualismValue names; - private MultilingualismValue shortDescriptions; - private String logoUrl; - private String type; - private List tags; + private String id; + private MultilingualismValue names; + private MultilingualismValue shortDescriptions; + private String logoUrl; + private String type; + private List tags; - @Override - public int hashCode() { - return new HashCodeBuilder().append(id).hashCode(); - } + @Override + public int hashCode() { + return new HashCodeBuilder().append(id).hashCode(); + } - @Override - public boolean equals(Object obj) { - if (obj == null || this.getClass() != obj.getClass()) { - return false; - } - return new EqualsBuilder().append(id, ((ProductModel) obj).getId()).isEquals(); - } + @Override + public boolean equals(Object obj) { + if (obj == null || this.getClass() != obj.getClass()) { + return false; + } + return new EqualsBuilder().append(id, ((ProductModel) obj).getId()).isEquals(); + } } diff --git a/marketplace-service/src/main/java/com/axonivy/market/repository/UserRepository.java b/marketplace-service/src/main/java/com/axonivy/market/repository/UserRepository.java index 30969ab97..faf1fc553 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/repository/UserRepository.java +++ b/marketplace-service/src/main/java/com/axonivy/market/repository/UserRepository.java @@ -6,5 +6,5 @@ @Repository public interface UserRepository extends MongoRepository { - User searchByGitHubId(String gitHubId); + User searchByGitHubId(String gitHubId); } diff --git a/marketplace-service/src/main/java/com/axonivy/market/schedulingtask/ScheduledTasks.java b/marketplace-service/src/main/java/com/axonivy/market/schedulingtask/ScheduledTasks.java index 5621c2d84..9e21e7453 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/schedulingtask/ScheduledTasks.java +++ b/marketplace-service/src/main/java/com/axonivy/market/schedulingtask/ScheduledTasks.java @@ -11,7 +11,7 @@ public class ScheduledTasks { private static final String SCHEDULING_TASK_PRODUCTS_CRON = "0 0 0/1 ? * *"; - private ProductService productService; + private final ProductService productService; public ScheduledTasks(ProductService productService) { this.productService = productService; diff --git a/marketplace-service/src/main/java/com/axonivy/market/service/FeedbackService.java b/marketplace-service/src/main/java/com/axonivy/market/service/FeedbackService.java index 1e8988f22..b7d1785b5 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/service/FeedbackService.java +++ b/marketplace-service/src/main/java/com/axonivy/market/service/FeedbackService.java @@ -2,6 +2,7 @@ import com.axonivy.market.entity.Feedback; import com.axonivy.market.exceptions.model.NotFoundException; +import com.axonivy.market.model.FeedbackModel; import com.axonivy.market.model.ProductRating; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -10,8 +11,12 @@ public interface FeedbackService { Page findFeedbacks(String productId, Pageable pageable) throws NotFoundException; + Feedback findFeedback(String id) throws NotFoundException; + Feedback findFeedbackByUserIdAndProductId(String userId, String productId) throws NotFoundException; - Feedback upsertFeedback(Feedback feedback) throws NotFoundException; + + Feedback upsertFeedback(FeedbackModel feedback) throws NotFoundException; + List getProductRatingById(String productId); } diff --git a/marketplace-service/src/main/java/com/axonivy/market/service/JwtService.java b/marketplace-service/src/main/java/com/axonivy/market/service/JwtService.java index 49f1c9d44..76f29ca17 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/service/JwtService.java +++ b/marketplace-service/src/main/java/com/axonivy/market/service/JwtService.java @@ -5,6 +5,8 @@ public interface JwtService { String generateToken(User user); + boolean validateToken(String token); + Claims getClaimsFromToken(String token); } diff --git a/marketplace-service/src/main/java/com/axonivy/market/service/UserService.java b/marketplace-service/src/main/java/com/axonivy/market/service/UserService.java index b6c064b4f..d47af915b 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/service/UserService.java +++ b/marketplace-service/src/main/java/com/axonivy/market/service/UserService.java @@ -7,6 +7,8 @@ public interface UserService { List getAllUsers(); + User createUser(User user); + User findUser(String id) throws NotFoundException; } diff --git a/marketplace-service/src/main/java/com/axonivy/market/service/VersionService.java b/marketplace-service/src/main/java/com/axonivy/market/service/VersionService.java index 214e7b669..19755be9c 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/service/VersionService.java +++ b/marketplace-service/src/main/java/com/axonivy/market/service/VersionService.java @@ -6,12 +6,12 @@ public interface VersionService { - List getVersionsToDisplay(Boolean isShowDevVersion, String designerVersion); + List getVersionsToDisplay(Boolean isShowDevVersion, String designerVersion); - List getVersionsFromArtifactDetails(String repoUrl, String groupId, String artifactId); + List getVersionsFromArtifactDetails(String repoUrl, String groupId, String artifactId); - String buildMavenMetadataUrlFromArtifact(String repoUrl, String groupId, String artifactId); + String buildMavenMetadataUrlFromArtifact(String repoUrl, String groupId, String artifactId); - List getArtifactsAndVersionToDisplay(String productId, Boolean isShowDevVersion, - String designerVersion); + List getArtifactsAndVersionToDisplay(String productId, Boolean isShowDevVersion, + String designerVersion); } \ No newline at end of file diff --git a/marketplace-service/src/main/java/com/axonivy/market/service/impl/FeedbackServiceImpl.java b/marketplace-service/src/main/java/com/axonivy/market/service/impl/FeedbackServiceImpl.java index 74ae9a998..4305fe0e8 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/service/impl/FeedbackServiceImpl.java +++ b/marketplace-service/src/main/java/com/axonivy/market/service/impl/FeedbackServiceImpl.java @@ -3,18 +3,16 @@ import com.axonivy.market.entity.Feedback; import com.axonivy.market.enums.ErrorCode; import com.axonivy.market.exceptions.model.NotFoundException; +import com.axonivy.market.model.FeedbackModel; import com.axonivy.market.model.ProductRating; import com.axonivy.market.repository.FeedbackRepository; import com.axonivy.market.repository.ProductRepository; import com.axonivy.market.repository.UserRepository; import com.axonivy.market.service.FeedbackService; -import com.axonivy.market.service.UserService; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -27,7 +25,8 @@ public class FeedbackServiceImpl implements FeedbackService { private final UserRepository userRepository; private final ProductRepository productRepository; - public FeedbackServiceImpl(FeedbackRepository feedbackRepository, UserRepository userRepository, ProductRepository productRepository, UserService userService) { + public FeedbackServiceImpl(FeedbackRepository feedbackRepository, UserRepository userRepository, + ProductRepository productRepository) { this.feedbackRepository = feedbackRepository; this.userRepository = userRepository; this.productRepository = productRepository; @@ -41,30 +40,36 @@ public Page findFeedbacks(String productId, Pageable pageable) throws @Override public Feedback findFeedback(String id) throws NotFoundException { - return feedbackRepository.findById(id).orElseThrow(() -> new NotFoundException(ErrorCode.FEEDBACK_NOT_FOUND, "Not found feedback with id: " + id)); + return feedbackRepository.findById(id) + .orElseThrow(() -> new NotFoundException(ErrorCode.FEEDBACK_NOT_FOUND, "Not found feedback with id: " + id)); } @Override public Feedback findFeedbackByUserIdAndProductId(String userId, String productId) throws NotFoundException { - userRepository.findById(userId) - .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND, "Not found user with id: " + userId)); + validateUserExists(userId); validateProductExists(productId); Feedback existingUserFeedback = feedbackRepository.findByUserIdAndProductId(userId, productId); if (existingUserFeedback == null) { - throw new NotFoundException(ErrorCode.FEEDBACK_NOT_FOUND, String.format("Not found feedback with user id '%s' and product id '%s'", userId, productId)); + throw new NotFoundException(ErrorCode.FEEDBACK_NOT_FOUND, + String.format("Not found feedback with user id '%s' and product id '%s'", userId, productId)); } return existingUserFeedback; } @Override - public Feedback upsertFeedback(Feedback feedback) throws NotFoundException { - userRepository.findById(feedback.getUserId()) - .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND,"Not found user with id: " + feedback.getUserId())); + public Feedback upsertFeedback(FeedbackModel feedback) throws NotFoundException { + validateUserExists(feedback.getUserId()); - Feedback existingUserFeedback = feedbackRepository.findByUserIdAndProductId(feedback.getUserId(), feedback.getProductId()); + Feedback existingUserFeedback = feedbackRepository.findByUserIdAndProductId(feedback.getUserId(), + feedback.getProductId()); if (existingUserFeedback == null) { - return feedbackRepository.save(feedback); + Feedback newFeedback = new Feedback(); + newFeedback.setUserId(feedback.getUserId()); + newFeedback.setProductId(feedback.getProductId()); + newFeedback.setRating(feedback.getRating()); + newFeedback.setContent(feedback.getContent()); + return feedbackRepository.save(newFeedback); } else { existingUserFeedback.setRating(feedback.getRating()); existingUserFeedback.setContent(feedback.getContent()); @@ -78,25 +83,28 @@ public List getProductRatingById(String productId) { int totalFeedbacks = feedbacks.size(); if (totalFeedbacks == 0) { - return IntStream.rangeClosed(1, 5) - .mapToObj(star -> new ProductRating(star, 0, 0)) - .collect(Collectors.toList()); + return IntStream.rangeClosed(1, 5).mapToObj(star -> new ProductRating(star, 0, 0)).toList(); } Map ratingCountMap = feedbacks.stream() .collect(Collectors.groupingBy(Feedback::getRating, Collectors.counting())); - return IntStream.rangeClosed(1, 5) - .mapToObj(star -> { - long count = ratingCountMap.getOrDefault(star, 0L); - int percent = (int) ((count * 100) / totalFeedbacks); - return new ProductRating(star, Math.toIntExact(count), percent); - }) - .collect(Collectors.toList()); + return IntStream.rangeClosed(1, 5).mapToObj(star -> { + long count = ratingCountMap.getOrDefault(star, 0L); + int percent = (int) ((count * 100) / totalFeedbacks); + return new ProductRating(star, Math.toIntExact(count), percent); + }).toList(); } private void validateProductExists(String productId) throws NotFoundException { - productRepository.findById(productId) - .orElseThrow(() -> new NotFoundException(ErrorCode.PRODUCT_NOT_FOUND, "Not found product with id: " + productId)); + if (productRepository.findById(productId).isEmpty()) { + throw new NotFoundException(ErrorCode.PRODUCT_NOT_FOUND, "Not found product with id: " + productId); + } + } + + private void validateUserExists(String userId) { + if (userRepository.findById(userId).isEmpty()) { + throw new NotFoundException(ErrorCode.USER_NOT_FOUND, "Not found user with id: " + userId); + } } } diff --git a/marketplace-service/src/main/java/com/axonivy/market/service/impl/JwtServiceImpl.java b/marketplace-service/src/main/java/com/axonivy/market/service/impl/JwtServiceImpl.java index 979bec72c..45526c950 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/service/impl/JwtServiceImpl.java +++ b/marketplace-service/src/main/java/com/axonivy/market/service/impl/JwtServiceImpl.java @@ -26,13 +26,9 @@ public String generateToken(User user) { Map claims = new HashMap<>(); claims.put("name", user.getName()); claims.put("username", user.getUsername()); - return Jwts.builder() - .setClaims(claims) - .setSubject(user.getId()) - .setIssuedAt(new Date()) + return Jwts.builder().setClaims(claims).setSubject(user.getId()).setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + expiration * 86400000)) - .signWith(SignatureAlgorithm.HS512, secret) - .compact(); + .signWith(SignatureAlgorithm.HS512, secret).compact(); } public boolean validateToken(String token) { diff --git a/marketplace-service/src/main/java/com/axonivy/market/service/impl/ProductServiceImpl.java b/marketplace-service/src/main/java/com/axonivy/market/service/impl/ProductServiceImpl.java index 04de791d5..4a8afd880 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/service/impl/ProductServiceImpl.java +++ b/marketplace-service/src/main/java/com/axonivy/market/service/impl/ProductServiceImpl.java @@ -1,38 +1,5 @@ package com.axonivy.market.service.impl; -import static java.util.Optional.ofNullable; -import static org.apache.commons.lang3.StringUtils.EMPTY; - -import java.io.IOException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Random; - -import com.fasterxml.jackson.core.type.TypeReference; -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.util.Strings; -import org.kohsuke.github.GHCommit; -import org.kohsuke.github.GHContent; -import org.kohsuke.github.GHRepository; -import org.kohsuke.github.GHTag; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Sort.Order; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - import com.axonivy.market.constants.CommonConstants; import com.axonivy.market.constants.GitHubConstants; import com.axonivy.market.entity.GitHubRepoMeta; @@ -50,9 +17,40 @@ import com.axonivy.market.repository.GitHubRepoMetaRepository; import com.axonivy.market.repository.ProductRepository; import com.axonivy.market.service.ProductService; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; - import lombok.extern.log4j.Log4j2; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.util.Strings; +import org.kohsuke.github.GHCommit; +import org.kohsuke.github.GHContent; +import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GHTag; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Order; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Random; + +import static java.util.Optional.ofNullable; +import static org.apache.commons.lang3.StringUtils.EMPTY; @Log4j2 @Service @@ -89,22 +87,22 @@ public Page findProducts(String type, String keyword, String language, final var searchPageable = refinePagination(language, pageable); Page result = Page.empty(); switch (typeOption) { - case ALL: - if (StringUtils.isBlank(keyword)) { - result = productRepository.findAll(searchPageable); - } else { - result = productRepository.searchByNameOrShortDescriptionRegex(keyword, language, searchPageable); - } - break; - case CONNECTORS, UTILITIES, SOLUTIONS: - if (StringUtils.isBlank(keyword)) { - result = productRepository.findByType(typeOption.getCode(), searchPageable); - } else { - result = productRepository.searchByKeywordAndType(keyword, typeOption.getCode(), language, searchPageable); - } - break; - default: - break; + case ALL: + if (StringUtils.isBlank(keyword)) { + result = productRepository.findAll(searchPageable); + } else { + result = productRepository.searchByNameOrShortDescriptionRegex(keyword, language, searchPageable); + } + break; + case CONNECTORS, UTILITIES, SOLUTIONS: + if (StringUtils.isBlank(keyword)) { + result = productRepository.findByType(typeOption.getCode(), searchPageable); + } else { + result = productRepository.searchByKeywordAndType(keyword, typeOption.getCode(), language, searchPageable); + } + break; + default: + break; } return result; } @@ -159,8 +157,8 @@ private void syncRepoMetaDataStatus() { if (lastGHCommit == null) { return; } - String repoURL = - Optional.ofNullable(lastGHCommit.getOwner()).map(GHRepository::getUrl).map(URL::getPath).orElse(EMPTY); + String repoURL = Optional.ofNullable(lastGHCommit.getOwner()).map(GHRepository::getUrl).map(URL::getPath) + .orElse(EMPTY); marketRepoMeta.setRepoURL(repoURL); marketRepoMeta.setRepoName(GitHubConstants.AXONIVY_MARKETPLACE_REPO_NAME); marketRepoMeta.setLastSHA1(lastGHCommit.getSHA1()); @@ -209,34 +207,34 @@ private void updateLatestChangeToProductsFromGithubRepo() { private void modifyProductLogo(String parentPath, GitHubFile file, Product product, GHContent fileContent) { Product result = null; switch (file.getStatus()) { - case MODIFIED, ADDED: - result = productRepository.findByMarketDirectoryRegex(parentPath); - if (result != null) { - result.setLogoUrl(GitHubUtils.getDownloadUrl(fileContent)); - productRepository.save(result); - } - break; - case REMOVED: - result = productRepository.findByLogoUrl(product.getLogoUrl()); - if (result != null) { - productRepository.deleteById(result.getId()); - } - break; - default: - break; + case MODIFIED, ADDED: + result = productRepository.findByMarketDirectoryRegex(parentPath); + if (result != null) { + result.setLogoUrl(GitHubUtils.getDownloadUrl(fileContent)); + productRepository.save(result); + } + break; + case REMOVED: + result = productRepository.findByLogoUrl(product.getLogoUrl()); + if (result != null) { + productRepository.deleteById(result.getId()); + } + break; + default: + break; } } private void modifyProductByMetaContent(GitHubFile file, Product product) { switch (file.getStatus()) { - case MODIFIED, ADDED: - productRepository.save(product); - break; - case REMOVED: - productRepository.deleteById(product.getId()); - break; - default: - break; + case MODIFIED, ADDED: + productRepository.save(product); + break; + case REMOVED: + productRepository.deleteById(product.getId()); + break; + default: + break; } } @@ -256,14 +254,14 @@ private Pageable refinePagination(String language, Pageable pageable) { private boolean isLastGithubCommitCovered() { boolean isLastCommitCovered = false; - long lastCommitTime = 0l; + long lastCommitTime = 0L; marketRepoMeta = gitHubRepoMetaRepository.findByRepoName(GitHubConstants.AXONIVY_MARKETPLACE_REPO_NAME); if (marketRepoMeta != null) { lastCommitTime = marketRepoMeta.getLastChange(); } lastGHCommit = axonIvyMarketRepoService.getLastCommit(lastCommitTime); - if (lastGHCommit != null && marketRepoMeta != null - && StringUtils.equals(lastGHCommit.getSHA1(), marketRepoMeta.getLastSHA1())) { + if (lastGHCommit != null && marketRepoMeta != null && StringUtils.equals(lastGHCommit.getSHA1(), + marketRepoMeta.getLastSHA1())) { isLastCommitCovered = true; } return isLastCommitCovered; @@ -309,8 +307,8 @@ private void updateProductFromReleaseTags(Product product) { List productModuleContents = new ArrayList<>(); for (GHTag ghtag : tags) { - ProductModuleContent productModuleContent = - axonIvyProductRepoService.getReadmeAndProductContentsFromTag(product, productRepo, ghtag.getName()); + ProductModuleContent productModuleContent = axonIvyProductRepoService.getReadmeAndProductContentsFromTag( + product, productRepo, ghtag.getName()); productModuleContents.add(productModuleContent); } product.setProductModuleContents(productModuleContents); diff --git a/marketplace-service/src/main/java/com/axonivy/market/service/impl/UserServiceImpl.java b/marketplace-service/src/main/java/com/axonivy/market/service/impl/UserServiceImpl.java index 750bf3995..0d6c534bb 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/service/impl/UserServiceImpl.java +++ b/marketplace-service/src/main/java/com/axonivy/market/service/impl/UserServiceImpl.java @@ -25,7 +25,8 @@ public List getAllUsers() { @Override public User findUser(String id) throws NotFoundException { - return userRepository.findById(id).orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND, "Not found user with id: " + id)); + return userRepository.findById(id) + .orElseThrow(() -> new NotFoundException(ErrorCode.USER_NOT_FOUND, "Not found user with id: " + id)); } @Override diff --git a/marketplace-service/src/main/java/com/axonivy/market/service/impl/VersionServiceImpl.java b/marketplace-service/src/main/java/com/axonivy/market/service/impl/VersionServiceImpl.java index 06d07123d..80f87948d 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/service/impl/VersionServiceImpl.java +++ b/marketplace-service/src/main/java/com/axonivy/market/service/impl/VersionServiceImpl.java @@ -1,22 +1,22 @@ package com.axonivy.market.service.impl; +import com.axonivy.market.comparator.ArchivedArtifactsComparator; +import com.axonivy.market.comparator.LatestVersionComparator; import com.axonivy.market.constants.CommonConstants; import com.axonivy.market.constants.GitHubConstants; import com.axonivy.market.constants.MavenConstants; import com.axonivy.market.constants.NonStandardProductPackageConstants; +import com.axonivy.market.entity.MavenArtifactModel; import com.axonivy.market.entity.MavenArtifactVersion; import com.axonivy.market.entity.Product; import com.axonivy.market.github.model.ArchivedArtifact; import com.axonivy.market.github.model.MavenArtifact; -import com.axonivy.market.entity.MavenArtifactModel; import com.axonivy.market.github.service.GHAxonIvyProductRepoService; import com.axonivy.market.github.util.GitHubUtils; import com.axonivy.market.model.MavenArtifactVersionModel; import com.axonivy.market.repository.MavenArtifactVersionRepository; import com.axonivy.market.repository.ProductRepository; import com.axonivy.market.service.VersionService; -import com.axonivy.market.comparator.ArchivedArtifactsComparator; -import com.axonivy.market.comparator.LatestVersionComparator; import com.axonivy.market.util.XmlReaderUtils; import lombok.Getter; import lombok.extern.log4j.Log4j2; @@ -27,7 +27,15 @@ import org.springframework.util.CollectionUtils; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.stream.Stream; @Log4j2 @@ -94,8 +102,8 @@ public boolean handleArtifactForVersionToDisplay(List versionsToDisplay, boolean isNewVersionDetected = false; for (String version : versionsToDisplay) { List artifactsInVersion = convertMavenArtifactsToModels(artifactsFromMeta, version); - List productArtifactModels = - proceedDataCache.getProductArtifactWithVersionReleased().get(version); + List productArtifactModels = proceedDataCache.getProductArtifactWithVersionReleased() + .get(version); if (productArtifactModels == null) { isNewVersionDetected = true; productArtifactModels = updateArtifactsInVersionWithProductArtifact(version); @@ -107,8 +115,8 @@ public boolean handleArtifactForVersionToDisplay(List versionsToDisplay, } public List updateArtifactsInVersionWithProductArtifact(String version) { - List productArtifactModels = - convertMavenArtifactsToModels(getProductJsonByVersion(version), version); + List productArtifactModels = convertMavenArtifactsToModels(getProductJsonByVersion(version), + version); proceedDataCache.getVersions().add(version); proceedDataCache.getProductArtifactWithVersionReleased().put(version, productArtifactModels); return productArtifactModels; @@ -126,8 +134,9 @@ public List getProductMetaArtifacts(String productId) { public void sanitizeMetaArtifactBeforeHandle() { artifactsFromMeta.remove(metaProductArtifact); artifactsFromMeta.forEach(artifact -> { - List archivedArtifacts = new ArrayList<>(Optional.ofNullable(artifact.getArchivedArtifacts()) - .orElse(Collections.emptyList()).stream().sorted(new ArchivedArtifactsComparator()).toList()); + List archivedArtifacts = new ArrayList<>( + Optional.ofNullable(artifact.getArchivedArtifacts()).orElse(Collections.emptyList()).stream() + .sorted(new ArchivedArtifactsComparator()).toList()); Collections.reverse(archivedArtifacts); archivedArtifactsMap.put(artifact.getArtifactId(), archivedArtifacts); }); @@ -152,9 +161,10 @@ public List getVersionsFromMavenArtifacts() { for (MavenArtifact artifact : artifactsFromMeta) { versions.addAll( getVersionsFromArtifactDetails(artifact.getRepoUrl(), artifact.getGroupId(), artifact.getArtifactId())); - Optional.ofNullable(artifact.getArchivedArtifacts()).orElse(Collections.emptyList()) - .forEach(archivedArtifact -> versions.addAll(getVersionsFromArtifactDetails(artifact.getRepoUrl(), - archivedArtifact.getGroupId(), archivedArtifact.getArtifactId()))); + Optional.ofNullable(artifact.getArchivedArtifacts()).orElse(Collections.emptyList()).forEach( + archivedArtifact -> versions.addAll( + getVersionsFromArtifactDetails(artifact.getRepoUrl(), archivedArtifact.getGroupId(), + archivedArtifact.getArtifactId()))); } List versionList = new ArrayList<>(versions); versionList.sort(new LatestVersionComparator()); @@ -206,8 +216,9 @@ public boolean isOfficialVersionOrUnReleasedDevVersion(List versions, St } else { bugfixVersion = getBugfixVersion(version.split(MavenConstants.SPRINT_RELEASE_POSTFIX)[0]); } - return versions.stream().noneMatch(currentVersion -> !currentVersion.equals(version) - && isReleasedVersion(currentVersion) && getBugfixVersion(currentVersion).equals(bugfixVersion)); + return versions.stream().noneMatch( + currentVersion -> !currentVersion.equals(version) && isReleasedVersion(currentVersion) && getBugfixVersion( + currentVersion).equals(bugfixVersion)); } public boolean isSnapshotVersion(String version) { @@ -231,8 +242,8 @@ public List getProductJsonByVersion(String version) { String versionTag = getVersionTag(version); productJsonFilePath = buildProductJsonFilePath(); try { - GHContent productJsonContent = - gitHubService.getContentFromGHRepoAndTag(repoName, productJsonFilePath, versionTag); + GHContent productJsonContent = gitHubService.getContentFromGHRepoAndTag(repoName, productJsonFilePath, + versionTag); if (Objects.isNull(productJsonContent)) { return result; } @@ -255,8 +266,8 @@ public String getVersionTag(String version) { public String buildProductJsonFilePath() { String pathToProductFolderFromTagContent = metaProductArtifact.getArtifactId(); GitHubUtils.getNonStandardProductFilePath(productId); - productJsonFilePath = - String.format(GitHubConstants.PRODUCT_JSON_FILE_PATH_FORMAT, pathToProductFolderFromTagContent); + productJsonFilePath = String.format(GitHubConstants.PRODUCT_JSON_FILE_PATH_FORMAT, + pathToProductFolderFromTagContent); return productJsonFilePath; } @@ -286,8 +297,8 @@ public String buildDownloadUrlFromArtifactAndVersion(MavenArtifact artifact, Str String groupIdByVersion = artifact.getGroupId(); String artifactIdByVersion = artifact.getArtifactId(); String repoUrl = Optional.ofNullable(artifact.getRepoUrl()).orElse(MavenConstants.DEFAULT_IVY_MAVEN_BASE_URL); - ArchivedArtifact archivedArtifactBestMatchVersion = - findArchivedArtifactInfoBestMatchWithVersion(artifact.getArtifactId(), version); + ArchivedArtifact archivedArtifactBestMatchVersion = findArchivedArtifactInfoBestMatchWithVersion( + artifact.getArtifactId(), version); if (Objects.nonNull(archivedArtifactBestMatchVersion)) { groupIdByVersion = archivedArtifactBestMatchVersion.getGroupId(); diff --git a/marketplace-service/src/main/java/com/axonivy/market/util/XmlReaderUtils.java b/marketplace-service/src/main/java/com/axonivy/market/util/XmlReaderUtils.java index d49802145..33fe8e20e 100644 --- a/marketplace-service/src/main/java/com/axonivy/market/util/XmlReaderUtils.java +++ b/marketplace-service/src/main/java/com/axonivy/market/util/XmlReaderUtils.java @@ -24,7 +24,8 @@ public class XmlReaderUtils { private static final RestTemplate restTemplate = new RestTemplate(); - private XmlReaderUtils() {} + private XmlReaderUtils() { + } public static List readXMLFromUrl(String url) { List versions = new ArrayList<>(); diff --git a/marketplace-service/src/test/java/com/axonivy/market/controller/FeedbackControllerTest.java b/marketplace-service/src/test/java/com/axonivy/market/controller/FeedbackControllerTest.java index 55817625b..ea02160f9 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/controller/FeedbackControllerTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/controller/FeedbackControllerTest.java @@ -3,6 +3,7 @@ import com.axonivy.market.assembler.FeedbackModelAssembler; import com.axonivy.market.entity.Feedback; import com.axonivy.market.entity.User; +import com.axonivy.market.model.FeedbackModel; import com.axonivy.market.service.FeedbackService; import com.axonivy.market.service.JwtService; import com.axonivy.market.service.UserService; @@ -120,6 +121,7 @@ void testFindFeedbackByUserIdAndProductId() { @Test void testCreateFeedback() { + FeedbackModel mockFeedbackModel = createFeedbackModelMock(); Feedback mockFeedback = createFeedbackMock(); Claims mockClaims = createMockClaims(); MockHttpServletRequest request = new MockHttpServletRequest(); @@ -128,7 +130,7 @@ void testCreateFeedback() { when(jwtService.getClaimsFromToken(TOKEN_SAMPLE)).thenReturn(mockClaims); when(service.upsertFeedback(any())).thenReturn(mockFeedback); - var result = feedbackController.createFeedback(mockFeedback, "Bearer " + TOKEN_SAMPLE); + var result = feedbackController.createFeedback(mockFeedbackModel, "Bearer " + TOKEN_SAMPLE); assertEquals(HttpStatus.CREATED, result.getStatusCode()); assertTrue(result.getHeaders().getLocation().toString().contains(mockFeedback.getId())); } @@ -143,6 +145,16 @@ private Feedback createFeedbackMock() { return mockFeedback; } + private FeedbackModel createFeedbackModelMock() { + FeedbackModel mockFeedback = new FeedbackModel(); + mockFeedback.setId(FEEDBACK_ID_SAMPLE); + mockFeedback.setUserId(USER_ID_SAMPLE); + mockFeedback.setProductId(PRODUCT_ID_SAMPLE); + mockFeedback.setContent("Great product!"); + mockFeedback.setRating(5); + return mockFeedback; + } + private User createUserMock() { User mockUser = new User(); mockUser.setId(USER_ID_SAMPLE); diff --git a/marketplace-service/src/test/java/com/axonivy/market/controller/OAuth2ControllerTest.java b/marketplace-service/src/test/java/com/axonivy/market/controller/OAuth2ControllerTest.java index eff891be0..efcc39756 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/controller/OAuth2ControllerTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/controller/OAuth2ControllerTest.java @@ -2,6 +2,7 @@ import com.axonivy.market.entity.User; import com.axonivy.market.github.service.GitHubService; +import com.axonivy.market.model.GitHubAccessTokenResponse; import com.axonivy.market.model.Oauth2AuthorizationCode; import com.axonivy.market.service.JwtService; import org.junit.jupiter.api.BeforeEach; @@ -44,7 +45,7 @@ void testGitHubLogin() { User user = createUserMock(); String jwtToken = "sampleJwtToken"; - when(gitHubService.getAccessToken(any(), any(), any())).thenReturn(Map.of("access_token", accessToken)); + when(gitHubService.getAccessToken(any(), any(), any())).thenReturn(createGitHubAccessTokenResponseMock()); when(gitHubService.getAndUpdateUser(accessToken)).thenReturn(user); when(jwtService.generateToken(user)).thenReturn(jwtToken); @@ -63,4 +64,10 @@ private User createUserMock() { user.setProvider("github"); return user; } + + private GitHubAccessTokenResponse createGitHubAccessTokenResponseMock() { + GitHubAccessTokenResponse gitHubAccessTokenResponse = new GitHubAccessTokenResponse(); + gitHubAccessTokenResponse.setAccessToken("sampleAccessToken"); + return gitHubAccessTokenResponse; + } } \ No newline at end of file diff --git a/marketplace-service/src/test/java/com/axonivy/market/controller/ProductControllerTest.java b/marketplace-service/src/test/java/com/axonivy/market/controller/ProductControllerTest.java index 0d984281e..079526960 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/controller/ProductControllerTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/controller/ProductControllerTest.java @@ -6,7 +6,6 @@ import com.axonivy.market.enums.SortOption; import com.axonivy.market.enums.TypeOption; import com.axonivy.market.model.MultilingualismValue; -import com.axonivy.market.model.ProductRating; import com.axonivy.market.service.ProductService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -113,12 +112,4 @@ private Product createProductMock() { mockProduct.setTags(List.of("AI")); return mockProduct; } - - private ProductRating createProductRatingMock() { - ProductRating productRatingMock = new ProductRating(); - productRatingMock.setStarRating(1); - productRatingMock.setPercent(10); - productRatingMock.setCommentNumber(5); - return productRatingMock; - } } diff --git a/marketplace-service/src/test/java/com/axonivy/market/controller/ProductDetailsControllerTest.java b/marketplace-service/src/test/java/com/axonivy/market/controller/ProductDetailsControllerTest.java index 0ac125d07..3551a82cf 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/controller/ProductDetailsControllerTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/controller/ProductDetailsControllerTest.java @@ -1,13 +1,12 @@ package com.axonivy.market.controller; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.List; -import java.util.Objects; - +import com.axonivy.market.assembler.ProductDetailModelAssembler; +import com.axonivy.market.entity.Product; +import com.axonivy.market.model.MavenArtifactVersionModel; +import com.axonivy.market.model.MultilingualismValue; +import com.axonivy.market.model.ProductDetailModel; +import com.axonivy.market.service.ProductService; +import com.axonivy.market.service.VersionService; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -18,13 +17,13 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import com.axonivy.market.assembler.ProductDetailModelAssembler; -import com.axonivy.market.entity.Product; -import com.axonivy.market.model.MavenArtifactVersionModel; -import com.axonivy.market.model.MultilingualismValue; -import com.axonivy.market.model.ProductDetailModel; -import com.axonivy.market.service.ProductService; -import com.axonivy.market.service.VersionService; +import java.util.List; +import java.util.Objects; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class ProductDetailsControllerTest { @@ -48,8 +47,8 @@ class ProductDetailsControllerTest { void testProductDetails() { Mockito.when(productService.fetchProductDetail(Mockito.anyString())).thenReturn(mockProduct()); Mockito.when(detailModelAssembler.toModel(mockProduct(), null)).thenReturn(createProductMockWithDetails()); - ResponseEntity mockExpectedResult = - new ResponseEntity<>(createProductMockWithDetails(), HttpStatus.OK); + ResponseEntity mockExpectedResult = new ResponseEntity<>(createProductMockWithDetails(), + HttpStatus.OK); ResponseEntity result = productDetailsController.findProductDetails(DOCKER_CONNECTOR_ID); @@ -64,11 +63,11 @@ void testProductDetails() { void testProductDetailsWithVersion() { Mockito.when(productService.fetchProductDetail(Mockito.anyString())).thenReturn(mockProduct()); Mockito.when(detailModelAssembler.toModel(mockProduct(), TAG)).thenReturn(createProductMockWithDetails()); - ResponseEntity mockExpectedResult = - new ResponseEntity<>(createProductMockWithDetails(), HttpStatus.OK); + ResponseEntity mockExpectedResult = new ResponseEntity<>(createProductMockWithDetails(), + HttpStatus.OK); - ResponseEntity result = - productDetailsController.findProductDetailsByVersion(DOCKER_CONNECTOR_ID, TAG); + ResponseEntity result = productDetailsController.findProductDetailsByVersion( + DOCKER_CONNECTOR_ID, TAG); assertEquals(HttpStatus.OK, result.getStatusCode()); assertEquals(result, mockExpectedResult); @@ -80,10 +79,10 @@ void testProductDetailsWithVersion() { void testFindProductVersionsById() { List models = List.of(new MavenArtifactVersionModel()); Mockito.when( - versionService.getArtifactsAndVersionToDisplay(Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyString())) + versionService.getArtifactsAndVersionToDisplay(Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyString())) .thenReturn(models); - ResponseEntity> result = - productDetailsController.findProductVersionsById("protal", true, "10.0.1"); + ResponseEntity> result = productDetailsController.findProductVersionsById("protal", + true, "10.0.1"); Assertions.assertEquals(HttpStatus.OK, result.getStatusCode()); Assertions.assertEquals(1, Objects.requireNonNull(result.getBody()).size()); Assertions.assertEquals(models, result.getBody()); diff --git a/marketplace-service/src/test/java/com/axonivy/market/factory/ProductFactoryTest.java b/marketplace-service/src/test/java/com/axonivy/market/factory/ProductFactoryTest.java index dd770b752..2446c18c1 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/factory/ProductFactoryTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/factory/ProductFactoryTest.java @@ -1,15 +1,7 @@ package com.axonivy.market.factory; -import static com.axonivy.market.constants.CommonConstants.SLASH; -import static com.axonivy.market.constants.MetaConstants.META_FILE; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.io.InputStream; - +import com.axonivy.market.constants.CommonConstants; +import com.axonivy.market.entity.Product; import com.axonivy.market.github.model.Meta; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -17,13 +9,19 @@ import org.kohsuke.github.GHContent; import org.mockito.junit.jupiter.MockitoExtension; -import com.axonivy.market.constants.CommonConstants; -import com.axonivy.market.entity.Product; +import java.io.IOException; +import java.io.InputStream; + +import static com.axonivy.market.constants.CommonConstants.SLASH; +import static com.axonivy.market.constants.MetaConstants.META_FILE; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class ProductFactoryTest { - private static final String DUMMY_LOGO_URL = - "https://raw.githubusercontent.com/axonivy-market/market/master/market/connector/amazon-comprehend-connector/logo.png"; + private static final String DUMMY_LOGO_URL = "https://raw.githubusercontent.com/axonivy-market/market/master/market/connector/amazon-comprehend-connector/logo.png"; @Test void testMappingByGHContent() throws IOException { diff --git a/marketplace-service/src/test/java/com/axonivy/market/service/FeedbackServiceImplTest.java b/marketplace-service/src/test/java/com/axonivy/market/service/FeedbackServiceImplTest.java index 51a510357..5237742c3 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/service/FeedbackServiceImplTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/service/FeedbackServiceImplTest.java @@ -3,6 +3,7 @@ import com.axonivy.market.entity.Feedback; import com.axonivy.market.entity.User; import com.axonivy.market.exceptions.model.NotFoundException; +import com.axonivy.market.model.FeedbackModel; import com.axonivy.market.model.ProductRating; import com.axonivy.market.repository.FeedbackRepository; import com.axonivy.market.repository.ProductRepository; @@ -20,9 +21,13 @@ import java.util.List; import java.util.Optional; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class FeedbackServiceImplTest { @@ -50,7 +55,9 @@ void testFindFeedbacks_ProductNotFound() { when(productRepository.findById(productId)).thenReturn(Optional.empty()); - assertThrows(NotFoundException.class, () -> feedbackService.findFeedbacks(productId, Pageable.unpaged())); + Pageable unpaged = Pageable.unpaged(); + + assertThrows(NotFoundException.class, () -> feedbackService.findFeedbacks(productId, unpaged)); verify(productRepository, times(1)).findById(productId); verify(feedbackRepository, never()).searchByProductId(any(), any()); @@ -99,7 +106,8 @@ void testFindFeedbackByUserIdAndProductId_UserNotFound() { when(userRepository.findById(nonExistingUserId)).thenReturn(Optional.empty()); // Test and verify exception - assertThrows(NotFoundException.class, () -> feedbackService.findFeedbackByUserIdAndProductId(nonExistingUserId, productId)); + assertThrows(NotFoundException.class, + () -> feedbackService.findFeedbackByUserIdAndProductId(nonExistingUserId, productId)); // Verify interactions verify(userRepository, times(1)).findById(nonExistingUserId); @@ -109,42 +117,54 @@ void testFindFeedbackByUserIdAndProductId_UserNotFound() { @Test void testUpsertFeedback_NewFeedback() throws NotFoundException { // Mock data + FeedbackModel newFeedbackModel = new FeedbackModel(); + newFeedbackModel.setUserId("user123"); + newFeedbackModel.setProductId("product123"); + newFeedbackModel.setContent("Great product!"); + newFeedbackModel.setRating(5); + Feedback newFeedback = new Feedback(); - newFeedback.setUserId("user123"); - newFeedback.setProductId("product123"); - newFeedback.setContent("Great product!"); - newFeedback.setRating(5); + newFeedback.setUserId(newFeedbackModel.getUserId()); + newFeedback.setProductId(newFeedbackModel.getProductId()); + newFeedback.setContent(newFeedbackModel.getContent()); + newFeedback.setRating(newFeedbackModel.getRating()); User u = new User(); - u.setId(newFeedback.getUserId()); - when(userRepository.findById(newFeedback.getUserId())).thenReturn(Optional.of(u)); - when(feedbackRepository.findByUserIdAndProductId(newFeedback.getUserId(), newFeedback.getProductId())).thenReturn(null); - when(feedbackRepository.save(newFeedback)).thenReturn(newFeedback); + u.setId(newFeedbackModel.getUserId()); + when(userRepository.findById(newFeedbackModel.getUserId())).thenReturn(Optional.of(u)); + when(feedbackRepository.findByUserIdAndProductId(newFeedbackModel.getUserId(), + newFeedbackModel.getProductId())).thenReturn(null); + when(feedbackRepository.save(any(Feedback.class))).thenReturn(newFeedback); // Test method - Feedback result = feedbackService.upsertFeedback(newFeedback); + Feedback result = feedbackService.upsertFeedback(newFeedbackModel); // Verify assertEquals(newFeedback, result); - verify(userRepository, times(1)).findById(newFeedback.getUserId()); - verify(feedbackRepository, times(1)).findByUserIdAndProductId(newFeedback.getUserId(), newFeedback.getProductId()); - verify(feedbackRepository, times(1)).save(newFeedback); } @Test void testUpsertFeedback_UpdateFeedback() throws NotFoundException { // Mock data + FeedbackModel existingFeedbackModel = new FeedbackModel(); + existingFeedbackModel.setId("existingFeedback123"); + existingFeedbackModel.setUserId("user123"); + existingFeedbackModel.setProductId("product123"); + existingFeedbackModel.setContent("Good product! Very well!"); + existingFeedbackModel.setRating(5); + Feedback existingFeedback = new Feedback(); existingFeedback.setId("existingFeedback123"); existingFeedback.setUserId("user123"); existingFeedback.setProductId("product123"); - existingFeedback.setContent("Good product!"); - existingFeedback.setRating(4); + existingFeedback.setContent("Bad product!"); + existingFeedback.setRating(1); User u = new User(); u.setId(existingFeedback.getUserId()); when(userRepository.findById(existingFeedback.getUserId())).thenReturn(Optional.of(u)); - when(feedbackRepository.findByUserIdAndProductId(existingFeedback.getUserId(), existingFeedback.getProductId())).thenReturn(existingFeedback); + when(feedbackRepository.findByUserIdAndProductId(existingFeedback.getUserId(), + existingFeedback.getProductId())).thenReturn(existingFeedback); when(feedbackRepository.save(existingFeedback)).thenReturn(existingFeedback); // Test method @@ -152,17 +172,18 @@ void testUpsertFeedback_UpdateFeedback() throws NotFoundException { updatedFeedback.setId(existingFeedback.getId()); updatedFeedback.setUserId(existingFeedback.getUserId()); updatedFeedback.setProductId(existingFeedback.getProductId()); - updatedFeedback.setContent("Excellent product!"); + updatedFeedback.setContent("Good product! Very well!"); updatedFeedback.setRating(5); - Feedback result = feedbackService.upsertFeedback(updatedFeedback); + Feedback result = feedbackService.upsertFeedback(existingFeedbackModel); // Verify assertEquals(updatedFeedback.getId(), result.getId()); assertEquals(updatedFeedback.getContent(), result.getContent()); assertEquals(updatedFeedback.getRating(), result.getRating()); verify(userRepository, times(1)).findById(existingFeedback.getUserId()); - verify(feedbackRepository, times(1)).findByUserIdAndProductId(existingFeedback.getUserId(), existingFeedback.getProductId()); + verify(feedbackRepository, times(1)).findByUserIdAndProductId(existingFeedback.getUserId(), + existingFeedback.getProductId()); verify(feedbackRepository, times(1)).save(existingFeedback); } diff --git a/marketplace-service/src/test/java/com/axonivy/market/service/GHAxonIvyMarketRepoServiceImplTest.java b/marketplace-service/src/test/java/com/axonivy/market/service/GHAxonIvyMarketRepoServiceImplTest.java index 0e1f06f4b..5eda06723 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/service/GHAxonIvyMarketRepoServiceImplTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/service/GHAxonIvyMarketRepoServiceImplTest.java @@ -6,8 +6,12 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.kohsuke.github.GHCommit.File; -import org.kohsuke.github.*; +import org.kohsuke.github.GHCompare; import org.kohsuke.github.GHCompare.Commit; +import org.kohsuke.github.GHContent; +import org.kohsuke.github.GHOrganization; +import org.kohsuke.github.GHRepository; +import org.kohsuke.github.PagedIterable; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; diff --git a/marketplace-service/src/test/java/com/axonivy/market/service/GHAxonIvyProductRepoServiceImplTest.java b/marketplace-service/src/test/java/com/axonivy/market/service/GHAxonIvyProductRepoServiceImplTest.java index fa0104d4a..1c7bdf164 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/service/GHAxonIvyProductRepoServiceImplTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/service/GHAxonIvyProductRepoServiceImplTest.java @@ -11,7 +11,11 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.kohsuke.github.*; +import org.kohsuke.github.GHContent; +import org.kohsuke.github.GHOrganization; +import org.kohsuke.github.GHRepository; +import org.kohsuke.github.GHTag; +import org.kohsuke.github.PagedIterable; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; @@ -26,9 +30,14 @@ import java.util.Iterator; import java.util.List; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class GHAxonIvyProductRepoServiceImplTest { @@ -104,8 +113,8 @@ void testExtractMavenArtifactFromJsonNode() { createListNodeForDataNoteByName(nodeName); MavenArtifact mockArtifact = Mockito.mock(MavenArtifact.class); - Mockito.doReturn(mockArtifact).when(axonivyProductRepoServiceImpl).createArtifactFromJsonNode(childNode, null, - isDependency); + Mockito.doReturn(mockArtifact).when(axonivyProductRepoServiceImpl) + .createArtifactFromJsonNode(childNode, null, isDependency); axonivyProductRepoServiceImpl.extractMavenArtifactFromJsonNode(dataNode, isDependency, artifacts); @@ -116,8 +125,8 @@ void testExtractMavenArtifactFromJsonNode() { nodeName = ProductJsonConstants.PROJECTS; createListNodeForDataNoteByName(nodeName); - Mockito.doReturn(mockArtifact).when(axonivyProductRepoServiceImpl).createArtifactFromJsonNode(childNode, null, - isDependency); + Mockito.doReturn(mockArtifact).when(axonivyProductRepoServiceImpl) + .createArtifactFromJsonNode(childNode, null, isDependency); axonivyProductRepoServiceImpl.extractMavenArtifactFromJsonNode(dataNode, isDependency, artifacts); @@ -190,8 +199,7 @@ void testGetOrganization() throws IOException { @Test void testGetReadmeAndProductContentsFromTag() throws IOException { - String readmeContentWithImage = - "#Product-name\n Test README\n## Demo\nDemo content\n## Setup\nSetup content (image.png)"; + String readmeContentWithImage = "#Product-name\n Test README\n## Demo\nDemo content\n## Setup\nSetup content (image.png)"; GHContent mockContent = createMockProductFolderWithProductJson(); @@ -213,8 +221,7 @@ void testGetReadmeAndProductContentsFromTag() throws IOException { @Test void testGetReadmeAndProductContentFromTag_ImageFromFolder() throws IOException { - String readmeContentWithImageFolder = - "#Product-name\n Test README\n## Demo\nDemo content\n## Setup\nSetup content (./images/image.png)"; + String readmeContentWithImageFolder = "#Product-name\n Test README\n## Demo\nDemo content\n## Setup\nSetup content (./images/image.png)"; GHContent mockImageFile = mock(GHContent.class); when(mockImageFile.getName()).thenReturn(ReadmeConstants.IMAGES, IMAGE_NAME); @@ -324,9 +331,10 @@ private static InputStream getMockInputStream() { } private static InputStream getMockInputStreamWithOutProjectAndDependency() { - String jsonContent = "{\n" + " \"installers\": [\n" + " {\n" + " \"data\": {\n" - + " \"repositories\": [\n" + " {\n" + " \"url\": \"http://example.com/repo\"\n" - + " }\n" + " ]\n" + " }\n" + " }\n" + " ]\n" + "}"; + String jsonContent = + "{\n" + " \"installers\": [\n" + " {\n" + " \"data\": {\n" + " \"repositories\": [\n" + + " {\n" + " \"url\": \"http://example.com/repo\"\n" + " }\n" + " ]\n" + + " }\n" + " }\n" + " ]\n" + "}"; return new ByteArrayInputStream(jsonContent.getBytes(StandardCharsets.UTF_8)); } @@ -357,10 +365,10 @@ private GHContent createMockProductFolderWithProductJson() throws IOException { GHContent mockContent2 = createMockProductJson(); - when(ghRepository.getDirectoryContent(CommonConstants.SLASH, RELEASE_TAG)) - .thenReturn(List.of(mockContent, mockContent2)); - when(ghRepository.getDirectoryContent(DOCUWARE_CONNECTOR_PRODUCT, RELEASE_TAG)) - .thenReturn(List.of(mockContent, mockContent2)); + when(ghRepository.getDirectoryContent(CommonConstants.SLASH, RELEASE_TAG)).thenReturn( + List.of(mockContent, mockContent2)); + when(ghRepository.getDirectoryContent(DOCUWARE_CONNECTOR_PRODUCT, RELEASE_TAG)).thenReturn( + List.of(mockContent, mockContent2)); return mockContent; } diff --git a/marketplace-service/src/test/java/com/axonivy/market/service/GitHubServiceImplTest.java b/marketplace-service/src/test/java/com/axonivy/market/service/GitHubServiceImplTest.java index bbd8416fa..c4e0c07ea 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/service/GitHubServiceImplTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/service/GitHubServiceImplTest.java @@ -19,7 +19,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class GitHubServiceImplTest { diff --git a/marketplace-service/src/test/java/com/axonivy/market/service/JwtServiceImplTest.java b/marketplace-service/src/test/java/com/axonivy/market/service/JwtServiceImplTest.java index 4eb8ffcec..d5c2b7457 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/service/JwtServiceImplTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/service/JwtServiceImplTest.java @@ -11,84 +11,87 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; @ExtendWith(MockitoExtension.class) class JwtServiceImplTest { - private static final String SECRET = "mySecret"; - private static final long EXPIRATION = 7L; // 7 days - - @InjectMocks - private JwtServiceImpl jwtService; - - @BeforeEach - void setUp() { - ReflectionTestUtils.setField(jwtService, "secret", SECRET); - ReflectionTestUtils.setField(jwtService, "expiration", EXPIRATION); - } - - @Test - void testGenerateToken() { - User user = new User(); - user.setId("123"); - user.setName("John Doe"); - user.setUsername("johndoe"); - - String token = jwtService.generateToken(user); - - assertNotNull(token); - assertFalse(token.isEmpty()); - - Claims claims = jwtService.getClaimsFromToken(token); - assertEquals("123", claims.getSubject()); - assertEquals("John Doe", claims.get("name")); - assertEquals("johndoe", claims.get("username")); - } - - @Test - void testValidateToken() { - User user = new User(); - user.setId("123"); - user.setName("John Doe"); - user.setUsername("johndoe"); - - String validToken = jwtService.generateToken(user); - assertTrue(jwtService.validateToken(validToken)); - - String invalidToken = "invalid.token.here"; - assertFalse(jwtService.validateToken(invalidToken)); - } - - @Test - void testGetClaimsFromToken() { - User user = new User(); - user.setId("123"); - user.setName("John Doe"); - user.setUsername("johndoe"); - - String token = jwtService.generateToken(user); - - Claims claims = jwtService.getClaimsFromToken(token); - assertNotNull(claims); - assertEquals("123", claims.getSubject()); - assertEquals("John Doe", claims.get("name")); - assertEquals("johndoe", claims.get("username")); - } - - @Test - void testGetClaimsJws() { - User user = new User(); - user.setId("123"); - user.setName("John Doe"); - user.setUsername("johndoe"); - - String token = jwtService.generateToken(user); - - Jws claimsJws = jwtService.getClaimsJws(token); - assertNotNull(claimsJws); - assertNotNull(claimsJws.getBody()); - assertEquals("123", claimsJws.getBody().getSubject()); - } + private static final String SECRET = "mySecret"; + private static final long EXPIRATION = 7L; // 7 days + + @InjectMocks + private JwtServiceImpl jwtService; + + @BeforeEach + void setUp() { + ReflectionTestUtils.setField(jwtService, "secret", SECRET); + ReflectionTestUtils.setField(jwtService, "expiration", EXPIRATION); + } + + @Test + void testGenerateToken() { + User user = new User(); + user.setId("123"); + user.setName("John Doe"); + user.setUsername("johndoe"); + + String token = jwtService.generateToken(user); + + assertNotNull(token); + assertFalse(token.isEmpty()); + + Claims claims = jwtService.getClaimsFromToken(token); + assertEquals("123", claims.getSubject()); + assertEquals("John Doe", claims.get("name")); + assertEquals("johndoe", claims.get("username")); + } + + @Test + void testValidateToken() { + User user = new User(); + user.setId("123"); + user.setName("John Doe"); + user.setUsername("johndoe"); + + String validToken = jwtService.generateToken(user); + assertTrue(jwtService.validateToken(validToken)); + + String invalidToken = "invalid.token.here"; + assertFalse(jwtService.validateToken(invalidToken)); + } + + @Test + void testGetClaimsFromToken() { + User user = new User(); + user.setId("123"); + user.setName("John Doe"); + user.setUsername("johndoe"); + + String token = jwtService.generateToken(user); + + Claims claims = jwtService.getClaimsFromToken(token); + assertNotNull(claims); + assertEquals("123", claims.getSubject()); + assertEquals("John Doe", claims.get("name")); + assertEquals("johndoe", claims.get("username")); + } + + @Test + void testGetClaimsJws() { + User user = new User(); + user.setId("123"); + user.setName("John Doe"); + user.setUsername("johndoe"); + + String token = jwtService.generateToken(user); + + Jws claimsJws = jwtService.getClaimsJws(token); + assertNotNull(claimsJws); + assertNotNull(claimsJws.getBody()); + assertEquals("123", claimsJws.getBody().getSubject()); + } } diff --git a/marketplace-service/src/test/java/com/axonivy/market/service/ProductServiceImplTest.java b/marketplace-service/src/test/java/com/axonivy/market/service/ProductServiceImplTest.java index 841cfc7f5..aa02a2c9f 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/service/ProductServiceImplTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/service/ProductServiceImplTest.java @@ -1,33 +1,21 @@ package com.axonivy.market.service; -import static com.axonivy.market.constants.CommonConstants.LOGO_FILE; -import static com.axonivy.market.constants.CommonConstants.SLASH; -import static com.axonivy.market.constants.MetaConstants.META_FILE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; -import java.util.stream.Collectors; - +import com.axonivy.market.constants.GitHubConstants; +import com.axonivy.market.entity.GitHubRepoMeta; +import com.axonivy.market.entity.Product; +import com.axonivy.market.entity.ProductModuleContent; +import com.axonivy.market.enums.FileStatus; +import com.axonivy.market.enums.FileType; +import com.axonivy.market.enums.SortOption; +import com.axonivy.market.enums.TypeOption; +import com.axonivy.market.github.model.GitHubFile; +import com.axonivy.market.github.service.GHAxonIvyMarketRepoService; +import com.axonivy.market.github.service.GHAxonIvyProductRepoService; +import com.axonivy.market.github.service.GitHubService; +import com.axonivy.market.model.MultilingualismValue; +import com.axonivy.market.repository.GitHubRepoMetaRepository; +import com.axonivy.market.repository.ProductRepository; +import com.axonivy.market.service.impl.ProductServiceImpl; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -50,22 +38,33 @@ import org.springframework.data.domain.Sort; import org.springframework.test.util.ReflectionTestUtils; -import com.axonivy.market.constants.GitHubConstants; -import com.axonivy.market.entity.GitHubRepoMeta; -import com.axonivy.market.entity.Product; -import com.axonivy.market.entity.ProductModuleContent; -import com.axonivy.market.enums.FileStatus; -import com.axonivy.market.enums.FileType; -import com.axonivy.market.enums.SortOption; -import com.axonivy.market.enums.TypeOption; -import com.axonivy.market.github.model.GitHubFile; -import com.axonivy.market.github.service.GHAxonIvyMarketRepoService; -import com.axonivy.market.github.service.GHAxonIvyProductRepoService; -import com.axonivy.market.github.service.GitHubService; -import com.axonivy.market.model.MultilingualismValue; -import com.axonivy.market.repository.GitHubRepoMetaRepository; -import com.axonivy.market.repository.ProductRepository; -import com.axonivy.market.service.impl.ProductServiceImpl; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +import static com.axonivy.market.constants.CommonConstants.LOGO_FILE; +import static com.axonivy.market.constants.CommonConstants.SLASH; +import static com.axonivy.market.constants.MetaConstants.META_FILE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class ProductServiceImplTest { @@ -73,8 +72,8 @@ class ProductServiceImplTest { private static final String SAMPLE_PRODUCT_ID = "amazon-comprehend"; private static final String SAMPLE_PRODUCT_NAME = "Amazon Comprehend"; private static final long LAST_CHANGE_TIME = 1718096290000l; - private static final Pageable PAGEABLE = - PageRequest.of(0, 20, Sort.by(SortOption.ALPHABETICALLY.getOption()).descending()); + private static final Pageable PAGEABLE = PageRequest.of(0, 20, + Sort.by(SortOption.ALPHABETICALLY.getOption()).descending()); private static final String SHA1_SAMPLE = "35baa89091b2452b77705da227f1a964ecabc6c8"; public static final String RELEASE_TAG = "v10.0.2"; private String keyword; @@ -250,9 +249,10 @@ void testFindAllProductsWithKeyword() throws IOException { verify(productRepository).findAll(any(Pageable.class)); // Test has keyword - when(productRepository.searchByNameOrShortDescriptionRegex(any(), any(), any(Pageable.class))) - .thenReturn(new PageImpl<>(mockResultReturn.stream() - .filter(product -> product.getNames().getEn().equals(SAMPLE_PRODUCT_NAME)).collect(Collectors.toList()))); + when(productRepository.searchByNameOrShortDescriptionRegex(any(), any(), any(Pageable.class))).thenReturn( + new PageImpl<>( + mockResultReturn.stream().filter(product -> product.getNames().getEn().equals(SAMPLE_PRODUCT_NAME)) + .collect(Collectors.toList()))); // Executes result = productService.findProducts(TypeOption.ALL.getOption(), SAMPLE_PRODUCT_NAME, langague, PAGEABLE); verify(productRepository).findAll(any(Pageable.class)); @@ -260,14 +260,10 @@ void testFindAllProductsWithKeyword() throws IOException { assertEquals(SAMPLE_PRODUCT_NAME, result.getContent().get(0).getNames().getEn()); // Test has keyword and type is connector - when( - productRepository.searchByKeywordAndType(any(), any(), any(), any(Pageable.class))) - .thenReturn( - new PageImpl<>( - mockResultReturn.stream() - .filter(product -> product.getNames().getEn().equals(SAMPLE_PRODUCT_NAME) - && product.getType().equals(TypeOption.CONNECTORS.getCode())) - .collect(Collectors.toList()))); + when(productRepository.searchByKeywordAndType(any(), any(), any(), any(Pageable.class))).thenReturn(new PageImpl<>( + mockResultReturn.stream().filter( + product -> product.getNames().getEn().equals(SAMPLE_PRODUCT_NAME) && product.getType() + .equals(TypeOption.CONNECTORS.getCode())).collect(Collectors.toList()))); // Executes result = productService.findProducts(TypeOption.CONNECTORS.getOption(), SAMPLE_PRODUCT_NAME, langague, PAGEABLE); assertTrue(result.hasContent()); @@ -279,8 +275,8 @@ void testSyncProductsFirstTime() throws IOException { var mockCommit = mockGHCommitHasSHA1(SHA1_SAMPLE); when(marketRepoService.getLastCommit(anyLong())).thenReturn(mockCommit); when(repoMetaRepository.findByRepoName(anyString())).thenReturn(null); - when(ghAxonIvyProductRepoService.getReadmeAndProductContentsFromTag(any(), any(), anyString())) - .thenReturn(mockReadmeProductContent()); + when(ghAxonIvyProductRepoService.getReadmeAndProductContentsFromTag(any(), any(), anyString())).thenReturn( + mockReadmeProductContent()); when(gitHubService.getRepository(any())).thenReturn(ghRepository); PagedIterable pagedIterable = mock(PagedIterable.class); when(ghRepository.listTags()).thenReturn(pagedIterable); @@ -330,8 +326,8 @@ void testSearchProducts() { String type = TypeOption.ALL.getOption(); keyword = "on"; langague = "en"; - when(productRepository.searchByNameOrShortDescriptionRegex(keyword, langague, simplePageable)) - .thenReturn(mockResultReturn); + when(productRepository.searchByNameOrShortDescriptionRegex(keyword, langague, simplePageable)).thenReturn( + mockResultReturn); var result = productService.findProducts(type, keyword, langague, simplePageable); assertEquals(result, mockResultReturn); diff --git a/marketplace-service/src/test/java/com/axonivy/market/service/SchedulingTasksTest.java b/marketplace-service/src/test/java/com/axonivy/market/service/SchedulingTasksTest.java index 70e4d0771..bdc720dfc 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/service/SchedulingTasksTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/service/SchedulingTasksTest.java @@ -10,7 +10,7 @@ import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.verify; -@SpringBootTest(properties = { "marketPlace-installation-url=D:/marketplace-installation.json" }) +@SpringBootTest(properties = { "MARKETPLACE_INSTALLATION_URL=D:/marketplace-installation.json" }) class SchedulingTasksTest { @SpyBean diff --git a/marketplace-service/src/test/java/com/axonivy/market/service/VersionServiceImplTest.java b/marketplace-service/src/test/java/com/axonivy/market/service/VersionServiceImplTest.java index ce3ef83ee..60ffb9248 100644 --- a/marketplace-service/src/test/java/com/axonivy/market/service/VersionServiceImplTest.java +++ b/marketplace-service/src/test/java/com/axonivy/market/service/VersionServiceImplTest.java @@ -19,16 +19,24 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.kohsuke.github.GHContent; -import org.mockito.*; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class VersionServiceImplTest { @@ -81,13 +89,13 @@ void testGetArtifactsAndVersionToDisplay() { String targetVersion = "10.0.10"; setUpArtifactFromMeta(); when(versionService.getProductMetaArtifacts(Mockito.anyString())).thenReturn(artifactsFromMeta); - when(versionService.getVersionsToDisplay(Mockito.anyBoolean(), Mockito.anyString())) - .thenReturn(List.of(targetVersion)); + when(versionService.getVersionsToDisplay(Mockito.anyBoolean(), Mockito.anyString())).thenReturn( + List.of(targetVersion)); when(mavenArtifactVersionRepository.findById(Mockito.anyString())).thenReturn(Optional.empty()); ArrayList artifactsInVersion = new ArrayList<>(); artifactsInVersion.add(new MavenArtifactModel()); - when(versionService.convertMavenArtifactsToModels(Mockito.anyList(), Mockito.anyString())) - .thenReturn(artifactsInVersion); + when(versionService.convertMavenArtifactsToModels(Mockito.anyList(), Mockito.anyString())).thenReturn( + artifactsInVersion); Assertions.assertEquals(1, versionService.getArtifactsAndVersionToDisplay(productId, false, targetVersion).size()); MavenArtifactVersion proceededData = new MavenArtifactVersion(); @@ -110,8 +118,8 @@ void testHandleArtifactForVersionToDisplay() { result = new ArrayList<>(); ArrayList artifactsInVersion = new ArrayList<>(); artifactsInVersion.add(new MavenArtifactModel()); - when(versionService.convertMavenArtifactsToModels(Mockito.anyList(), Mockito.anyString())) - .thenReturn(artifactsInVersion); + when(versionService.convertMavenArtifactsToModels(Mockito.anyList(), Mockito.anyString())).thenReturn( + artifactsInVersion); Assertions.assertFalse(versionService.handleArtifactForVersionToDisplay(versionsToDisplay, result)); Assertions.assertEquals(1, result.size()); Assertions.assertEquals(1, result.get(0).getArtifactsByVersion().size()); @@ -141,8 +149,8 @@ void testUpdateArtifactsInVersionWithProductArtifact() { MavenArtifactModel artifactModel = new MavenArtifactModel(); List mockMavenArtifactModels = List.of(artifactModel); when(versionService.getProductJsonByVersion(Mockito.anyString())).thenReturn(List.of(new MavenArtifact())); - when(versionService.convertMavenArtifactsToModels(Mockito.anyList(), Mockito.anyString())) - .thenReturn(mockMavenArtifactModels); + when(versionService.convertMavenArtifactsToModels(Mockito.anyList(), Mockito.anyString())).thenReturn( + mockMavenArtifactModels); Assertions.assertEquals(mockMavenArtifactModels, versionService.updateArtifactsInVersionWithProductArtifact(version)); Assertions.assertEquals(1, proceedDataCache.getVersions().size()); @@ -208,8 +216,8 @@ void getVersionsFromMavenArtifacts() { versionFromArchivedArtifact.add("10.0.2"); versionFromArchivedArtifact.add("10.0.1"); artifactsFromMeta.get(0).setArchivedArtifacts(archivedArtifacts); - when(versionService.getVersionsFromArtifactDetails(repoUrl, groupId, archivedArtifactId)) - .thenReturn(versionFromArchivedArtifact); + when(versionService.getVersionsFromArtifactDetails(repoUrl, groupId, archivedArtifactId)).thenReturn( + versionFromArchivedArtifact); versionFromArtifact.addAll(versionFromArchivedArtifact); Assertions.assertEquals(versionService.getVersionsFromMavenArtifacts(), versionFromArtifact); } @@ -230,10 +238,10 @@ void testGetVersionsFromArtifactDetails() { try (MockedStatic xmlUtils = Mockito.mockStatic(XmlReaderUtils.class)) { xmlUtils.when(() -> XmlReaderUtils.readXMLFromUrl(Mockito.anyString())).thenReturn(versionFromArtifact); + Assertions.assertEquals(versionService.getVersionsFromArtifactDetails(repoUrl, null, null), new ArrayList<>()); + Assertions.assertEquals(versionService.getVersionsFromArtifactDetails(repoUrl, groupId, artifactId), + versionFromArtifact); } - Assertions.assertEquals(versionService.getVersionsFromArtifactDetails(repoUrl, null, null), new ArrayList<>()); - Assertions.assertEquals(versionService.getVersionsFromArtifactDetails(repoUrl, groupId, artifactId), - versionFromArtifact); } @Test @@ -241,8 +249,7 @@ void testBuildMavenMetadataUrlFromArtifact() { String repoUrl = "https://maven.axonivy.com"; String groupId = "com.axonivy.connector.adobe.acrobat.sign"; String artifactId = "adobe-acrobat-sign-connector"; - String metadataUrl = - "https://maven.axonivy.com/com/axonivy/connector/adobe/acrobat/sign/adobe-acrobat-sign-connector/maven-metadata.xml"; + String metadataUrl = "https://maven.axonivy.com/com/axonivy/connector/adobe/acrobat/sign/adobe-acrobat-sign-connector/maven-metadata.xml"; Assertions.assertEquals(StringUtils.EMPTY, versionService.buildMavenMetadataUrlFromArtifact(repoUrl, null, artifactId)); Assertions.assertEquals(StringUtils.EMPTY, versionService.buildMavenMetadataUrlFromArtifact(repoUrl, groupId, null), @@ -335,26 +342,26 @@ void testGetProductJsonByVersion() { repoName = "adobe-acrobat-sign-connector"; ReflectionTestUtils.setField(versionService, "repoName", repoName); ReflectionTestUtils.setField(versionService, "productId", "adobe-acrobat-connector"); - MavenArtifact productArtifact = - new MavenArtifact("https://maven.axonivy.com", null, targetGroupId, targetArtifactId, "iar", null, true, null); + MavenArtifact productArtifact = new MavenArtifact("https://maven.axonivy.com", null, targetGroupId, + targetArtifactId, "iar", null, true, null); metaProductArtifact.setRepoUrl("https://maven.axonivy.com"); metaProductArtifact.setGroupId(targetGroupId); metaProductArtifact.setArtifactId(targetArtifactId); - when(gitHubService.getContentFromGHRepoAndTag(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) - .thenReturn(null); + when(gitHubService.getContentFromGHRepoAndTag(Mockito.anyString(), Mockito.anyString(), + Mockito.anyString())).thenReturn(null); Assertions.assertEquals(0, versionService.getProductJsonByVersion("10.0.20").size()); metaProductArtifact.setGroupId("com.axonivy.connector.adobe.acrobat.connector"); - when(gitHubService.getContentFromGHRepoAndTag(Mockito.anyString(), Mockito.anyString(), Mockito.anyString())) - .thenReturn(mockContent); + when(gitHubService.getContentFromGHRepoAndTag(Mockito.anyString(), Mockito.anyString(), + Mockito.anyString())).thenReturn(mockContent); try { when(gitHubService.convertProductJsonToMavenProductInfo(mockContent)).thenReturn(List.of(productArtifact)); Assertions.assertEquals(1, versionService.getProductJsonByVersion("10.0.20").size()); - when(gitHubService.convertProductJsonToMavenProductInfo(mockContent)) - .thenThrow(new IOException("Mock IO Exception")); + when(gitHubService.convertProductJsonToMavenProductInfo(mockContent)).thenThrow( + new IOException("Mock IO Exception")); Assertions.assertEquals(0, versionService.getProductJsonByVersion("10.0.20").size()); } catch (IOException e) { Fail.fail("Mock setup should not throw an exception"); @@ -363,8 +370,7 @@ void testGetProductJsonByVersion() { @Test void testConvertMavenArtifactToModel() { - String downloadUrl = - "https://maven.axonivy.com/com/axonivy/connector/adobe/acrobat/sign/adobe-acrobat-sign-connector/10.0.21/adobe-acrobat-sign-connector-10.0.21.iar"; + String downloadUrl = "https://maven.axonivy.com/com/axonivy/connector/adobe/acrobat/sign/adobe-acrobat-sign-connector/10.0.21/adobe-acrobat-sign-connector-10.0.21.iar"; String artifactName = "Adobe Acrobat Sign Connector (iar)"; MavenArtifact targetArtifact = new MavenArtifact(null, null, "com.axonivy.connector.adobe.acrobat.sign", @@ -408,22 +414,22 @@ void testBuildDownloadUrlFromArtifactAndVersion() { // Set up artifact for testing String targetArtifactId = "adobe-acrobat-sign-connector"; String targetGroupId = "com.axonivy.connector"; - MavenArtifact targetArtifact = - new MavenArtifact(null, null, targetGroupId, targetArtifactId, "iar", null, null, null); + MavenArtifact targetArtifact = new MavenArtifact(null, null, targetGroupId, targetArtifactId, "iar", null, null, + null); String targetVersion = "10.0.10"; // Assert case without archived artifact - String expectedResult = - String.format(MavenConstants.ARTIFACT_DOWNLOAD_URL_FORMAT, MavenConstants.DEFAULT_IVY_MAVEN_BASE_URL, - "com/axonivy/connector", targetArtifactId, targetVersion, targetArtifactId, targetVersion, "iar"); + String expectedResult = String.format(MavenConstants.ARTIFACT_DOWNLOAD_URL_FORMAT, + MavenConstants.DEFAULT_IVY_MAVEN_BASE_URL, "com/axonivy/connector", targetArtifactId, targetVersion, + targetArtifactId, targetVersion, "iar"); String result = versionService.buildDownloadUrlFromArtifactAndVersion(targetArtifact, targetVersion); Assertions.assertEquals(expectedResult, result); // Assert case with artifact not match & use custom repo - ArchivedArtifact adobeArchivedArtifactVersion9 = - new ArchivedArtifact("10.0.9", "com.axonivy.adobe.connector", "adobe-connector"); - ArchivedArtifact adobeArchivedArtifactVersion8 = - new ArchivedArtifact("10.0.8", "com.axonivy.adobe.sign.connector", "adobe-sign-connector"); + ArchivedArtifact adobeArchivedArtifactVersion9 = new ArchivedArtifact("10.0.9", "com.axonivy.adobe.connector", + "adobe-connector"); + ArchivedArtifact adobeArchivedArtifactVersion8 = new ArchivedArtifact("10.0.8", "com.axonivy.adobe.sign.connector", + "adobe-sign-connector"); archivedArtifactsMap.put(targetArtifactId, List.of(adobeArchivedArtifactVersion9, adobeArchivedArtifactVersion8)); String customRepoUrl = "https://nexus.axonivy.com"; targetArtifact.setRepoUrl(customRepoUrl); @@ -447,16 +453,16 @@ void testBuildDownloadUrlFromArtifactAndVersion() { void testFindArchivedArtifactInfoBestMatchWithVersion() { String targetArtifactId = "adobe-acrobat-sign-connector"; String targetVersion = "10.0.10"; - ArchivedArtifact result = - versionService.findArchivedArtifactInfoBestMatchWithVersion(targetArtifactId, targetVersion); + ArchivedArtifact result = versionService.findArchivedArtifactInfoBestMatchWithVersion(targetArtifactId, + targetVersion); Assertions.assertNull(result); // Assert case with target version higher than all of latest version from // archived artifact list - ArchivedArtifact adobeArchivedArtifactVersion8 = - new ArchivedArtifact("10.0.8", "com.axonivy.connector", "adobe-sign-connector"); - ArchivedArtifact adobeArchivedArtifactVersion9 = - new ArchivedArtifact("10.0.9", "com.axonivy.connector", "adobe-acrobat-sign-connector"); + ArchivedArtifact adobeArchivedArtifactVersion8 = new ArchivedArtifact("10.0.8", "com.axonivy.connector", + "adobe-sign-connector"); + ArchivedArtifact adobeArchivedArtifactVersion9 = new ArchivedArtifact("10.0.9", "com.axonivy.connector", + "adobe-acrobat-sign-connector"); List archivedArtifacts = new ArrayList<>(); archivedArtifacts.add(adobeArchivedArtifactVersion8); archivedArtifacts.add(adobeArchivedArtifactVersion9); @@ -470,8 +476,8 @@ void testFindArchivedArtifactInfoBestMatchWithVersion() { Assertions.assertEquals(adobeArchivedArtifactVersion8, result); // Assert case with target version is in range of archived artifact list - ArchivedArtifact adobeArchivedArtifactVersion10 = - new ArchivedArtifact("10.0.10", "com.axonivy.connector", "adobe-sign-connector"); + ArchivedArtifact adobeArchivedArtifactVersion10 = new ArchivedArtifact("10.0.10", "com.axonivy.connector", + "adobe-sign-connector"); archivedArtifactsMap.get(targetArtifactId).add(adobeArchivedArtifactVersion10); result = versionService.findArchivedArtifactInfoBestMatchWithVersion(targetArtifactId, targetVersion); diff --git a/marketplace-service/src/test/resources/meta.json b/marketplace-service/src/test/resources/meta.json index d46c28424..6f23b2898 100644 --- a/marketplace-service/src/test/resources/meta.json +++ b/marketplace-service/src/test/resources/meta.json @@ -3,21 +3,21 @@ "id": "amazon-comprehend", "names": [ { - "locale":"en", + "locale": "en", "value": "Amazon Comprehend" }, { - "locale":"de", + "locale": "de", "value": "Amazon Comprehend DE" } ], "descriptions": [ { - "locale":"en", + "locale": "en", "value": "Amazon Comprehend is a AI service that uses machine learning to uncover information in unstructured data." }, { - "locale":"de", + "locale": "de", "value": "Amazon Comprehend is a AI service that uses machine learning to uncover information in unstructured data. DE" } ],