Handle optionnal flags

This commit is contained in:
nemunaire 2022-05-31 22:03:51 +02:00
parent e581630d5e
commit a414cd22c8
18 changed files with 68 additions and 22 deletions

View file

@ -195,7 +195,8 @@ CREATE TABLE IF NOT EXISTS exercice_flags(
validator_regexp VARCHAR(255) NULL,
sort_re_grps BOOLEAN NOT NULL DEFAULT 0,
cksum BINARY(64) NOT NULL,
choices_cost INTEGER NOT NULL,
choices_cost MEDIUMINT NOT NULL,
bonus_gain MEDIUMINT NOT NULL,
FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice)
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
`); err != nil {

View file

@ -471,10 +471,10 @@ func (e *Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq
// Check flags
for _, flag := range flags {
if res, ok := respflags[flag.Id]; !ok && (!PartialValidation || t.HasPartiallySolved(flag) == nil) {
valid = false
valid = valid && flag.IsOptionnal()
} else if flag.Check([]byte(res)) != 0 {
if !PartialValidation || t.HasPartiallySolved(flag) == nil {
valid = false
valid = valid && flag.IsOptionnal()
}
} else {
flag.FoundBy(t)

View file

@ -338,7 +338,7 @@ func (f *EFile) GetDepends() ([]Flag, error) {
if err := rows.Scan(&d); err != nil {
return nil, err
}
deps = append(deps, &FlagKey{d, f.IdExercice, 0, "", "", "", "", "", false, false, false, nil, false, []byte{}, 0})
deps = append(deps, &FlagKey{d, f.IdExercice, 0, "", "", "", "", "", false, false, false, nil, false, []byte{}, 0, 0})
}
if err := rows.Err(); err != nil {
return nil, err

View file

@ -12,6 +12,7 @@ type Flag interface {
GetDepends() ([]Flag, error)
GetOrder() int8
Check(val interface{}) int
IsOptionnal() bool
FoundBy(t *Team)
}

View file

@ -42,12 +42,14 @@ type FlagKey struct {
// Checksum is the expected hashed flag
Checksum []byte `json:"value"`
// ChoicesCost is the number of points lost to display choices.
ChoicesCost int64 `json:"choices_cost"`
ChoicesCost int32 `json:"choices_cost"`
// BonusGain makes the flag completion optionnal. If it is filled and correct, it gives some points.
BonusGain int32 `json:"bonus_gain"`
}
// GetFlagKeys returns a list of key's flags comming with the challenge.
func (e *Exercice) GetFlagKeys() ([]*FlagKey, error) {
if rows, err := DBQuery("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost FROM exercice_flags WHERE id_exercice = ?", e.Id); err != nil {
if rows, err := DBQuery("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost, bonus_gain FROM exercice_flags WHERE id_exercice = ?", e.Id); err != nil {
return nil, err
} else {
defer rows.Close()
@ -57,7 +59,7 @@ func (e *Exercice) GetFlagKeys() ([]*FlagKey, error) {
k := &FlagKey{}
k.IdExercice = e.Id
if err := rows.Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.NoTrim, &k.Multiline, &k.ValidatorRegexp, &k.SortReGroups, &k.Checksum, &k.ChoicesCost); err != nil {
if err := rows.Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.NoTrim, &k.Multiline, &k.ValidatorRegexp, &k.SortReGroups, &k.Checksum, &k.ChoicesCost, &k.BonusGain); err != nil {
return nil, err
}
@ -74,21 +76,21 @@ func (e *Exercice) GetFlagKeys() ([]*FlagKey, error) {
// GetFlagKey returns a list of flags comming with the challenge.
func GetFlagKey(id int) (k *FlagKey, err error) {
k = &FlagKey{}
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost FROM exercice_flags WHERE id_flag = ?", id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.Multiline, &k.NoTrim, &k.ValidatorRegexp, &k.SortReGroups, &k.Checksum, &k.ChoicesCost)
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost, bonus_gain FROM exercice_flags WHERE id_flag = ?", id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.Multiline, &k.NoTrim, &k.ValidatorRegexp, &k.SortReGroups, &k.Checksum, &k.ChoicesCost, &k.BonusGain)
return
}
// GetFlagKey returns a flag.
func (e *Exercice) GetFlagKey(id int) (k *FlagKey, err error) {
k = &FlagKey{}
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost FROM exercice_flags WHERE id_flag = ? AND id_exercice = ?", id, e.Id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.NoTrim, &k.Multiline, &k.ValidatorRegexp, &k.SortReGroups, &k.Checksum, &k.ChoicesCost)
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost, bonus_gain FROM exercice_flags WHERE id_flag = ? AND id_exercice = ?", id, e.Id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.NoTrim, &k.Multiline, &k.ValidatorRegexp, &k.SortReGroups, &k.Checksum, &k.ChoicesCost, &k.BonusGain)
return
}
// GetFlagKeyByLabel returns a flag matching the given label.
func (e *Exercice) GetFlagKeyByLabel(label string) (k *FlagKey, err error) {
k = &FlagKey{}
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost FROM exercice_flags WHERE type LIKE ? AND id_exercice = ?", label, e.Id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.NoTrim, &k.Multiline, &k.ValidatorRegexp, &k.SortReGroups, &k.Checksum, &k.ChoicesCost)
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost, bonus_gain FROM exercice_flags WHERE type LIKE ? AND id_exercice = ?", label, e.Id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.NoTrim, &k.Multiline, &k.ValidatorRegexp, &k.SortReGroups, &k.Checksum, &k.ChoicesCost, &k.BonusGain)
return
}
@ -139,7 +141,7 @@ func ExecValidatorRegexp(vre string, val []byte, ignorecase bool, sortregroups b
}
// AddRawFlagKey creates and fills a new struct FlagKey, from a non-hashed flag, and registers it into the database.
func (e *Exercice) AddRawFlagKey(name string, t string, placeholder string, ignorecase bool, multiline bool, notrim bool, validator_regexp *string, sortregroups bool, raw_value []byte, choicescost int64) (*FlagKey, error) {
func (e *Exercice) AddRawFlagKey(name string, t string, placeholder string, ignorecase bool, multiline bool, notrim bool, validator_regexp *string, sortregroups bool, raw_value []byte, choicescost int32, bonusgain int32) (*FlagKey, error) {
hash, err := ComputeHashedFlag(raw_value, ignorecase, notrim, validator_regexp, sortregroups)
if err != nil {
return nil, err
@ -156,6 +158,7 @@ func (e *Exercice) AddRawFlagKey(name string, t string, placeholder string, igno
SortReGroups: sortregroups,
Checksum: hash[:],
ChoicesCost: choicescost,
BonusGain: bonusgain,
}
_, err = f.Create(e)
@ -185,7 +188,7 @@ func (k *FlagKey) Create(e *Exercice) (Flag, error) {
}
}
if res, err := DBExec("INSERT INTO exercice_flags (id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", e.Id, k.Order, k.Label, k.Type, k.Placeholder, k.Help, k.Unit, k.IgnoreCase, k.NoTrim, k.Multiline, k.ValidatorRegexp, k.SortReGroups, k.Checksum, k.ChoicesCost); err != nil {
if res, err := DBExec("INSERT INTO exercice_flags (id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, notrim, multiline, validator_regexp, sort_re_grps, cksum, choices_cost, bonus_gain) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", e.Id, k.Order, k.Label, k.Type, k.Placeholder, k.Help, k.Unit, k.IgnoreCase, k.NoTrim, k.Multiline, k.ValidatorRegexp, k.SortReGroups, k.Checksum, k.ChoicesCost, k.BonusGain); err != nil {
return k, err
} else if kid, err := res.LastInsertId(); err != nil {
return k, err
@ -210,7 +213,7 @@ func (k *FlagKey) Update() (int64, error) {
}
}
if res, err := DBExec("UPDATE exercice_flags SET id_exercice = ?, ordre = ?, label = ?, type = ?, placeholder = ?, help = ?, unit = ?, ignorecase = ?, notrim = ?, multiline = ?, validator_regexp = ?, sort_re_grps = ?, cksum = ?, choices_cost = ? WHERE id_flag = ?", k.IdExercice, k.Order, k.Label, k.Type, k.Placeholder, k.Help, k.Unit, k.IgnoreCase, k.NoTrim, k.Multiline, k.ValidatorRegexp, k.SortReGroups, k.Checksum, k.ChoicesCost, k.Id); err != nil {
if res, err := DBExec("UPDATE exercice_flags SET id_exercice = ?, ordre = ?, label = ?, type = ?, placeholder = ?, help = ?, unit = ?, ignorecase = ?, notrim = ?, multiline = ?, validator_regexp = ?, sort_re_grps = ?, cksum = ?, choices_cost = ?, bonus_gain = ? WHERE id_flag = ?", k.IdExercice, k.Order, k.Label, k.Type, k.Placeholder, k.Help, k.Unit, k.IgnoreCase, k.NoTrim, k.Multiline, k.ValidatorRegexp, k.SortReGroups, k.Checksum, k.ChoicesCost, k.BonusGain, k.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
@ -299,6 +302,11 @@ func (k *FlagKey) GetDepends() ([]Flag, error) {
return deps, nil
}
// IsOptionnal to know if the flag can be omitted when validating the step.
func (k *FlagKey) IsOptionnal() bool {
return k.BonusGain != 0
}
// Check if the given val is the expected one for this flag.
func (k *FlagKey) Check(v interface{}) int {
var val []byte

View file

@ -167,6 +167,11 @@ func (k *FlagLabel) GetDepends() ([]Flag, error) {
return deps, nil
}
// IsOptionnal to know if the flag can be omitted when validating the step.
func (k *FlagLabel) IsOptionnal() bool {
return true
}
// Check if the given val is the expected one for this flag.
func (k *FlagLabel) Check(v interface{}) int {
return 0

View file

@ -314,6 +314,11 @@ func (c *MCQ_entry) GetJustifiedFlag(e *Exercice) (*FlagKey, error) {
return e.GetFlagKeyByLabel(fmt.Sprintf("\\%%%d\\%%%%", c.Id))
}
// IsOptionnal to know if the flag can be omitted when validating the step.
func (m *MCQ) IsOptionnal() bool {
return false
}
// Check if the given vals are the expected ones to validate this flag.
func (m *MCQ) Check(v interface{}) int {
var vals map[int]bool

View file

@ -32,6 +32,7 @@ func exoptsQuery(whereExo string) string {
SELECT id_team, id_exercice, MIN(time) AS time, ` + fmt.Sprintf("%f", FirstBlood) + ` AS coeff, "First blood" AS reason FROM exercice_solved GROUP BY id_exercice UNION
SELECT id_team, id_exercice, time, coefficient AS coeff, "Validation" AS reason FROM exercice_solved
) S INNER JOIN exercices E ON S.id_exercice = E.id_exercice ` + whereExo + ` UNION ALL
SELECT B.id_team, B.time, F.bonus_gain AS points, 1 AS coeff, "Bonus flag" AS reason, F.id_exercice FROM flag_found B INNER JOIN exercice_flags F ON F.id_flag = B.id_flag WHERE F.bonus_gain != 0 HAVING points != 0 UNION ALL
SELECT id_team, MAX(time) AS time, (FLOOR(COUNT(*)/10 - 1) * (FLOOR(COUNT(*)/10)))/0.2 + (FLOOR(COUNT(*)/10) * (COUNT(*)%10)) AS points, ` + fmt.Sprintf("%f", SubmissionCostBase*-1) + ` AS coeff, "Tries" AS reason, id_exercice FROM ` + tries_table + ` S ` + whereExo + ` GROUP BY id_exercice, id_team`
}

View file

@ -48,6 +48,7 @@ type myTeamFlag struct {
PSolved *time.Time `json:"part_solved,omitempty"`
Soluce string `json:"soluce,omitempty"`
Justify bool `json:"justify,omitempty"`
BonusGain int64 `json:"bonus_gain,omitempty"`
Choices map[string]interface{} `json:"choices,omitempty"`
ChoicesCost int64 `json:"choices_cost,omitempty"`
Variant string `json:"variant,omitempty"`
@ -275,6 +276,7 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
}
flag.Multiline = k.Multiline
flag.BonusGain = int64(float64(k.BonusGain) * GlobalScoreCoefficient)
var fl FlagMCQLabel
if fl, err = k.GetMCQJustification(); err == nil {