2018-01-10 02:45:56 +00:00
|
|
|
package sync
|
|
|
|
|
|
|
|
import (
|
2019-07-05 20:28:56 +00:00
|
|
|
"fmt"
|
2018-01-10 02:45:56 +00:00
|
|
|
"path"
|
|
|
|
|
|
|
|
"github.com/BurntSushi/toml"
|
2019-07-05 20:28:56 +00:00
|
|
|
"srs.epita.fr/fic-server/libfic"
|
2018-01-10 02:45:56 +00:00
|
|
|
)
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
// ExerciceHintParams holds EHint definition infomation.
|
2018-01-10 03:42:50 +00:00
|
|
|
type ExerciceHintParams struct {
|
|
|
|
Filename string
|
2018-05-12 00:01:49 +00:00
|
|
|
Content string
|
2018-01-10 03:42:50 +00:00
|
|
|
Cost int64
|
|
|
|
Title string
|
2019-10-26 09:33:30 +00:00
|
|
|
NeedFlag []ExerciceDependency `toml:"need_flag,omitempty"`
|
2018-01-10 03:42:50 +00:00
|
|
|
}
|
|
|
|
|
2018-05-12 00:01:49 +00:00
|
|
|
// ExerciceDependency holds dependency definitions information.
|
|
|
|
type ExerciceDependency struct {
|
|
|
|
Id int64
|
|
|
|
Theme string `toml:",omitempty"`
|
|
|
|
}
|
|
|
|
|
2018-09-07 18:53:08 +00:00
|
|
|
// ExerciceUnlockFile holds parameters related to a locked file.
|
|
|
|
type ExerciceUnlockFile struct {
|
|
|
|
Filename string `toml:",omitempty"`
|
|
|
|
}
|
|
|
|
|
2019-01-16 04:25:20 +00:00
|
|
|
// ExerciceFlag holds informations about one flag.
|
2018-05-12 00:01:49 +00:00
|
|
|
type ExerciceFlag struct {
|
2019-09-06 21:03:08 +00:00
|
|
|
Id int64
|
|
|
|
Label string `toml:",omitempty"`
|
|
|
|
Type string `toml:",omitempty"`
|
|
|
|
Raw interface{}
|
|
|
|
Separator string `toml:",omitempty"`
|
|
|
|
Ordered bool `toml:",omitempty"`
|
|
|
|
CaseSensitive bool `toml:",omitempty"`
|
|
|
|
ValidatorRe string `toml:"validator_regexp,omitempty"`
|
|
|
|
Help string `toml:",omitempty"`
|
|
|
|
ChoicesCost int64 `toml:"choices_cost,omitempty"`
|
|
|
|
Choice []ExerciceFlagChoice
|
|
|
|
LockedFile []ExerciceUnlockFile `toml:"unlock_file,omitempty"`
|
|
|
|
NeedFlag []ExerciceDependency `toml:"need_flag,omitempty"`
|
|
|
|
NoShuffle bool
|
2018-05-12 00:01:49 +00:00
|
|
|
}
|
|
|
|
|
2019-09-06 20:58:30 +00:00
|
|
|
// ExerciceFlagChoice holds informations about a choice (for MCQ and UCQ).
|
|
|
|
type ExerciceFlagChoice struct {
|
|
|
|
ExerciceFlag
|
|
|
|
Value interface{} `toml:",omitempty"`
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
// ExerciceParams contains values parsed from defines.txt.
|
2018-01-10 02:45:56 +00:00
|
|
|
type ExerciceParams struct {
|
2018-05-12 00:01:49 +00:00
|
|
|
Gain int64
|
2018-11-18 21:44:23 +00:00
|
|
|
Tags []string
|
2018-05-12 00:01:49 +00:00
|
|
|
Hints []ExerciceHintParams `toml:"hint"`
|
|
|
|
Dependencies []ExerciceDependency `toml:"depend"`
|
|
|
|
Flags []ExerciceFlag `toml:"flag"`
|
2019-01-16 04:25:20 +00:00
|
|
|
FlagsMCQ []ExerciceFlag `toml:"flag_mcq"`
|
|
|
|
FlagsUCQ []ExerciceFlag `toml:"flag_ucq"`
|
2018-01-10 02:45:56 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
// parseExerciceParams reads challenge definitions from defines.txt and extract usefull data to set up the challenge.
|
2019-07-21 20:31:43 +00:00
|
|
|
func parseExerciceParams(i Importer, exPath string) (p ExerciceParams, md toml.MetaData, err error) {
|
2018-01-10 02:45:56 +00:00
|
|
|
var defs string
|
2018-05-12 00:01:49 +00:00
|
|
|
defs, err = getFileContent(i, path.Join(exPath, "challenge.txt"))
|
2019-07-21 20:31:43 +00:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2018-01-10 02:45:56 +00:00
|
|
|
|
2019-07-21 20:31:43 +00:00
|
|
|
md, err = toml.Decode(defs, &p)
|
2018-01-10 02:45:56 +00:00
|
|
|
|
|
|
|
return
|
|
|
|
}
|
2019-07-05 20:28:56 +00:00
|
|
|
|
|
|
|
// getExerciceParams returns normalized
|
|
|
|
func getExerciceParams(i Importer, exercice fic.Exercice) (params ExerciceParams, errs []string) {
|
|
|
|
var err error
|
2019-07-21 20:31:43 +00:00
|
|
|
if params, _, err = parseExerciceParams(i, exercice.Path); err != nil {
|
2019-07-05 20:28:56 +00:00
|
|
|
errs = append(errs, fmt.Sprintf("%q: challenge.txt: %s", path.Base(exercice.Path), err))
|
|
|
|
} 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 {
|
|
|
|
// Treat legacy UCQ flags as ExerciceFlag
|
|
|
|
for _, flag := range params.FlagsUCQ {
|
|
|
|
params.Flags = append(params.Flags, ExerciceFlag{
|
|
|
|
Id: flag.Id,
|
|
|
|
Label: flag.Label,
|
|
|
|
Type: "ucq",
|
|
|
|
Raw: flag.Raw,
|
|
|
|
ValidatorRe: flag.ValidatorRe,
|
|
|
|
Help: flag.Help,
|
|
|
|
ChoicesCost: flag.ChoicesCost,
|
|
|
|
Choice: flag.Choice,
|
|
|
|
LockedFile: flag.LockedFile,
|
|
|
|
NeedFlag: flag.NeedFlag,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
params.FlagsUCQ = []ExerciceFlag{}
|
|
|
|
|
|
|
|
// Treat legacy MCQ flags as ExerciceFlag
|
|
|
|
for _, flag := range params.FlagsMCQ {
|
|
|
|
params.Flags = append(params.Flags, ExerciceFlag{
|
|
|
|
Id: flag.Id,
|
|
|
|
Label: flag.Label,
|
|
|
|
Type: "mcq",
|
|
|
|
ChoicesCost: flag.ChoicesCost,
|
|
|
|
Choice: flag.Choice,
|
|
|
|
LockedFile: flag.LockedFile,
|
|
|
|
NeedFlag: flag.NeedFlag,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
params.FlagsMCQ = []ExerciceFlag{}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|