Skip to content

Commit

Permalink
fixup! Fixes #22338: Refactor some code and changes API url for compl…
Browse files Browse the repository at this point in the history
…iance by directive

Fixes #22338: Refactor some code and changes API url for compliance by directive
  • Loading branch information
VinceMacBuche committed Mar 6, 2023
1 parent 4664db2 commit c36ee28
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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))
Expand Down Expand Up @@ -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))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit c36ee28

Please sign in to comment.