diff --git a/app/controllers/Statistics.scala b/app/controllers/Statistics.scala index 7ab18c6..12d42da 100644 --- a/app/controllers/Statistics.scala +++ b/app/controllers/Statistics.scala @@ -92,6 +92,7 @@ object Statistics{ //implicit val groupedDependencyFormats = Json.format[GroupedDependency] implicit val groupedVulnerableDependencyDetailedIdentifierWrites = Json.writes[GroupedVulnerableDependencyDetailedIdentifier] implicit val canonizedGroupedVulnerableDependencyDetailedIdentifierWrites = Json.writes[CanonizedGroupedVulnerableDependencyDetailedIdentifier] + } //noinspection TypeAnnotation @@ -475,4 +476,33 @@ class Statistics @Inject()( } + def librariesCountApi(selector: Option[String], operator: Option[String], threshold: Option[Double], strict: Boolean) = ApiAction(Dependencies).async{ implicit req => + val (lastRefreshTime, resultsFuture) = projectReportsProvider.resultsForVersions(versions) + val vulnLibFilterOrError: Either[GroupedDependency => Boolean, String] = (operator, threshold) match { + case (Some("gte"|">="|"≥"), Some(num)) => Left(_.vulnerabilities.exists(_.cvssScore.exists(_>=num))) + case (Some("gt"|">"), Some(num)) => Left(_.vulnerabilities.exists(_.cvssScore.exists(_>num))) + // Other operators are currently not defined due to unclear semantics when some library has multiple vulnerabilities with various severities + case (None, None) => Left(_ => true) + case _ => Right("Bad combination of operator and number. Supported operators are gt and gte or their variants (>, >=, ≥).") + } + vulnLibFilterOrError match { + case Left(vulnLibFilter) => + resultsFuture flatMap { allResults => + select(allResults, selector).fold(Future.successful(NotFound(Json.obj("error" -> "not found")))) { selection => + val reports = selection.result + if (reports.failedProjects.nonEmpty && strict) { + Future.successful(InternalServerError(Json.obj("error" -> "I don't have all results I need."))) + } else { + Future.successful(Ok(Json.toJson(Map( + "all" -> reports.groupedDependencies.size, + "vulnerable" -> reports.vulnerableDependencies.count(vulnLibFilter) + )))) + } + } + } + case Right(error) => Future.successful(BadRequest(Json.obj("error" -> error))) + } + } + } + diff --git a/conf/routes b/conf/routes index 1d6f56b..a6f1bb9 100644 --- a/conf/routes +++ b/conf/routes @@ -4,6 +4,7 @@ # Home page GET / controllers.Application.homepage() +GET /api/stats/libraries/count.json controllers.Statistics.librariesCountApi(selector: Option[String], operator: Option[String], threshold: Option[Double], strict: Boolean) GET /api/table controllers.Statistics.table() GET /api/all-dependencies.json controllers.Statistics.allDependencies(selector: Option[String]) GET /api/all-dependencies-verbose.json controllers.Statistics.allDependenciesVerbose(selector: Option[String])