Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pagination #36

Merged
merged 3 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion api-examples/Get CVEs by Gardenlinux Version.bru
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ meta {
}

get {
url: {{schema_hostname_port}}/v1/cves/1592.0?sortBy=cveId
url: {{schema_hostname_port}}/v1/cves/1592.0?sortBy=cveId&pageNumber=1&pageSize=3
body: none
auth: none
}

params:query {
sortBy: cveId
pageNumber: 1
pageSize: 3
}
41 changes: 29 additions & 12 deletions src/main/java/io/gardenlinux/glvd/GlvdController.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,53 +24,70 @@ public GlvdController(@Nonnull GlvdService glvdService) {
ResponseEntity<List<SourcePackageCve>> 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}")
ResponseEntity<List<SourcePackageCve>> getCvePackages(
@PathVariable final String gardenlinuxVersion, @PathVariable final String packageList) {
var cveForPackages = glvdService.getCveForPackages(gardenlinuxVersion, packageList);
@PathVariable final String gardenlinuxVersion,
@PathVariable final String packageList,
@RequestParam(defaultValue = "cveId") final String sortBy,
@RequestParam(defaultValue = "ASC") final String sortOrder,
@RequestParam(required = false) final String pageNumber,
@RequestParam(required = false) final String pageSize
) {
var cveForPackages = glvdService.getCveForPackages(gardenlinuxVersion, packageList, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize));
return ResponseEntity.ok().body(cveForPackages);
}

@GetMapping("/packages/{sourcePackage}")
ResponseEntity<List<SourcePackageCve>> 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<List<SourcePackageCve>> 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<List<SourcePackage>> 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}")
ResponseEntity<List<SourcePackageCve>> 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)));
}

}
68 changes: 55 additions & 13 deletions src/main/java/io/gardenlinux/glvd/GlvdService.java
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -16,33 +24,67 @@ 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<SourcePackageCve> 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);
}

// native query does not support sorting
private Pageable determinePageAndSortFeatures2(SortAndPageOptions sortAndPageOptions) {
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);
} catch (NumberFormatException e) {
// fall through, don't page
logger.warn("Could not parse paging parameters", e);
}
}

return Pageable.unpaged();
}

public List<SourcePackageCve> getCveForDistribution(String gardenlinuxVersion, SortAndPageOptions sortAndPageOptions) {
return sourcePackageCveRepository.findByGardenlinuxVersion(gardenlinuxVersion, determinePageAndSortFeatures(sortAndPageOptions));
}

