Dependancy between flags

This commit is contained in:
nemunaire 2018-12-02 19:21:07 +01:00
commit f9abdd23c6
8 changed files with 111 additions and 1 deletions

View file

@ -18,6 +18,7 @@ Tous les textes doivent utiliser l'encodage UTF8.
* `id = CHID` : identifiant du challenge ;
* `theme = "NomDuTheme"` : (facultatif) nom du thème dans lequel aller chercher l'identifiant (par défaut, on prend le thème courant) ;
- `[[flag]]` : drapeau classique à valider pour résoudre le challenge :
* `id = 42` : (facultatif) identifiant du flag au sein de l'exercice, pour définir des dépendances ;
* `label = "Intitulé"` : (facultatif, par défaut : `Flag`) intitulé du drapeau ;
* `raw = 'MieH2athxuPhai6u'` : drapeau exact à trouver ;
* `validator_regexp = "^(?:sudo +)?(.*)$"` : (facultatif) expression rationnelle dont les groupes capturés serviront comme chaîne à valider (notez que `?:` au début d'un groupe ne le capturera pas) ;
@ -25,6 +26,8 @@ Tous les textes doivent utiliser l'encodage UTF8.
* `help = "Indication"` : (facultatif) chaîne de caractères placée sous le champ du formulaire, idéale pour donner une indication de format ;
* `[[flag.unlock_file]]` : bloque l'accès à un fichier tant que le flag n'est pas obtenu :
+ `filename = "toto.txt"` : nom du fichier tel qu'il apparaît dans le dossier `files` ;
* `[[flag.need_flag]]` : liste des flags devant être validés avant de débloquer celui-ci :
+ `id = 23` : identifiant du flag tel qu'il a été défini plus tôt dans le fichier ;
- `[[flag_mcq]]` : drapeau sous forme de question à choix multiple (cases à cocher) :
* `label = "Intitulé du groupe"` : (facultatif) intitulé du groupe de choix ;
* `[[flag_mcq.choice]]` : représente un choix, répétez autant de fois qu'il y a de choix :
@ -32,6 +35,7 @@ Tous les textes doivent utiliser l'encodage UTF8.
+ `value = true` : (facultatif, par défaut `false`) valeur attendue pour ce choix ; pour un QCM justifié, utilisez une chaîne de caractères (notez qu'il n'est pas possible de combiner des réponses vraies justifiées et justifiées),
+ `help = "Flag correspondant"` : (facultatif) indication affichée dans le champ de texte des QCM justifiés ;
- `[[flag_ucq]]` : drapeau sous forme de question à choix unique :
* `id = 42` : (facultatif) identifiant du flag au sein de l'exercice, pour définir des dépendances ;
* `label = "Intitulé du groupe"` : (facultatif) intitulé du groupe de choix ;
* `raw = 'MieH2athxuPhai6u'` : drapeau attendu parmi les propositions ;
* `validator_regexp = "^(?:sudo +)?(.*)$"` : (facultatif) expression rationnelle dont les groupes capturés serviront comme chaîne à valider (notez que `?:` au début d'un groupe ne le capturera pas) ;
@ -43,6 +47,8 @@ Tous les textes doivent utiliser l'encodage UTF8.
+ `label = "Intitulé de la réponse"` : (facultatif, par défaut identique à `value`) ;
* `[[flag_ucq.unlock_file]]` : bloque l'accès à un fichier tant que le flag n'est pas obtenu :
+ `filename = "toto.txt"` : nom du fichier tel qu'il apparaît dans le dossier `files` ;
* `[[flag_ucq.need_flag]]` : liste des flags devant être validés avant de débloquer celui-ci :
+ `id = 23` : identifiant du flag tel qu'il a été défini plus tôt dans le fichier ;
- `[[hint]]` : paramètres pour un indice :
* `filename = "toto.txt"` : (mutuellement exclusif avec `content`) nom du fichier tel qu'il apparaît dans le dossier `hints` ;
* `content = "Contenu de l'indice"` : (mutuellement exclusif avec `filename`) contenu de l'indice affiché, en markdown ;

View file

@ -27,12 +27,14 @@ type ExerciceUnlockFile struct {
// ExerciceFlag holds informations about a "classic" flag.
type ExerciceFlag struct {
Id int64
Label string `toml:",omitempty"`
Raw string
IgnoreCase bool `toml:",omitempty"`
ValidatorRe string `toml:"validator_regexp,omitempty"`
Help string `toml:",omitempty"`
LockedFile []ExerciceUnlockFile `toml:"unlock_file,omitempty"`
NeedFlag []ExerciceDependency `toml:"need_flag,omitempty"`
}
// ExerciceFlagMCQChoice holds a choice for an MCQ flag.
@ -57,6 +59,7 @@ type ExerciceFlagUCQChoice struct {
// ExerciceFlagUCQ holds information about a UCQ flag.
type ExerciceFlagUCQ struct {
Id int64
Label string `toml:",omitempty"`
Raw string
IgnoreCase bool `toml:",omitempty"`
@ -66,6 +69,7 @@ type ExerciceFlagUCQ struct {
Choices_Cost int64 `toml:",omitempty"`
Choice []ExerciceFlagUCQChoice
LockedFile []ExerciceUnlockFile `toml:"unlock_file,omitempty"`
NeedFlag []ExerciceDependency `toml:"need_flag,omitempty"`
NoShuffle bool
}

View file

@ -40,6 +40,8 @@ func SyncExerciceFlags(i Importer, exercice fic.Exercice) (errs []string) {
} else if len(params.Flags) == 0 && len(params.FlagsUCQ) == 0 && len(params.FlagsMCQ) == 0 {
errs = append(errs, fmt.Sprintf("%q: has no flag", path.Base(exercice.Path)))
} else {
kmap := map[int64]fic.Flag{}
// Import normal flags
for nline, flag := range params.Flags {
if len(flag.Label) == 0 {
@ -54,6 +56,21 @@ func SyncExerciceFlags(i Importer, exercice fic.Exercice) (errs []string) {
errs = append(errs, fmt.Sprintf("%q: error flag #%d: %s", path.Base(exercice.Path), nline + 1, err))
continue
} else {
if flag.Id != 0 {
kmap[flag.Id] = k
}
// Import dependency to flag
for _, nf := range flag.NeedFlag {
if rf, ok := kmap[nf.Id]; !ok {
errs = append(errs, fmt.Sprintf("%q: error flag #%d dependency to flag id=%s: id not defined, perhaps not available at time of processing", path.Base(exercice.Path), nline + 1, nf.Id))
continue
} else if err := k.AddDepend(rf); err != nil {
errs = append(errs, fmt.Sprintf("%q: error flag #%d dependency to %s: %s", path.Base(exercice.Path), nline + 1, nf.Id, err))
continue
}
}
// Import dependency to file
for _, lf := range flag.LockedFile {
if rf, err := exercice.GetFileByFilename(lf.Filename); err != nil {
@ -81,6 +98,22 @@ func SyncExerciceFlags(i Importer, exercice fic.Exercice) (errs []string) {
errs = append(errs, fmt.Sprintf("%q: error flag UCQ #%d: %s", path.Base(exercice.Path), nline + 1, err))
continue
} else {
// Import dependency to file
if flag.Id != 0 {
kmap[flag.Id] = k
}
// Import dependency to flag
for _, nf := range flag.NeedFlag {
if rf, ok := kmap[nf.Id]; !ok {
errs = append(errs, fmt.Sprintf("%q: error flag #%d dependency to flag id=%s: id not defined, perhaps not available at time of processing", path.Base(exercice.Path), nline + 1, nf.Id))
continue
} else if err := k.AddDepend(rf); err != nil {
errs = append(errs, fmt.Sprintf("%q: error flag #%d dependency to %s: %s", path.Base(exercice.Path), nline + 1, nf.Id, err))
continue
}
}
// Import dependency to file
for _, lf := range flag.LockedFile {
if rf, err := exercice.GetFileByFilename(lf.Filename); err != nil {