From c36ee28d2e8a1049a28974dda388492c78a970bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Membr=C3=A9?= Date: Mon, 6 Mar 2023 16:15:31 +0100 Subject: [PATCH] fixup! Fixes #22338: Refactor some code and changes API url for compliance by directive Fixes #22338: Refactor some code and changes API url for compliance by directive --- .../rudder/rest/EndpointsDefinition.scala | 7 -- .../rudder/rest/RestExtractorService.scala | 13 +-- .../rudder/rest/RoleApiMapping.scala | 2 +- .../rudder/rest/data/Compliance.scala | 19 ++++ .../normation/rudder/rest/data/RestData.scala | 3 - .../rudder/rest/lift/ComplianceApi.scala | 104 +++++------------- .../directivecompliance/sources/ApiCalls.elm | 4 +- .../sources/JsonDecoder.elm | 4 - 8 files changed, 58 insertions(+), 98 deletions(-) diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/EndpointsDefinition.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/EndpointsDefinition.scala index ccd1b197f50..6e0e6a10715 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/EndpointsDefinition.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/EndpointsDefinition.scala @@ -174,13 +174,6 @@ object ComplianceApi extends ApiModuleProvider[ComplianceApi] { val dataContainer = Some("directivesCompliance") } - final case object ExportDirectiveComplianceCSV extends ComplianceApi with OneParam with StartsAtVersion17 with SortIndex { - val z = implicitly[Line].value - val description = "Get a directive's compliance to CSV format" - val (action, path) = GET / "compliance" / "directives" / "{id}" - val dataContainer = Some("directiveComplianceExportCSV") - } - def endpoints = ca.mrvisser.sealerate.values[ComplianceApi].toList.sortBy(_.z) } diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RestExtractorService.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RestExtractorService.scala index 0c51d453db0..22c95589976 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RestExtractorService.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RestExtractorService.scala @@ -1512,14 +1512,13 @@ final case class RestExtractorService( } - def extractDirectiveComplianceExportFormat(params: Map[String, List[String]]): Box[String] = { + def extractComplianceFormat(params: Map[String, List[String]]): Box[ComplianceFormat] = { params.get("format") match { - case None | Some(Nil) => Full("csv") // by default if no there is no format, should I choose the only one available ? - case Some(format :: tail) => // only take into account the first format param if several are passed - format.toLowerCase() match { - case "csv" => Full("csv") - case _ => Failure(s"Value of export format for compliance by directive should be CSV instead of ${format}") - } + case None | Some(Nil) | Some("" :: Nil) => + Full(ComplianceFormat.JSON) // by default if no there is no format, should I choose the only one available ? + case Some(format :: _) => + ComplianceFormat.fromValue(format).toBox } } + } diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RoleApiMapping.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RoleApiMapping.scala index ed6095b6508..3825532ae03 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RoleApiMapping.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/RoleApiMapping.scala @@ -122,7 +122,7 @@ object AuthorizationApiMapping { case Compliance.Read => ComplianceApi.GetGlobalCompliance.x :: ComplianceApi.GetRulesCompliance.x :: ComplianceApi.GetRulesComplianceId.x :: ComplianceApi.GetNodesCompliance.x :: ComplianceApi.GetNodeComplianceId.x :: ChangesApi.GetRuleRepairedReports.x :: - ChangesApi.GetRecentChanges.x :: ComplianceApi.GetDirectiveComplianceId.x :: ComplianceApi.ExportDirectiveComplianceCSV.x :: + ChangesApi.GetRecentChanges.x :: ComplianceApi.GetDirectiveComplianceId.x :: ComplianceApi.GetDirectivesCompliance.x :: Nil case Compliance.Write => Nil case Compliance.Edit => Nil diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/data/Compliance.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/data/Compliance.scala index a6a63708e5b..2de91e16763 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/data/Compliance.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/data/Compliance.scala @@ -911,3 +911,22 @@ object JsonCompliance { ).filter { case (k, v) => v > 0 }.view.mapValues(percent => percent).toMap } } + +sealed trait ComplianceFormat { + def value: String +} + +object ComplianceFormat { + case object CSV extends ComplianceFormat { val value = "csv" } + case object JSON extends ComplianceFormat { val value = "json" } + def allValues = ca.mrvisser.sealerate.values[ComplianceFormat] + def fromValue(value: String): Either[String, ComplianceFormat] = { + allValues.find(_.value == value) match { + case None => + Left( + s"Wrong type of value for compliance format '${value}', expected : ${allValues.map(_.value).mkString("[", ", ", "]")}" + ) + case Some(action) => Right(action) + } + } +} diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/data/RestData.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/data/RestData.scala index c567440589f..06463edf058 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/data/RestData.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/data/RestData.scala @@ -245,9 +245,6 @@ final case object AcceptNode extends NodeStatusAction final case object RefuseNode extends NodeStatusAction final case object DeleteNode extends NodeStatusAction -sealed trait ExportFormat -final case object CSV extends ExportFormat - final case class RestParameter( value: Option[ConfigValue] = None, description: Option[String] = None, diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/lift/ComplianceApi.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/lift/ComplianceApi.scala index 5ff4203df1a..7d1e6e5354d 100644 --- a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/lift/ComplianceApi.scala +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/lift/ComplianceApi.scala @@ -68,6 +68,7 @@ import com.normation.rudder.services.reports.ReportingService import com.normation.zio.currentTimeMillis import net.liftweb.common._ import net.liftweb.http.LiftResponse +import net.liftweb.http.PlainTextResponse import net.liftweb.http.Req import net.liftweb.json._ import net.liftweb.json.JsonDSL._ @@ -97,14 +98,13 @@ class ComplianceApi( API.endpoints .map(e => { e match { - case API.GetRulesCompliance => GetRules - case API.GetRulesComplianceId => GetRuleId - case API.GetNodesCompliance => GetNodes - case API.GetNodeComplianceId => GetNodeId - case API.GetGlobalCompliance => GetGlobal - case API.GetDirectiveComplianceId => GetDirectiveId - case API.GetDirectivesCompliance => GetDirectives - case API.ExportDirectiveComplianceCSV => ExportCSV + case API.GetRulesCompliance => GetRules + case API.GetRulesComplianceId => GetRuleId + case API.GetNodesCompliance => GetNodes + case API.GetNodeComplianceId => GetNodeId + case API.GetGlobalCompliance => GetGlobal + case API.GetDirectiveComplianceId => GetDirectiveId + case API.GetDirectivesCompliance => GetDirectives } }) .toList @@ -194,44 +194,6 @@ class ComplianceApi( } } - object ExportCSV extends LiftApiModule { - val schema = API.ExportDirectiveComplianceCSV - val restExtractor = restExtractorService - def process( - version: ApiVersion, - path: ApiPath, - directiveId: String, - req: Req, - params: DefaultParams, - authzToken: AuthzToken - ): LiftResponse = { - implicit val action = schema.name - implicit val prettify = params.prettify - - (for { - level <- restExtractor.extractComplianceLevel(req.params) - t1 = System.currentTimeMillis - // if there is no format CSV format is used by default, if the format is wrong, it should be an error - format <- restExtractor.extractDirectiveComplianceExportFormat(req.params) - id <- DirectiveId.parse(directiveId).toBox - t2 = System.currentTimeMillis - _ = TimingDebugLogger.trace(s"API ExportDirectiveComplianceCSV - getting query param in ${t2 - t1} ms") - directive <- complianceService.getDirectiveCompliance(id, level) - t3 = System.currentTimeMillis - _ = TimingDebugLogger.trace(s"API ExportDirectiveComplianceCSV - getting directive compliance in ${t3 - t2} ms") - } yield { - directive.toCsv - }) match { - case Full(csv) => - toJsonResponse(None, ("directiveComplianceExportCSV" -> csv.mkString("\n"))) - - case eb: EmptyBox => - val message = (eb ?~ (s"Could not export to CSV compliance for directive '${directiveId}'")).messageChain - toJsonError(None, JString(message)) - } - } - } - object GetDirectiveId extends LiftApiModule { val schema = API.GetDirectiveComplianceId val restExtractor = restExtractorService @@ -245,34 +207,32 @@ class ComplianceApi( ): LiftResponse = { implicit val action = schema.name implicit val prettify = params.prettify - (for { level <- restExtractor.extractComplianceLevel(req.params) t1 = System.currentTimeMillis precision <- restExtractor.extractPercentPrecision(req.params) + format <- restExtractorService.extractComplianceFormat(req.params) id <- DirectiveId.parse(directiveId).toBox t2 = System.currentTimeMillis _ = TimingDebugLogger.trace(s"API DirectiveCompliance - getting query param in ${t2 - t1} ms") directive <- complianceService.getDirectiveCompliance(id, level) t3 = System.currentTimeMillis _ = TimingDebugLogger.trace(s"API DirectiveCompliance - getting directive compliance '${id.uid.value}' in ${t3 - t2} ms") - } yield { - if (version.value <= 6) { - directive.toJsonV6 - } else { - val json = directive.toJson( - level.getOrElse(10), - precision.getOrElse(CompliancePrecision.Level2) - ) // by default, all details are displayed - val t4 = System.currentTimeMillis - TimingDebugLogger.trace(s"API DirectiveCompliance - serialize to json in ${t4 - t3} ms") - json + format match { + case ComplianceFormat.CSV => + PlainTextResponse(directive.toCsv.mkString("\n")) + case ComplianceFormat.JSON => + val json = directive.toJson( + level.getOrElse(10), + precision.getOrElse(CompliancePrecision.Level2) + ) // by default, all details are displayed + val t4 = System.currentTimeMillis + TimingDebugLogger.trace(s"API DirectiveCompliance - serialize to json in ${t4 - t3} ms") + toJsonResponse(None, ("directiveCompliance" -> json)) } }) match { - case Full(rule) => - toJsonResponse(None, ("directiveCompliance" -> rule)) - + case Full(compliance) => compliance case eb: EmptyBox => val message = (eb ?~ (s"Could not get compliance for directive '${directiveId}'")).messageChain toJsonError(None, JString(message)) @@ -309,19 +269,15 @@ class ComplianceApi( _ = TimingDebugLogger.trace(s"API DirectivesCompliance - getting directives compliance in ${t5 - t4} ms") } yield { - if (version.value <= 6) { - directives.map(_.toJsonV6) - } else { - val json = directives.map( - _.toJson( - level.getOrElse(10), - precision.getOrElse(CompliancePrecision.Level2) - ) - ) // by default, all details are displayed - val t6 = System.currentTimeMillis - TimingDebugLogger.trace(s"API DirectivesCompliance - serialize to json in ${t6 - t5} ms") - json - } + val json = directives.map( + _.toJson( + level.getOrElse(10), + precision.getOrElse(CompliancePrecision.Level2) + ) + ) // by default, all details are displayed + val t6 = System.currentTimeMillis + TimingDebugLogger.trace(s"API DirectivesCompliance - serialize to json in ${t6 - t5} ms") + json }) match { case Full(rule) => toJsonResponse(None, ("directivesCompliance" -> rule)) diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/directivecompliance/sources/ApiCalls.elm b/webapp/sources/rudder/rudder-web/src/main/elm/directivecompliance/sources/ApiCalls.elm index d69333847ed..0dcf911b40a 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/directivecompliance/sources/ApiCalls.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/directivecompliance/sources/ApiCalls.elm @@ -85,9 +85,9 @@ getCSVExport model = request { method = "GET" , headers = [] - , url = getUrl model [ "compliance", "directives", "export", model.directiveId.value ] [] + , url = getUrl model [ "compliance", "directives", model.directiveId.value ] [ Url.Builder.string "format" "csv"] , body = emptyBody - , expect = expectJson Export decodeExportCVS + , expect = expectString Export , timeout = Nothing , tracker = Nothing } diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/directivecompliance/sources/JsonDecoder.elm b/webapp/sources/rudder/rudder-web/src/main/elm/directivecompliance/sources/JsonDecoder.elm index 62eeb6730e6..4fc6c26216e 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/directivecompliance/sources/JsonDecoder.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/directivecompliance/sources/JsonDecoder.elm @@ -19,10 +19,6 @@ decodeGetDirectiveCompliance : Decoder DirectiveCompliance decodeGetDirectiveCompliance = at ["data", "directiveCompliance" ] decodeDirectiveCompliance -decodeExportCVS : Decoder String -decodeExportCVS = - at ["data", "directiveComplianceExportCSV"] string - decodeDirectiveCompliance : Decoder DirectiveCompliance decodeDirectiveCompliance = succeed DirectiveCompliance