Skip to content

Commit

Permalink
Fixes #24099: Add a select type for technique parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
VinceMacBuche committed Jan 29, 2024
1 parent 39283a0 commit 63f5371
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ import com.normation.rudder.ncf.Constraint.CheckResult
import com.normation.rudder.ncf.Constraint.Constraint
import java.util.regex.Pattern
import zio.ZIO
import zio.json.SnakeCase
import zio.json.jsonDiscriminator
import zio.json.jsonHint
import zio.json.jsonMemberNames

sealed trait NcfId {
def value: String
Expand Down Expand Up @@ -196,7 +198,8 @@ final case class TechniqueParameter(
name: String,
description: String,
documentation: Option[String],
mayBeEmpty: Boolean
mayBeEmpty: Boolean,
constraints: Option[Constraints]
)

object ParameterType {
Expand Down Expand Up @@ -276,6 +279,17 @@ object ParameterType {
}
}

@jsonMemberNames(SnakeCase)
case class Constraints(
allowEmptyString: Option[Boolean],
allowWhiteSpaceString: Option[Boolean],
minLength: Option[Int],
maxLength: Option[Int],
regex: Option[String],
notRegex: Option[String],
select: Option[List[String]]
)

object Constraint {
sealed trait Constraint {
def check(value: String): CheckResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class TechniqueSerializer(parameterTypeService: ParameterTypeService) {
implicit val encoderMethodElem: JsonEncoder[MethodElem] = DeriveJsonEncoder.gen
implicit val encoderTechniqueParameterType: JsonEncoder[ParameterType.ParameterType] =
JsonEncoder[String].contramap(s => parameterTypeService.value(s).getOrElse(s.toString))
implicit val encoderConstraints: JsonEncoder[Constraints] = DeriveJsonEncoder.gen
implicit val encoderTechniqueParameter: JsonEncoder[TechniqueParameter] = DeriveJsonEncoder.gen
implicit val encoderResourceFileState: JsonEncoder[ResourceFileState] = JsonEncoder[String].contramap(_.value)
implicit val encoderResourceFile: JsonEncoder[ResourceFile] = DeriveJsonEncoder.gen
Expand All @@ -83,6 +84,7 @@ class TechniqueSerializer(parameterTypeService: ParameterTypeService) {
case Left(err) => Left(err.fullMsg)
case Right(r) => Right(r)
})
implicit val decoderConstraints: JsonDecoder[Constraints] = DeriveJsonDecoder.gen
implicit val decoderTechniqueParameter: JsonDecoder[TechniqueParameter] = DeriveJsonDecoder.gen
implicit val decoderMethodElem: JsonDecoder[MethodElem] = DeriveJsonDecoder.gen
implicit val decoderResourceFileState: JsonDecoder[ResourceFileState] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ object MigrateJsonTechniquesService {
desc,
doc,
oldTechnique.parameter.map(p =>
TechniqueParameter(ParameterId(p.id), canonify(p.name), p.name, Some(p.description), p.mayBeEmpty)
TechniqueParameter(ParameterId(p.id), canonify(p.name), p.name, Some(p.description), p.mayBeEmpty, None)
),
oldTechnique.resources.flatMap(s => ResourceFileState.parse(s.state).map(ResourceFile(s.name, _)).toSeq),
Map(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@ case class TechniqueParameter(
constraints: Constraints
)

case class Constraints(
allow_empty: Option[Boolean]
)

object YamlTechniqueSerializer {
implicit val encoderParameterId: JsonEncoder[ParameterId] = JsonEncoder[String].contramap(_.value)
implicit val encoderFieldParameterId: JsonFieldEncoder[ParameterId] = JsonFieldEncoder[String].contramap(_.value)
Expand Down Expand Up @@ -223,7 +219,9 @@ object YamlTechniqueSerializer {
techniqueParameter.name,
techniqueParameter.description,
techniqueParameter.documentation,
Constraints(allow_empty = Some(techniqueParameter.mayBeEmpty))
techniqueParameter.constraints
.getOrElse(Constraints(None, None, None, None, None, None, None))
.copy(allowEmptyString = Some(techniqueParameter.mayBeEmpty))
)
}

Expand All @@ -233,7 +231,8 @@ object YamlTechniqueSerializer {
techniqueParameter.name,
techniqueParameter.description,
techniqueParameter.documentation,
techniqueParameter.constraints.allow_empty.getOrElse(false)
techniqueParameter.constraints.allowEmptyString.getOrElse(false),
Some(techniqueParameter.constraints)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,8 @@ class TestEditorTechniqueWriter extends Specification with ContentMatchers with
"technique parameter",
Some(" a long description, with line \n break within"),
// we must ensure that it will lead to: [parameter(Mandatory=$false)]
true
true,
None
) :: Nil,
Nil,
Map(),
Expand Down Expand Up @@ -661,7 +662,8 @@ class TestEditorTechniqueWriter extends Specification with ContentMatchers with
"version",
"package version",
Some("Package version to install"),
false
false,
None
) :: Nil,
Nil,
Map(),
Expand Down Expand Up @@ -752,7 +754,8 @@ class TestEditorTechniqueWriter extends Specification with ContentMatchers with
"my_custom_condition",
"my custom condition",
None,
false
false,
None
) :: Nil,
Nil,
Map(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ update msg model =

newValidation =
List.foldl ( \param val ->
accumulateErrorConstraint param (Maybe.withDefault [] (Dict.get param.id.value constraints)) val
accumulateErrorConstraint param (Maybe.withDefault defaultConstraint (Dict.get param.id.value constraints)) val
) b.validation realCall.parameters

in
Expand Down Expand Up @@ -497,7 +497,7 @@ update msg model =
case model.mode of
TechniqueDetails t o ui editInfo->
let
parameters = List.append t.parameters [ TechniqueParameter paramId "" "" Nothing False ]
parameters = List.append t.parameters [ TechniqueParameter paramId "" "" Nothing False defaultConstraint]
in
TechniqueDetails { t | parameters = parameters } o ui editInfo
_ -> model.mode
Expand Down Expand Up @@ -771,8 +771,8 @@ update msg model =

calls = updateElemIf (getId >> (==) call.id ) (updateParameter paramId newValue) t.elems
constraints = case Dict.get call.methodName.value model.methods of
Just m -> Maybe.withDefault [] (Maybe.map (.constraints) (List.Extra.find (.name >> (==) paramId) m.parameters))
Nothing -> []
Just m -> Maybe.withDefault defaultConstraint (Maybe.map (.constraints) (List.Extra.find (.name >> (==) paramId) m.parameters))
Nothing -> defaultConstraint

updateCallUi = \optCui ->
let
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,23 @@ type alias Draft = { technique : Technique, origin : Maybe Technique, id : Strin

type AgentValue = Value String | Variable (List AgentValue)

type Constraint =
AllowEmpty Bool
| AllowWhiteSpace Bool
| MaxLength Int
| MinLength Int
| MatchRegex String
| NotMatchRegex String
| Select (List String)
type alias Constraint =
{ allowEmpty : Maybe Bool
, allowWhiteSpace: Maybe Bool
, maxLength: Maybe Int
, minLength: Maybe Int
, matchRegex: Maybe String
, notMatchRegex: Maybe String
, select: Maybe (List String)
}

defaultConstraint = Constraint Nothing Nothing Nothing Nothing Nothing Nothing Nothing

type alias MethodParameter =
{ name : ParameterId
, description : String
, type_ : String
, constraints : List Constraint
, constraints : Constraint
}

type Agent = Cfengine | Dsc
Expand Down Expand Up @@ -112,12 +115,15 @@ type alias CallParameter =
, value : List AgentValue
}

type ParameterType = StringParameter | SelectParameter (List String)

type alias TechniqueParameter =
{ id : ParameterId
, name : String
, description : String
, documentation : Maybe String
, mayBeEmpty : Bool
, constraints : Constraint
}

type alias TechniqueCategory =
Expand Down Expand Up @@ -217,7 +223,6 @@ type alias TechniqueUiInfo =
, nameState : ValidationState TechniqueNameError
, idState : ValidationState TechniqueIdError
, enableDragDrop : Maybe CallId

}

type alias TechniqueEditInfo =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ decodeTechniqueParameter =
|> required "id" (map ParameterId string)
|> required "name" string
|> required "description" string
|> optional "documentation" (maybe string) Nothing
|> required "documentation" (maybe string)
|> optional "mayBeEmpty" bool False
|> optional "constraints" decodeConstraint defaultConstraint

decodeCallParameter : List (String, List AgentValue) -> List CallParameter
decodeCallParameter params =
Expand Down Expand Up @@ -155,44 +156,16 @@ decodeAgent =
_ -> fail (v ++ " is not a valid agent")
) string

decodeConstraint: Decoder (List Constraint)
decodeConstraint: Decoder Constraint
decodeConstraint =
andThen ( \v ->
List.foldl (\val acc ->
case val of
("allow_empty_string", value) ->
case decodeValue bool value of
Ok b -> andThen (\t -> succeed (AllowEmpty b :: t) ) acc
Err e-> fail (errorToString e)
("allow_whitespace_string", value) ->
case decodeValue bool value of
Ok b -> andThen (\t -> succeed (AllowWhiteSpace b :: t) ) acc
Err e-> fail (errorToString e)
("max_length", value) ->
case decodeValue int value of
Ok b -> andThen (\t -> succeed (MaxLength b :: t) ) acc
Err e-> fail (errorToString e)
("min_length", value) ->
case decodeValue int value of
Ok b -> andThen (\t -> succeed (MinLength b :: t) ) acc
Err e-> fail (errorToString e)
("regex", value) ->
case decodeValue string value of
Ok b -> andThen (\t -> succeed (MatchRegex b :: t) ) acc
Err e-> fail (errorToString e)
("not_regex", value) ->
case decodeValue string value of
Ok b -> andThen (\t -> succeed (NotMatchRegex b :: t) ) acc
Err e-> fail (errorToString e)
("select", value) ->
case decodeValue (list string) value of
Ok b -> andThen (\t -> succeed (Select b :: t) ) acc
Err e-> fail (errorToString e)
_ -> acc

) (succeed []) v

) (keyValuePairs value)
succeed Constraint
|> optional "allow_empty_string" (maybe bool) Nothing
|> optional "allow_whitespace_string" (maybe bool) Nothing
|> optional "max_length" (maybe int) Nothing
|> optional "min_length" (maybe int) Nothing
|> optional "regex" (maybe string) Nothing
|> optional "not_regex" (maybe string) Nothing
|> optional "select" (maybe (list string)) Nothing

decodeMethodParameter: Decoder MethodParameter
decodeMethodParameter =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,37 @@ encodeResource resource =
)
]

