Skip to content

Commit

Permalink
Feature/marp 473 follow up for marp 264 installation frequency provid…
Browse files Browse the repository at this point in the history
…ing data (#35)
  • Loading branch information
tvtphuc-axonivy authored Jul 18, 2024
1 parent 27f4c1b commit 40e9d29
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/service-dev-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ jobs:
- name: Restart Tomcat server
run: |
sudo systemctl stop tomcat
sudo systemctl start tomcat
sudo systemctl start tomcat
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ private void createDetailResource(ProductDetailModel model, Product product, Str
model.setCompatibility(product.getCompatibility());
model.setContactUs(product.getContactUs());
model.setCost(product.getCost());
model.setInstallationCount(product.getInstallationCount());

if (StringUtils.isBlank(tag) && StringUtils.isNotBlank(product.getNewestReleaseVersion())) {
tag = product.getNewestReleaseVersion();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
package com.axonivy.market.controller;

import com.axonivy.market.model.MavenArtifactVersionModel;
import com.axonivy.market.service.VersionService;
import static com.axonivy.market.constants.RequestMappingConstants.PRODUCT_DETAILS;

import java.util.List;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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 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 org.springframework.web.bind.annotation.PathVariable;

import java.util.List;

import static com.axonivy.market.constants.RequestMappingConstants.PRODUCT_DETAILS;
import io.swagger.v3.oas.annotations.Operation;

@RestController
@RequestMapping(PRODUCT_DETAILS)
Expand All @@ -39,6 +42,13 @@ public ResponseEntity<ProductDetailModel> findProductDetailsByVersion(@PathVaria
return new ResponseEntity<>(detailModelAssembler.toModel(productDetail, tag), HttpStatus.OK);
}

@Operation(summary = "increase installation count by 1", description = "increase installation count by 1")
@PutMapping("/installationcount/{key}")
public ResponseEntity<Integer> syncInstallationCount(@PathVariable("key") String key) {
int result = productService.updateInstallationCountForProduct(key);
return new ResponseEntity<>(result, HttpStatus.OK);
}

@GetMapping("/{id}")
public ResponseEntity<ProductDetailModel> findProductDetails(@PathVariable("id") String id) {
var productDetail = productService.fetchProductDetail(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,11 @@
import java.util.Date;
import java.util.List;


import com.axonivy.market.model.MultilingualismValue;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import lombok.*;
import com.axonivy.market.github.model.MavenArtifact;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.springframework.data.annotation.Id;
Expand All @@ -24,6 +20,7 @@
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Document(PRODUCT)
public class Product implements Serializable {
private static final long serialVersionUID = -8770801877877277258L;
Expand Down Expand Up @@ -51,11 +48,12 @@ public class Product implements Serializable {
private String compatibility;
private Boolean validate;
private Boolean contactUs;
private Integer installationCount;
private int installationCount;
private Date newestPublishedDate;
private String newestReleaseVersion;
private List<ProductModuleContent> productModuleContents;
private List<MavenArtifact> artifacts;
private Boolean synchronizedInstallationCount;

@Override
public int hashCode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class ProductDetailModel extends ProductModel {
private String compatibility;
private Boolean contactUs;
private ProductModuleContent productModuleContent;
private int installationCount;

@Override
public int hashCode() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public interface ProductService {

boolean syncLatestDataFromMarketRepo();

int updateInstallationCountForProduct(String key);
Product fetchProductDetail(String id);

String getCompatibilityFromOldestTag(String oldestTag);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,25 @@

import java.io.IOException;
import java.net.URL;
import java.util.*;
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.axonivy.market.constants.CommonConstants;
import com.axonivy.market.github.service.GHAxonIvyProductRepoService;
import com.axonivy.market.github.util.GitHubUtils;
import com.axonivy.market.entity.ProductModuleContent;
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;
Expand All @@ -26,19 +33,24 @@
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;
import com.axonivy.market.entity.Product;
import com.axonivy.market.entity.ProductModuleContent;
import com.axonivy.market.enums.FileType;
import com.axonivy.market.enums.SortOption;
import com.axonivy.market.enums.TypeOption;
import com.axonivy.market.factory.ProductFactory;
import com.axonivy.market.github.model.GitHubFile;
import com.axonivy.market.github.service.GHAxonIvyMarketRepoService;
import com.axonivy.market.entity.GitHubRepoMeta;
import com.axonivy.market.enums.TypeOption;
import com.axonivy.market.github.service.GHAxonIvyProductRepoService;
import com.axonivy.market.github.service.GitHubService;
import com.axonivy.market.github.util.GitHubUtils;
import com.axonivy.market.repository.GitHubRepoMetaRepository;
import com.axonivy.market.repository.ProductRepository;
import com.axonivy.market.service.ProductService;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.extern.log4j.Log4j2;

Expand All @@ -54,9 +66,13 @@ public class ProductServiceImpl implements ProductService {

private GHCommit lastGHCommit;
private GitHubRepoMeta marketRepoMeta;
private final ObjectMapper mapper = new ObjectMapper();

public static final String NON_NUMERIC_CHAR = "[^0-9.]";
@Value("${synchronized.installation.counts.path}")
private String installationCountPath;

public static final String NON_NUMERIC_CHAR = "[^0-9.]";
private final Random random = new Random();
public ProductServiceImpl(ProductRepository productRepository, GHAxonIvyMarketRepoService axonIvyMarketRepoService,
GHAxonIvyProductRepoService axonIvyProductRepoService, GitHubRepoMetaRepository gitHubRepoMetaRepository,
GitHubService gitHubService) {
Expand Down Expand Up @@ -108,6 +124,37 @@ public boolean syncLatestDataFromMarketRepo() {
return isAlreadyUpToDate;
}

@Override
public int updateInstallationCountForProduct(String key) {
return productRepository.findById(key).map(product -> {
log.info("updating installation count for product {}", key);
if (!BooleanUtils.isTrue(product.getSynchronizedInstallationCount())) {
syncInstallationCountWithProduct(product);
}
product.setInstallationCount(product.getInstallationCount() + 1);
return productRepository.save(product);
}).map(Product::getInstallationCount).orElse(0);
}

private void syncInstallationCountWithProduct(Product product) {
log.info("synchronizing installation count for product {}", product.getId());
try {
String installationCounts = Files.readString(Paths.get(installationCountPath));
Map<String, Integer> mapping = mapper.readValue(installationCounts,
new TypeReference<HashMap<String, Integer>>(){});
List<String> keyList = mapping.keySet().stream().toList();
int currentInstallationCount = keyList.contains(product.getId())
? mapping.get(product.getId())
: random.nextInt(20, 50);
product.setInstallationCount(currentInstallationCount);
product.setSynchronizedInstallationCount(true);
log.info("synchronized installation count for product {} successfully", product.getId());
} catch (IOException ex) {
log.error(ex.getMessage());
log.error("Could not read the marketplace-installation file to synchronize");
}
}

private void syncRepoMetaDataStatus() {
if (lastGHCommit == null) {
return;
Expand Down Expand Up @@ -273,6 +320,7 @@ private void updateProductFromReleaseTags(Product product) {
}

// Cover 3 cases after removing non-numeric characters (8, 11.1 and 10.0.2)
@Override
public String getCompatibilityFromOldestTag(String oldestTag) {
if (!oldestTag.contains(CommonConstants.DOT_SEPARATOR)) {
return oldestTag + ".0+";
Expand All @@ -287,6 +335,13 @@ public String getCompatibilityFromOldestTag(String oldestTag) {

@Override
public Product fetchProductDetail(String id) {
return productRepository.findById(id).orElse(null);
Product product = productRepository.findById(id).orElse(null);
return Optional.ofNullable(product).map(productItem -> {
if (!BooleanUtils.isTrue(productItem.getSynchronizedInstallationCount())) {
syncInstallationCountWithProduct(productItem);
return productRepository.save(productItem);
}
return productItem;
}).orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ springdoc.api-docs.path=/api-docs
springdoc.swagger-ui.path=/swagger-ui.html
market.cors.allowed.origin.patterns=http://localhost:[*], http://10.193.8.78:[*], http://marketplace.server.ivy-cloud.com:[*]
market.cors.allowed.origin.maxAge=3600
synchronized.installation.counts.path=${MARKETPLACE_INSTALLATION_URL}
spring.security.oauth2.client.registration.github.client-id=<replace-with-your-client-id>
spring.security.oauth2.client.registration.github.client-secret=<replace-with-your-client-secret>
jwt.secret=<replace-with-jwt-secret>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@
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.model.MavenArtifactVersionModel;
import com.axonivy.market.model.MultilingualismValue;
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;
import org.mockito.InjectMocks;

import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

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;

@ExtendWith(MockitoExtension.class)
class ProductDetailsControllerTest {
Expand Down Expand Up @@ -89,6 +89,15 @@ void testFindProductVersionsById() {
Assertions.assertEquals(models, result.getBody());
}

@Test
void testSyncInstallationCount() {
when(productService.updateInstallationCountForProduct("google-maps-connector")).thenReturn(1);

var result = productDetailsController.syncInstallationCount("google-maps-connector");

assertEquals(1, result.getBody());
}

private Product mockProduct() {
Product mockProduct = new Product();
mockProduct.setId(DOCKER_CONNECTOR_ID);
Expand Down
Loading

0 comments on commit 40e9d29

Please sign in to comment.