From 6e7de4332fa765df0121b1dc7dcaa0c4a845931a Mon Sep 17 00:00:00 2001 From: Clark Andrianasolo Date: Fri, 19 Apr 2024 18:30:36 +0200 Subject: [PATCH] Work in progress --- .../rudder/apidata/JsonResponseObjects.scala | 78 ++++++++++++++++++- .../rudder/rest/EndpointsDefinition.scala | 17 ++++ .../rest/internal/GroupsInternalAPI.scala | 43 ++++++++++ .../src/main/elm/sources/Groups/DataTypes.elm | 1 - .../main/elm/sources/Groups/JsonDecoder.elm | 2 - 5 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/internal/GroupsInternalAPI.scala diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/apidata/JsonResponseObjects.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/apidata/JsonResponseObjects.scala index da2e2fea9f2..7856856922a 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/apidata/JsonResponseObjects.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/apidata/JsonResponseObjects.scala @@ -67,6 +67,7 @@ import com.normation.rudder.ncf.ResourceFile import com.normation.rudder.ncf.TechniqueParameter import com.normation.rudder.repository.FullActiveTechnique import com.normation.rudder.repository.FullActiveTechniqueCategory +import com.normation.rudder.repository.FullNodeGroupCategory import com.normation.rudder.rule.category.RuleCategory import com.normation.rudder.rule.category.RuleCategoryId import com.normation.rudder.services.queries.CmdbQueryParser @@ -76,6 +77,7 @@ import com.normation.utils.DateFormaterService import com.softwaremill.quicklens.* import com.typesafe.config.ConfigRenderOptions import com.typesafe.config.ConfigValue +import io.scalaland.chimney.Transformer import io.scalaland.chimney.dsl.* import zio.* import zio.Tag as _ @@ -477,6 +479,21 @@ object JsonResponseObjects { override def toRuleTarget: TargetComposition = TargetUnion(list.map(_.toRuleTarget).toSet) } } + + implicit val transformer: Transformer[RuleTarget, JRRuleTarget] = apply _ + } + + final case class JRRuleTargetInfo( + id: JRRuleTarget, + @jsonField("displayName") name: String, + description: String, + @jsonField("enabled") isEnabled: Boolean, + target: JRRuleTarget + ) + + object JRRuleTargetInfo { + implicit val transformer: Transformer[RuleTargetInfo, JRRuleTargetInfo] = + Transformer.define[RuleTargetInfo, JRRuleTargetInfo].withFieldRenamed(_.target, _.id).buildTransformer } // CategoryKind is either JRRuleCategory or String (category id) @@ -870,6 +887,58 @@ object JsonResponseObjects { } } + /** + * Representation of a group category with bare minimum group information + */ + final case class JRGroupCategoryInfo( + id: String, + name: String, + description: String, + @jsonField("categories") subCategories: List[JRGroupCategoryInfo], + groups: List[JRGroupCategoryInfo.JRGroupInfo], + @jsonField("targets") targetInfos: List[JRRuleTargetInfo] + ) + + object JRGroupCategoryInfo { + final case class JRGroupInfo( + id: NodeGroupId, + displayName: String, + description: String, + category: Option[String], + dynamic: Boolean, + enabled: Boolean, + target: String + ) + object JRGroupInfo { + def apply(nodeGroupCategory: NodeGroupCategoryId, fullGroupTarget: FullGroupTarget): JRGroupInfo = { + JRGroupInfo( + fullGroupTarget.nodeGroup.id, + fullGroupTarget.nodeGroup.name, + fullGroupTarget.nodeGroup.description, + Some(nodeGroupCategory.value), + fullGroupTarget.nodeGroup.isDynamic, + fullGroupTarget.nodeGroup.isEnabled, + fullGroupTarget.target.target + ) + } + + } + + implicit lazy val transformer: Transformer[FullNodeGroupCategory, JRGroupCategoryInfo] = { + Transformer + .define[FullNodeGroupCategory, JRGroupCategoryInfo] + .withFieldComputed( + _.groups, + _.allCategories.toList.flatMap { + case (catId, groups) => + groups.allGroups.values.map(JRGroupInfo(catId, _)) + } + ) + .withFieldComputed(_.targetInfos, _.targetInfos.map(_.toTargetInfo.transformInto[JRRuleTargetInfo])) + .buildTransformer + } + } + final case class JRRuleNodesDirectives( id: String, // id is in format uid+rev @@ -923,7 +992,10 @@ trait RudderJsonEncoders { } } - implicit val ruleIdEncoder: JsonEncoder[RuleId] = JsonEncoder[String].contramap(_.serialize) + implicit val ruleTargetInfoEncoder: JsonEncoder[JRRuleTargetInfo] = DeriveJsonEncoder.gen[JRRuleTargetInfo] + + implicit val ruleIdEncoder: JsonEncoder[RuleId] = JsonEncoder[String].contramap(_.serialize) + implicit val groupIdEncoder: JsonEncoder[NodeGroupId] = JsonEncoder[String].contramap(_.serialize) implicit val applicationStatusEncoder: JsonEncoder[JRApplicationStatus] = DeriveJsonEncoder.gen @@ -997,6 +1069,10 @@ trait RudderJsonEncoders { implicit val groupEncoder: JsonEncoder[JRGroup] = DeriveJsonEncoder.gen implicit val objectInheritedObjectProperties: JsonEncoder[JRGroupInheritedProperties] = DeriveJsonEncoder.gen + implicit val groupInfoEncoder: JsonEncoder[JRGroupCategoryInfo.JRGroupInfo] = + DeriveJsonEncoder.gen[JRGroupCategoryInfo.JRGroupInfo] + implicit lazy val groupCategoryInfoEncoder: JsonEncoder[JRGroupCategoryInfo] = DeriveJsonEncoder.gen[JRGroupCategoryInfo] + implicit val revisionInfoEncoder: JsonEncoder[JRRevisionInfo] = DeriveJsonEncoder.gen } 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 3ef6469cba2..39b2c76104f 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 @@ -817,6 +817,23 @@ object RuleInternalApi extends Enum[RuleInternalApi] with ApiModuleProvide def values = findValues } +sealed trait GroupInternalApi extends EnumEntry with EndpointSchema with InternalApi with SortIndex { + override def dataContainer: Option[String] = Some("groupsinternal") +} + +object GroupInternalApi extends Enum[GroupInternalApi] with ApiModuleProvider[GroupInternalApi] { + final case object GetGroupCategoryTree extends GroupInternalApi with ZeroParam with StartsAtVersion14 with SortIndex { + val z: Int = implicitly[Line].value + val description = "Get the tree of groups with bare minimum group information" + val (action, path) = GET / "groupsinternal" / "categorytree" / "{id}" + override def dataContainer: Option[String] = None + } + + def endpoints: List[GroupInternalApi] = values.toList.sortBy(_.z) + + def values = findValues +} + sealed trait ScoreApi extends EnumEntry with EndpointSchema with InternalApi with SortIndex { override def dataContainer: Option[String] = Some("scores") } diff --git a/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/internal/GroupsInternalAPI.scala b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/internal/GroupsInternalAPI.scala new file mode 100644 index 00000000000..61718d87c6c --- /dev/null +++ b/webapp/sources/rudder/rudder-rest/src/main/scala/com/normation/rudder/rest/internal/GroupsInternalAPI.scala @@ -0,0 +1,43 @@ +package com.normation.rudder.rest.internal + +import com.normation.errors.IOResult +import com.normation.rudder.api.ApiVersion +import com.normation.rudder.apidata.JsonResponseObjects.* +import com.normation.rudder.apidata.implicits.* +import com.normation.rudder.repository.RoNodeGroupRepository +import com.normation.rudder.rest.ApiModuleProvider +import com.normation.rudder.rest.ApiPath +import com.normation.rudder.rest.AuthzToken +import com.normation.rudder.rest.GroupInternalApi as API +import com.normation.rudder.rest.implicits.* +import com.normation.rudder.rest.lift.* +import io.scalaland.chimney.syntax.* +import net.liftweb.http.LiftResponse +import net.liftweb.http.Req + +class GroupsInternalApi( + readGroup: RoNodeGroupRepository +) extends LiftApiModuleProvider[API] { + + def schemas: ApiModuleProvider[API] = API + + def getLiftEndpoints(): List[LiftApiModule] = { + API.endpoints.map(e => { + e match { + case API.GetGroupCategoryTree => GetGroupCategoryTree + } + }) + } + + object GetGroupCategoryTree extends LiftApiModule0 { + val schema: API.GetGroupCategoryTree.type = API.GetGroupCategoryTree + + def process0(version: ApiVersion, path: ApiPath, req: Req, params: DefaultParams, authzToken: AuthzToken): LiftResponse = { + getGroupCategoryTree().toLiftResponseOne(params, schema, _ => None) + } + } + + def getGroupCategoryTree(): IOResult[JRGroupCategoryInfo] = { + readGroup.getFullGroupLibrary().map(_.transformInto[JRGroupCategoryInfo]) + } +} diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Groups/DataTypes.elm b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Groups/DataTypes.elm index 53a28f01e1c..818573c2b01 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Groups/DataTypes.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Groups/DataTypes.elm @@ -48,7 +48,6 @@ type alias Group = , name : String , description : String , category : Maybe String - , nodeIds : List String , dynamic : Bool , enabled : Bool , target : String diff --git a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Groups/JsonDecoder.elm b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Groups/JsonDecoder.elm index 0e5755b50fe..b1418acc83c 100644 --- a/webapp/sources/rudder/rudder-web/src/main/elm/sources/Groups/JsonDecoder.elm +++ b/webapp/sources/rudder/rudder-web/src/main/elm/sources/Groups/JsonDecoder.elm @@ -52,7 +52,6 @@ decodeGroup = |> required "displayName" string |> required "description" string |> optional "category" (map Just string) Nothing - |> required "nodeIds" (list string) |> required "dynamic" bool |> required "enabled" bool |> required "target" string @@ -64,7 +63,6 @@ decodeTarget = |> required "displayName" string |> required "description" string |> optional "category" (map Just string) Nothing - |> hardcoded [] |> hardcoded True |> required "enabled" bool |> required "target" string