public List<SourcePackageCve> getCveForPackages(String gardenlinuxVersion, String packages) {
return sourcePackageCveRepository.findBySourcePackageNameInAndGardenlinuxVersion("{"+packages+"}", gardenlinuxVersion);
public List<SourcePackageCve> getCveForPackages(String gardenlinuxVersion, String packages, SortAndPageOptions sortAndPageOptions) {
return sourcePackageCveRepository.findBySourcePackageNameInAndGardenlinuxVersion("{" + packages + "}", gardenlinuxVersion, determinePageAndSortFeatures2(sortAndPageOptions));
}

public List<SourcePackage> getPackagesForDistro(String gardenlinuxVersion, String sortBy, String sortOrder) {
return sourcePackageRepository.findByGardenlinuxVersion(gardenlinuxVersion, Sort.by(Sort.Direction.valueOf(sortOrder), sortBy));
public List<SourcePackage> getPackagesForDistro(String gardenlinuxVersion, SortAndPageOptions sortAndPageOptions) {
return sourcePackageRepository.findByGardenlinuxVersion(gardenlinuxVersion, determinePageAndSortFeatures(sortAndPageOptions));
}

public List<SourcePackageCve> getPackageWithVulnerabilities(String sourcePackage, String sortBy, String sortOrder) {
return sourcePackageCveRepository.findBySourcePackageName(sourcePackage, Sort.by(Sort.Direction.valueOf(sortOrder), sortBy));
public List<SourcePackageCve> getPackageWithVulnerabilities(String sourcePackage, SortAndPageOptions sortAndPageOptions) {
return sourcePackageCveRepository.findBySourcePackageName(sourcePackage, determinePageAndSortFeatures(sortAndPageOptions));
}

public List<SourcePackageCve> getPackageWithVulnerabilitiesByVersion(String sourcePackage, String sourcePackageVersion, String sortBy) {
return sourcePackageCveRepository.findBySourcePackageNameAndSourcePackageVersion(sourcePackage, sourcePackageVersion, Sort.by(Sort.Direction.DESC, sortBy));
public List<SourcePackageCve> getPackageWithVulnerabilitiesByVersion(String sourcePackage, String sourcePackageVersion, SortAndPageOptions sortAndPageOptions) {
return sourcePackageCveRepository.findBySourcePackageNameAndSourcePackageVersion(sourcePackage, sourcePackageVersion, determinePageAndSortFeatures(sortAndPageOptions));
}

public List<SourcePackageCve> getPackagesByVulnerability(String gardenlinuxVersion, String cveId, String sortBy, String sortOrder) {
return sourcePackageCveRepository.findByCveIdAndGardenlinuxVersion(cveId, gardenlinuxVersion, Sort.by(Sort.Direction.valueOf(sortOrder), sortBy));
public List<SourcePackageCve> getPackagesByVulnerability(String gardenlinuxVersion, String cveId, SortAndPageOptions sortAndPageOptions) {
return sourcePackageCveRepository.findByCveIdAndGardenlinuxVersion(cveId, gardenlinuxVersion, determinePageAndSortFeatures(sortAndPageOptions));
}

}
4 changes: 4 additions & 0 deletions src/main/java/io/gardenlinux/glvd/SortAndPageOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.gardenlinux.glvd;

public record SortAndPageOptions(String sortBy, String sortOrder, String pageNumber, String pageSize) {
}
18 changes: 14 additions & 4 deletions src/main/java/io/gardenlinux/glvd/UiController.java
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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";
Expand All @@ -45,9 +49,13 @@ public String getCveForDistribution(
public String getCveForPackages(
@RequestParam(name = "gardenlinuxVersion", required = true) String gardenlinuxVersion,
@RequestParam(name = "packages", required = true) String packages,
@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.getCveForPackages(gardenlinuxVersion, packages);
var sourcePackageCves = glvdService.getCveForPackages(gardenlinuxVersion, packages, new SortAndPageOptions(sortBy, sortOrder, pageNumber, pageSize));
model.addAttribute("sourcePackageCves", sourcePackageCves);
model.addAttribute("gardenlinuxVersion", gardenlinuxVersion);
model.addAttribute("packages", packages);
Expand All @@ -60,9 +68,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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@

public interface SourcePackageCveRepository extends JpaRepository<SourcePackageCve, String> {

List<SourcePackageCve> findBySourcePackageName(@Param("source_package_name") String source_package_name, Sort sort);
List<SourcePackageCve> findBySourcePackageNameAndSourcePackageVersion(@Param("source_package_name") String source_package_name, @Param("source_package_version") String source_package_version, Sort sort);
List<SourcePackageCve> findByCveIdAndGardenlinuxVersion(@Param("cve_id") String cve_id, @Param("gardenlinux_version") String gardenlinux_version, Sort sort);
List<SourcePackageCve> findBySourcePackageName(@Param("source_package_name") String source_package_name, Pageable pageable);
List<SourcePackageCve> findBySourcePackageNameAndSourcePackageVersion(@Param("source_package_name") String source_package_name, @Param("source_package_version") String source_package_version, Pageable pageable);
List<SourcePackageCve> findByCveIdAndGardenlinuxVersion(@Param("cve_id") String cve_id, @Param("gardenlinux_version") String gardenlinux_version, Pageable pageable);

List<SourcePackageCve> findByGardenlinuxVersion(@Param("gardenlinux_version") String gardenlinux_version, Sort sort);
List<SourcePackageCve> 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?
// fixme: does not support sorting, cf https://github.com/spring-projects/spring-data-jpa/issues/2504#issuecomment-1527743003
// pagination seems to work ok
@Query(value = """
SELECT * FROM sourcepackagecve
WHERE source_package_name = ANY(:source_package_names ::TEXT[]) AND gardenlinux_version = :gardenlinux_version
""", nativeQuery = true)
List<SourcePackageCve> findBySourcePackageNameInAndGardenlinuxVersion(@Param("source_package_names") String source_package_names, @Param("gardenlinux_version") String gardenlinux_version);
List<SourcePackageCve> findBySourcePackageNameInAndGardenlinuxVersion(@Param("source_package_names") String source_package_names, @Param("gardenlinux_version") String gardenlinux_version, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
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;

import java.util.List;

public interface SourcePackageRepository extends JpaRepository<SourcePackage, String> {
List<SourcePackage> findByGardenlinuxVersion(@Param("gardenlinux_version") String gardenlinux_version, Sort by);
List<SourcePackage> findByGardenlinuxVersion(@Param("gardenlinux_version") String gardenlinux_version, Pageable pageable);
}
Loading
Loading