From 0055a032d688a7122168844662598693ac68a1cb Mon Sep 17 00:00:00 2001 From: Florian Wilhelm Date: Thu, 12 Sep 2024 14:38:17 +0200 Subject: [PATCH] Pagination --- .../io/gardenlinux/glvd/GlvdController.java | 31 ++++++++---- .../java/io/gardenlinux/glvd/GlvdService.java | 50 ++++++++++++++----- .../gardenlinux/glvd/SortAndPageOptions.java | 4 ++ .../io/gardenlinux/glvd/UiController.java | 12 +++-- .../glvd/db/SourcePackageCveRepository.java | 8 +-- .../glvd/db/SourcePackageRepository.java | 3 +- .../gardenlinux/glvd/GlvdControllerTest.java | 11 ++-- 7 files changed, 83 insertions(+), 36 deletions(-) create mode 100644 src/main/java/io/gardenlinux/glvd/SortAndPageOptions.java diff --git a/src/main/java/io/gardenlinux/glvd/GlvdController.java b/src/main/java/io/gardenlinux/glvd/GlvdController.java index 0bf6f0d..453596d 100644 --- a/src/main/java/io/gardenlinux/glvd/GlvdController.java +++ b/src/main/java/io/gardenlinux/glvd/GlvdController.java @@ -24,9 +24,11 @@ public GlvdController(@Nonnull GlvdService glvdService) { ResponseEntity> getCveDistro( @PathVariable final String gardenlinuxVersion, @RequestParam(defaultValue = "cveId") final String sortBy, - @RequestParam(defaultValue = "ASC") final String sortOrder + @RequestParam(defaultValue = "ASC") final String sortOrder, + @RequestParam(required = false) final String pageNumber, + @RequestParam(required = false) final String pageSize ) { - return ResponseEntity.ok().body(glvdService.getCveForDistribution(gardenlinuxVersion, sortBy, sortOrder)); + return ResponseEntity.ok().body(glvdService.getCveForDistribution(gardenlinuxVersion, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize))); } @GetMapping("/cves/{gardenlinuxVersion}/packages/{packageList}") @@ -40,27 +42,34 @@ ResponseEntity> getCvePackages( ResponseEntity> packageWithVulnerabilities( @PathVariable final String sourcePackage, @RequestParam(defaultValue = "cveId") final String sortBy, - @RequestParam(defaultValue = "ASC") final String sortOrder + @RequestParam(defaultValue = "ASC") final String sortOrder, + @RequestParam(required = false) final String pageNumber, + @RequestParam(required = false) final String pageSize ) { - return ResponseEntity.ok(glvdService.getPackageWithVulnerabilities(sourcePackage, sortBy, sortOrder)); + return ResponseEntity.ok(glvdService.getPackageWithVulnerabilities(sourcePackage, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize))); } @GetMapping("/packages/{sourcePackage}/{sourcePackageVersion}") ResponseEntity> packageWithVulnerabilitiesByVersion( @PathVariable final String sourcePackage, @PathVariable final String sourcePackageVersion, - @RequestParam(defaultValue = "cveId") final String sortBy + @RequestParam(defaultValue = "cveId") final String sortBy, + @RequestParam(defaultValue = "ASC") final String sortOrder, + @RequestParam(required = false) final String pageNumber, + @RequestParam(required = false) final String pageSize ) { - return ResponseEntity.ok(glvdService.getPackageWithVulnerabilitiesByVersion(sourcePackage, sourcePackageVersion, sortBy)); + return ResponseEntity.ok(glvdService.getPackageWithVulnerabilitiesByVersion(sourcePackage, sourcePackageVersion, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize))); } @GetMapping("/distro/{gardenlinuxVersion}") ResponseEntity> packagesForDistro( @PathVariable final String gardenlinuxVersion, @RequestParam(defaultValue = "sourcePackageName") final String sortBy, - @RequestParam(defaultValue = "ASC") final String sortOrder + @RequestParam(defaultValue = "ASC") final String sortOrder, + @RequestParam(required = false) final String pageNumber, + @RequestParam(required = false) final String pageSize ) { - return ResponseEntity.ok(glvdService.getPackagesForDistro(gardenlinuxVersion, sortBy, sortOrder)); + return ResponseEntity.ok(glvdService.getPackagesForDistro(gardenlinuxVersion, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize))); } @GetMapping("/distro/{gardenlinuxVersion}/{cveId}") @@ -68,9 +77,11 @@ ResponseEntity> packagesByVulnerability( @PathVariable final String gardenlinuxVersion, @PathVariable final String cveId, @RequestParam(defaultValue = "cveId") final String sortBy, - @RequestParam(defaultValue = "ASC") final String sortOrder + @RequestParam(defaultValue = "ASC") final String sortOrder, + @RequestParam(required = false) final String pageNumber, + @RequestParam(required = false) final String pageSize ) { - return ResponseEntity.ok(glvdService.getPackagesByVulnerability(gardenlinuxVersion, cveId, sortBy, sortOrder)); + return ResponseEntity.ok(glvdService.getPackagesByVulnerability(gardenlinuxVersion, cveId, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize))); } } diff --git a/src/main/java/io/gardenlinux/glvd/GlvdService.java b/src/main/java/io/gardenlinux/glvd/GlvdService.java index ac2a509..b979798 100644 --- a/src/main/java/io/gardenlinux/glvd/GlvdService.java +++ b/src/main/java/io/gardenlinux/glvd/GlvdService.java @@ -1,7 +1,15 @@ package io.gardenlinux.glvd; -import io.gardenlinux.glvd.db.*; +import io.gardenlinux.glvd.db.SourcePackage; +import io.gardenlinux.glvd.db.SourcePackageCve; +import io.gardenlinux.glvd.db.SourcePackageCveRepository; +import io.gardenlinux.glvd.db.SourcePackageRepository; import jakarta.annotation.Nonnull; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; @@ -16,33 +24,51 @@ public class GlvdService { @Nonnull private final SourcePackageRepository sourcePackageRepository; + Logger logger = LoggerFactory.getLogger(GlvdService.class); + public GlvdService(@Nonnull SourcePackageCveRepository sourcePackageCveRepository, @Nonnull SourcePackageRepository sourcePackageRepository) { this.sourcePackageCveRepository = sourcePackageCveRepository; this.sourcePackageRepository = sourcePackageRepository; } - public List getCveForDistribution(String gardenlinuxVersion, String sortBy, String sortOrder) { - return sourcePackageCveRepository.findByGardenlinuxVersion(gardenlinuxVersion, Sort.by(Sort.Direction.valueOf(sortOrder), sortBy)); + private Pageable determinePageAndSortFeatures(SortAndPageOptions sortAndPageOptions) { + var sort = Sort.by(Sort.Direction.valueOf(sortAndPageOptions.sortOrder()), sortAndPageOptions.sortBy()); + if (!StringUtils.isEmpty(sortAndPageOptions.pageNumber()) && !StringUtils.isEmpty(sortAndPageOptions.pageSize())) { + try { + var num = Integer.parseInt(sortAndPageOptions.pageNumber()); + var size = Integer.parseInt(sortAndPageOptions.pageSize()); + return PageRequest.of(num, size, sort); + } catch (NumberFormatException e) { + // fall through, don't page + logger.warn("Could not parse paging parameters", e); + } + } + + return Pageable.unpaged(sort); + } + + public List getCveForDistribution(String gardenlinuxVersion, SortAndPageOptions sortAndPageOptions) { + return sourcePackageCveRepository.findByGardenlinuxVersion(gardenlinuxVersion, determinePageAndSortFeatures(sortAndPageOptions)); } public List getCveForPackages(String gardenlinuxVersion, String packages) { - return sourcePackageCveRepository.findBySourcePackageNameInAndGardenlinuxVersion("{"+packages+"}", gardenlinuxVersion); + return sourcePackageCveRepository.findBySourcePackageNameInAndGardenlinuxVersion("{" + packages + "}", gardenlinuxVersion); } - public List getPackagesForDistro(String gardenlinuxVersion, String sortBy, String sortOrder) { - return sourcePackageRepository.findByGardenlinuxVersion(gardenlinuxVersion, Sort.by(Sort.Direction.valueOf(sortOrder), sortBy)); + public List getPackagesForDistro(String gardenlinuxVersion, SortAndPageOptions sortAndPageOptions) { + return sourcePackageRepository.findByGardenlinuxVersion(gardenlinuxVersion, determinePageAndSortFeatures(sortAndPageOptions)); } - public List getPackageWithVulnerabilities(String sourcePackage, String sortBy, String sortOrder) { - return sourcePackageCveRepository.findBySourcePackageName(sourcePackage, Sort.by(Sort.Direction.valueOf(sortOrder), sortBy)); + public List getPackageWithVulnerabilities(String sourcePackage, SortAndPageOptions sortAndPageOptions) { + return sourcePackageCveRepository.findBySourcePackageName(sourcePackage, determinePageAndSortFeatures(sortAndPageOptions)); } - public List getPackageWithVulnerabilitiesByVersion(String sourcePackage, String sourcePackageVersion, String sortBy) { - return sourcePackageCveRepository.findBySourcePackageNameAndSourcePackageVersion(sourcePackage, sourcePackageVersion, Sort.by(Sort.Direction.DESC, sortBy)); + public List getPackageWithVulnerabilitiesByVersion(String sourcePackage, String sourcePackageVersion, SortAndPageOptions sortAndPageOptions) { + return sourcePackageCveRepository.findBySourcePackageNameAndSourcePackageVersion(sourcePackage, sourcePackageVersion, determinePageAndSortFeatures(sortAndPageOptions)); } - public List getPackagesByVulnerability(String gardenlinuxVersion, String cveId, String sortBy, String sortOrder) { - return sourcePackageCveRepository.findByCveIdAndGardenlinuxVersion(cveId, gardenlinuxVersion, Sort.by(Sort.Direction.valueOf(sortOrder), sortBy)); + public List getPackagesByVulnerability(String gardenlinuxVersion, String cveId, SortAndPageOptions sortAndPageOptions) { + return sourcePackageCveRepository.findByCveIdAndGardenlinuxVersion(cveId, gardenlinuxVersion, determinePageAndSortFeatures(sortAndPageOptions)); } } diff --git a/src/main/java/io/gardenlinux/glvd/SortAndPageOptions.java b/src/main/java/io/gardenlinux/glvd/SortAndPageOptions.java new file mode 100644 index 0000000..e0f3f4e --- /dev/null +++ b/src/main/java/io/gardenlinux/glvd/SortAndPageOptions.java @@ -0,0 +1,4 @@ +package io.gardenlinux.glvd; + +public record SortAndPageOptions(String sortBy, String sortOrder, String pageNumber, String pageSize) { +} diff --git a/src/main/java/io/gardenlinux/glvd/UiController.java b/src/main/java/io/gardenlinux/glvd/UiController.java index a8e0ae9..659f72f 100644 --- a/src/main/java/io/gardenlinux/glvd/UiController.java +++ b/src/main/java/io/gardenlinux/glvd/UiController.java @@ -21,8 +21,10 @@ public String getPackagesForDistro( @RequestParam(name = "gardenlinuxVersion", required = true) String gardenlinuxVersion, @RequestParam(defaultValue = "cveId") final String sortBy, @RequestParam(defaultValue = "ASC") final String sortOrder, + @RequestParam(required = false) final String pageNumber, + @RequestParam(required = false) final String pageSize, Model model) { - var packages = glvdService.getPackagesForDistro(gardenlinuxVersion, sortBy, sortOrder); + var packages = glvdService.getPackagesForDistro(gardenlinuxVersion, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize)); model.addAttribute("packages", packages); model.addAttribute("gardenlinuxVersion", gardenlinuxVersion); return "getPackagesForDistro"; @@ -33,9 +35,11 @@ public String getCveForDistribution( @RequestParam(name = "gardenlinuxVersion", required = true) String gardenlinuxVersion, @RequestParam(defaultValue = "cveId") final String sortBy, @RequestParam(defaultValue = "ASC") final String sortOrder, + @RequestParam(required = false) final String pageNumber, + @RequestParam(required = false) final String pageSize, Model model ) { - var sourcePackageCves = glvdService.getCveForDistribution(gardenlinuxVersion, sortBy, sortOrder); + var sourcePackageCves = glvdService.getCveForDistribution(gardenlinuxVersion, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize)); model.addAttribute("sourcePackageCves", sourcePackageCves); model.addAttribute("gardenlinuxVersion", gardenlinuxVersion); return "getCveForDistribution"; @@ -60,9 +64,11 @@ public String getPackagesByVulnerability( @RequestParam(name = "cveId", required = true) String cveId, @RequestParam(defaultValue = "cveId") final String sortBy, @RequestParam(defaultValue = "ASC") final String sortOrder, + @RequestParam(required = false) final String pageNumber, + @RequestParam(required = false) final String pageSize, Model model ) { - var sourcePackageCves = glvdService.getPackagesByVulnerability(gardenlinuxVersion, cveId, sortBy, sortOrder); + var sourcePackageCves = glvdService.getPackagesByVulnerability(gardenlinuxVersion, cveId, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize)); model.addAttribute("sourcePackageCves", sourcePackageCves); model.addAttribute("gardenlinuxVersion", gardenlinuxVersion); model.addAttribute("cveId", cveId); diff --git a/src/main/java/io/gardenlinux/glvd/db/SourcePackageCveRepository.java b/src/main/java/io/gardenlinux/glvd/db/SourcePackageCveRepository.java index e404c1f..ace4b94 100644 --- a/src/main/java/io/gardenlinux/glvd/db/SourcePackageCveRepository.java +++ b/src/main/java/io/gardenlinux/glvd/db/SourcePackageCveRepository.java @@ -10,11 +10,11 @@ public interface SourcePackageCveRepository extends JpaRepository { - List findBySourcePackageName(@Param("source_package_name") String source_package_name, Sort sort); - List findBySourcePackageNameAndSourcePackageVersion(@Param("source_package_name") String source_package_name, @Param("source_package_version") String source_package_version, Sort sort); - List findByCveIdAndGardenlinuxVersion(@Param("cve_id") String cve_id, @Param("gardenlinux_version") String gardenlinux_version, Sort sort); + List findBySourcePackageName(@Param("source_package_name") String source_package_name, Pageable pageable); + List findBySourcePackageNameAndSourcePackageVersion(@Param("source_package_name") String source_package_name, @Param("source_package_version") String source_package_version, Pageable pageable); + List findByCveIdAndGardenlinuxVersion(@Param("cve_id") String cve_id, @Param("gardenlinux_version") String gardenlinux_version, Pageable pageable); - List findByGardenlinuxVersion(@Param("gardenlinux_version") String gardenlinux_version, Sort sort); + List findByGardenlinuxVersion(@Param("gardenlinux_version") String gardenlinux_version, Pageable pageable); // would be nice if we did not need a native query here // is this (the in-array search for packages) possible in any other way with spring data jpa? diff --git a/src/main/java/io/gardenlinux/glvd/db/SourcePackageRepository.java b/src/main/java/io/gardenlinux/glvd/db/SourcePackageRepository.java index 8eea5d3..a30a7bb 100644 --- a/src/main/java/io/gardenlinux/glvd/db/SourcePackageRepository.java +++ b/src/main/java/io/gardenlinux/glvd/db/SourcePackageRepository.java @@ -1,5 +1,6 @@ package io.gardenlinux.glvd.db; +import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.query.Param; @@ -7,5 +8,5 @@ import java.util.List; public interface SourcePackageRepository extends JpaRepository { - List findByGardenlinuxVersion(@Param("gardenlinux_version") String gardenlinux_version, Sort by); + List findByGardenlinuxVersion(@Param("gardenlinux_version") String gardenlinux_version, Pageable pageable); } diff --git a/src/test/java/io/gardenlinux/glvd/GlvdControllerTest.java b/src/test/java/io/gardenlinux/glvd/GlvdControllerTest.java index 24873fe..5963211 100644 --- a/src/test/java/io/gardenlinux/glvd/GlvdControllerTest.java +++ b/src/test/java/io/gardenlinux/glvd/GlvdControllerTest.java @@ -9,7 +9,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; @@ -79,7 +78,7 @@ public void shouldReturnCvesForGardenlinux() { .filter(document("getCveForDistro", preprocessRequest(modifyUris().scheme("https").host("glvd.gardenlinux.io").removePort()), preprocessResponse(prettyPrint()))) - .when().port(this.port).get("/v1/cves/1592.0?sortBy=cveId&sortOrder=DESC") + .when().port(this.port).get("/v1/cves/1592.0?sortBy=cveId&sortOrder=DESC&pageNumber=4&pageSize=2") .then().statusCode(HttpStatus.SC_OK); } @@ -89,7 +88,7 @@ public void shouldReturnCvesForListOfPackages() { .filter(document("getCveForPackages", preprocessRequest(modifyUris().scheme("https").host("glvd.gardenlinux.io").removePort()), preprocessResponse(prettyPrint()))) - .when().port(this.port).get("/v1/cves/1592.0/packages/crun,vim") + .when().port(this.port).get("/v1/cves/1592.0/packages/crun,vim?pageNumber=4&pageSize=2") .then().statusCode(HttpStatus.SC_OK); } @@ -99,7 +98,7 @@ public void shouldGetPackagesForDistro() { .filter(document("getPackages", preprocessRequest(modifyUris().scheme("https").host("glvd.gardenlinux.io").removePort()), preprocessResponse(prettyPrint()))) - .when().port(this.port).get("/v1/distro/1592.0") + .when().port(this.port).get("/v1/distro/1592.0?pageNumber=4&pageSize=2") .then().statusCode(200); } @@ -109,7 +108,7 @@ public void shouldPackageWithVulnerabilities() { .filter(document("getPackageWithVulnerabilities", preprocessRequest(modifyUris().scheme("https").host("glvd.gardenlinux.io").removePort()), preprocessResponse(prettyPrint()))) - .when().port(this.port).get("/v1/packages/vim") + .when().port(this.port).get("/v1/packages/vim?pageNumber=4&pageSize=2") .then().statusCode(200); } @@ -119,7 +118,7 @@ public void shouldPackageWithVulnerabilitiesByVersion() { .filter(document("getPackageWithVulnerabilitiesByVersion", preprocessRequest(modifyUris().scheme("https").host("glvd.gardenlinux.io").removePort()), preprocessResponse(prettyPrint()))) - .when().port(this.port).get("/v1/packages/vim/2:9.1.0496-1+b1") + .when().port(this.port).get("/v1/packages/vim/2:9.1.0496-1+b1?pageNumber=4&pageSize=2") .then().statusCode(200); }