Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #24099: Add a select type for technique parameter #5362

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,19 @@ object ParameterType {
}
}

case class SelectOption(value: String, name: Option[String])

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

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,8 @@ 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 encoderSelectOption: JsonEncoder[SelectOption] = DeriveJsonEncoder.gen
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 +85,8 @@ class TechniqueSerializer(parameterTypeService: ParameterTypeService) {
case Left(err) => Left(err.fullMsg)
case Right(r) => Right(r)
})
implicit val decoderSelectOption: JsonDecoder[SelectOption] = DeriveJsonDecoder.gen
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,16 +97,13 @@ 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)
implicit val encoderBundleName: JsonEncoder[BundleName] = JsonEncoder[String].contramap(_.value)
implicit val encoderVersion: JsonEncoder[Version] = JsonEncoder[String].contramap(_.value)
implicit val encoderReporting: JsonEncoder[Reporting] = DeriveJsonEncoder.gen
implicit val encoderSelectOption: JsonEncoder[SelectOption] = DeriveJsonEncoder.gen
implicit val encoderConstraints: JsonEncoder[Constraints] = DeriveJsonEncoder.gen
implicit val encoderPolicyMode: JsonEncoder[PolicyMode] = JsonEncoder[String].contramap(_.name)
implicit lazy val encoderMethodElem: JsonEncoder[MethodItem] = DeriveJsonEncoder.gen
Expand All @@ -119,6 +116,8 @@ object YamlTechniqueSerializer {
implicit val decoderFieldParameterId: JsonFieldDecoder[ParameterId] = JsonFieldDecoder[String].map(ParameterId.apply)
implicit val decoderVersion: JsonDecoder[Version] = JsonDecoder[String].map(s => new Version(s))
implicit val decoderReporting: JsonDecoder[Reporting] = DeriveJsonDecoder.gen
implicit val decoderSelectOption: JsonDecoder[SelectOption] =
JsonDecoder[String].map(SelectOption(_, None)).orElse(DeriveJsonDecoder.gen)
implicit val decoderConstraints: JsonDecoder[Constraints] = DeriveJsonDecoder.gen
implicit val decoderTechniqueParameter: JsonDecoder[TechniqueParameter] = DeriveJsonDecoder.gen
implicit val decoderPolicyMode: JsonDecoder[PolicyMode] = JsonDecoder[String].mapOrFail(PolicyMode.parse(_) match {
Expand Down Expand Up @@ -223,7 +222,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(allowEmpty = Some(techniqueParameter.mayBeEmpty))
)
}

Expand All @@ -233,7 +234,8 @@ object YamlTechniqueSerializer {
techniqueParameter.name,
techniqueParameter.description,
techniqueParameter.documentation,
techniqueParameter.constraints.allow_empty.getOrElse(false)
techniqueParameter.constraints.allowEmpty.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,28 @@ 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 SelectOption)
}

type alias SelectOption =
{ value : String
, name : Maybe 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 +120,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 +228,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 @@ -27,6 +27,7 @@ decodeTechniqueParameter =
|> required "description" string
|> optional "documentation" (maybe string) Nothing
|> optional "mayBeEmpty" bool False
|> optional "constraints" decodeConstraint defaultConstraint

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

decodeConstraint: Decoder (List 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
decoderSelectOption : Decoder SelectOption
decoderSelectOption =
oneOf [ map (\s ->SelectOption s Nothing) string
, succeed SelectOption
|> required "value" string
|> optional "name" (maybe string) Nothing
]

) (keyValuePairs value)
decodeConstraint: Decoder Constraint
decodeConstraint =
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 decoderSelectOption)) Nothing

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

encodeSelectOption : SelectOption -> Value
encodeSelectOption option =
object [
("value", string option.value)
, ("name", string (Maybe.withDefault option.value option.name))
]


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 encodeSelectOption 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
Loading