Skip to content

Commit

Permalink
Merge branch 'develop' of https://github.com/axonivy-market/marketplace
Browse files Browse the repository at this point in the history
… into feature/MARP-224-Create-dockerfile-for-deployment-of-marketplace

# Conflicts:
#	marketplace-service/src/main/java/com/axonivy/market/config/MongoConfig.java
#	marketplace-service/src/main/java/com/axonivy/market/config/WebConfig.java
#	marketplace-service/src/main/java/com/axonivy/market/controller/ProductController.java
#	marketplace-service/src/main/java/com/axonivy/market/entity/User.java
#	marketplace-service/src/main/java/com/axonivy/market/github/service/impl/GitHubServiceImpl.java
  • Loading branch information
nqhoan-axonivy committed Jul 18, 2024
2 parents ced5e75 + 445a3aa commit 215561d
Show file tree
Hide file tree
Showing 71 changed files with 964 additions and 850 deletions.
17 changes: 12 additions & 5 deletions marketplace-service/README.md
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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=
Expand All @@ -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
* 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
6 changes: 3 additions & 3 deletions marketplace-service/pom.xml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
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">
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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath />
<relativePath/>
</parent>
<groupId>com.axonivy.market</groupId>
<artifactId>marketplace-service</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
@SpringBootApplication
public class MarketplaceServiceApplication {

private ProductService productService;
private final ProductService productService;

public MarketplaceServiceApplication(ProductService productService) {
this.productService = productService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,15 @@ 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);
}

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();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<Product, ProductDetailModel> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
import java.util.Comparator;

public class ArchivedArtifactsComparator implements Comparator<ArchivedArtifact> {
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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,29 @@

public class LatestVersionComparator implements Comparator<String> {

@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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ public class MongoConfig extends AbstractMongoClientConfiguration {
@Value("${spring.data.mongodb.uri}")
private String uri;

@Value("${spring.data.mongodb.database}")
private String databaseName;
@Value("${spring.data.mongodb.database}")
private String databaseName;

@Override
protected String getDatabaseName() {
return databaseName;
}
@Override
protected String getDatabaseName() {
return databaseName;
}

@Override
public MongoClient mongoClient() {
Expand All @@ -43,19 +43,19 @@ public MongoClient mongoClient() {
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;
}
/**
* 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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", "OPTIONS" };

private final MarketHeaderInterceptor headerInterceptor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
}
Original file line number Diff line number Diff line change
@@ -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";
Expand Down
Original file line number Diff line number Diff line change
@@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ public ResponseEntity<Message> 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,7 +41,8 @@ public class FeedbackController {

private final PagedResourcesAssembler<Feedback> pagedResourcesAssembler;

public FeedbackController(FeedbackService feedbackService, JwtService jwtService, FeedbackModelAssembler feedbackModelAssembler, PagedResourcesAssembler<Feedback> pagedResourcesAssembler) {
public FeedbackController(FeedbackService feedbackService, JwtService jwtService,
FeedbackModelAssembler feedbackModelAssembler, PagedResourcesAssembler<Feedback> pagedResourcesAssembler) {
this.feedbackService = feedbackService;
this.jwtService = jwtService;
this.feedbackModelAssembler = feedbackModelAssembler;
Expand All @@ -43,7 +51,8 @@ public FeedbackController(FeedbackService feedbackService, JwtService jwtService

@Operation(summary = "Find all feedbacks by product id")
@GetMapping("/product/{productId}")
public ResponseEntity<PagedModel<FeedbackModel>> findFeedbacks(@PathVariable("productId") String productId, Pageable pageable) {
public ResponseEntity<PagedModel<FeedbackModel>> findFeedbacks(@PathVariable("productId") String productId,
Pageable pageable) {
Page<Feedback> results = feedbackService.findFeedbacks(productId, pageable);
if (results.isEmpty()) {
return generateEmptyPagedModel();
Expand All @@ -61,15 +70,15 @@ public ResponseEntity<FeedbackModel> findFeedback(@PathVariable("id") String id)

@Operation(summary = "Find all feedbacks by user id and product id")
@GetMapping()
public ResponseEntity<FeedbackModel> findFeedbackByUserIdAndProductId(
@RequestParam String userId,
public ResponseEntity<FeedbackModel> findFeedbackByUserIdAndProductId(@RequestParam String userId,
@RequestParam String productId) {
Feedback feedback = feedbackService.findFeedbackByUserIdAndProductId(userId, productId);
return ResponseEntity.ok(feedbackModelAssembler.toModel(feedback));
}

@PostMapping
public ResponseEntity<Void> createFeedback(@RequestBody @Valid Feedback feedback, @RequestHeader(value = "Authorization", required = false) String authorizationHeader) {
public ResponseEntity<Void> 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
Expand All @@ -84,9 +93,7 @@ public ResponseEntity<Void> 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();
Expand All @@ -100,8 +107,8 @@ public ResponseEntity<List<ProductRating>> getProductRating(@PathVariable("produ

@SuppressWarnings("unchecked")
private ResponseEntity<PagedModel<FeedbackModel>> generateEmptyPagedModel() {
var emptyPagedModel = (PagedModel<FeedbackModel>) pagedResourcesAssembler
.toEmptyModel(Page.empty(), FeedbackModel.class);
var emptyPagedModel = (PagedModel<FeedbackModel>) pagedResourcesAssembler.toEmptyModel(Page.empty(),
FeedbackModel.class);
return new ResponseEntity<>(emptyPagedModel, HttpStatus.OK);
}
}
Loading

0 comments on commit 215561d

Please sign in to comment.