encodeTechniqueConstraint : Constraint -> Value
encodeTechniqueConstraint constraint =
let
allowEmpty = constraint.allowEmpty |> Maybe.map ( \v -> [ ("allow_empty_string", bool v) ]) |> Maybe.withDefault []
allowWp = constraint.allowWhiteSpace |> Maybe.map ( \v -> [ ("allow_whitespace_string", bool v) ]) |> Maybe.withDefault []
max = constraint.maxLength |> Maybe.map ( \v -> [ ("max_length", int v) ]) |> Maybe.withDefault []
min = constraint.minLength |> Maybe.map ( \v -> [ ("min_length", int v) ]) |> Maybe.withDefault []
regex = constraint.matchRegex |> Maybe.map ( \v -> [ ("regex", string v) ]) |> Maybe.withDefault []
notRegex = constraint.notMatchRegex |> Maybe.map ( \v -> [ ("not_regex", string v) ]) |> Maybe.withDefault []
select = constraint.select |> Maybe.map ( \v -> [ ("select", list string v) ]) |> Maybe.withDefault []
in
object (List.concat [ allowEmpty, allowWp, max, min, regex, notRegex, select ])


encodeTechniqueParameters: TechniqueParameter -> Value
encodeTechniqueParameters param =
let
doc = ( case param.documentation of
Nothing -> []
Just s -> [ ( "documentation", string s)]
)
doc = case param.documentation of
Nothing -> []
Just s -> [ ( "documentation", string s)]
constraint = if (param.constraints == defaultConstraint) then
[]
else
[ ("constraints", encodeTechniqueConstraint param.constraints) ]
base = [ ("id" , string param.id.value)
, ("name" , string (if (String.isEmpty param.name) then (canonifyString param.description) else param.name))
, ("description", string param.description)
, ("mayBeEmpty" , bool param.mayBeEmpty)
]
in
object (List.append base doc )
object (List.concat [ base, doc, constraint ] )


appendPolicyMode: Maybe PolicyMode -> List (String, Value) -> Value
Expand Down

0 comments on commit 63f5371

Please sign in to comment.