Handle optionnal flags
This commit is contained in:
parent
e581630d5e
commit
a414cd22c8
18 changed files with 68 additions and 22 deletions
|
@ -735,7 +735,8 @@ type uploadedFlag struct {
|
||||||
SortReGroups bool `json:"sort_re_grps"`
|
SortReGroups bool `json:"sort_re_grps"`
|
||||||
Flag string
|
Flag string
|
||||||
Value []byte
|
Value []byte
|
||||||
ChoicesCost int64 `json:"choices_cost"`
|
ChoicesCost int32 `json:"choices_cost"`
|
||||||
|
BonusGain int32 `json:"bonus_gain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func createExerciceFlag(c *gin.Context) {
|
func createExerciceFlag(c *gin.Context) {
|
||||||
|
@ -758,7 +759,7 @@ func createExerciceFlag(c *gin.Context) {
|
||||||
|
|
||||||
exercice := c.MustGet("exercice").(*fic.Exercice)
|
exercice := c.MustGet("exercice").(*fic.Exercice)
|
||||||
|
|
||||||
flag, err := exercice.AddRawFlagKey(uk.Label, uk.Type, uk.Placeholder, uk.IgnoreCase, uk.NoTrim, uk.Multiline, vre, uk.SortReGroups, []byte(uk.Flag), uk.ChoicesCost)
|
flag, err := exercice.AddRawFlagKey(uk.Label, uk.Type, uk.Placeholder, uk.IgnoreCase, uk.NoTrim, uk.Multiline, vre, uk.SortReGroups, []byte(uk.Flag), uk.ChoicesCost, uk.BonusGain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Unable to createExerciceFlag:", err.Error())
|
log.Println("Unable to createExerciceFlag:", err.Error())
|
||||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when trying to create flag."})
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs when trying to create flag."})
|
||||||
|
@ -839,6 +840,7 @@ func updateExerciceFlag(c *gin.Context) {
|
||||||
flag.Checksum = uk.Value
|
flag.Checksum = uk.Value
|
||||||
}
|
}
|
||||||
flag.ChoicesCost = uk.ChoicesCost
|
flag.ChoicesCost = uk.ChoicesCost
|
||||||
|
flag.BonusGain = uk.BonusGain
|
||||||
|
|
||||||
if uk.ValidatorRe != nil && len(*uk.ValidatorRe) > 0 {
|
if uk.ValidatorRe != nil && len(*uk.ValidatorRe) > 0 {
|
||||||
flag.ValidatorRegexp = uk.ValidatorRe
|
flag.ValidatorRegexp = uk.ValidatorRe
|
||||||
|
|
|
@ -62,6 +62,9 @@
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<input type="text" id="kccost{{flag.id}}" ng-model="flag.choices_cost" class="form-control form-control-sm" placeholder="Choices cost" title="Choices cost" integer>
|
<input type="text" id="kccost{{flag.id}}" ng-model="flag.choices_cost" class="form-control form-control-sm" placeholder="Choices cost" title="Choices cost" integer>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-2">
|
||||||
|
<input type="text" id="kbgain{{flag.id}}" ng-model="flag.bonus_gain" class="form-control form-control-sm" placeholder="Bonus gain" title="Bonus gain" integer>
|
||||||
|
</div>
|
||||||
<div class="col-2">
|
<div class="col-2">
|
||||||
<input type="text" id="korder{{flag.id}}" ng-model="flag.order" class="form-control form-control-sm" placeholder="Order" title="Order" integer>
|
<input type="text" id="korder{{flag.id}}" ng-model="flag.order" class="form-control form-control-sm" placeholder="Order" title="Order" integer>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="row in scores | filter: query | orderBy:'time'" ng-class="{'bg-ffound': row.reason == 'First blood', 'bg-wchoices': row.reason == 'Display choices', 'bg-success': row.reason == 'Validation', 'bg-info': row.reason == 'Hint', 'bg-warning': row.reason == 'Tries'}">
|
<tr ng-repeat="row in scores | filter: query | orderBy:'time'" ng-class="{'bg-danger': row.reason == 'Bonus flag', 'bg-ffound': row.reason == 'First blood', 'bg-wchoices': row.reason == 'Display choices', 'bg-success': row.reason == 'Validation', 'bg-info': row.reason == 'Hint', 'bg-warning': row.reason == 'Tries'}">
|
||||||
<td>
|
<td>
|
||||||
<a ng-repeat="exercice in exercices" ng-if="exercice.id == row.id_exercice" href="exercices/{{ row.id_exercice }}">{{ exercice.title }}</a>
|
<a ng-repeat="exercice in exercices" ng-if="exercice.id == row.id_exercice" href="exercices/{{ row.id_exercice }}">{{ exercice.title }}</a>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -43,7 +43,8 @@ type ExerciceFlag struct {
|
||||||
SortReGroups bool `toml:"sort_validator_regexp_groups,omitempty"`
|
SortReGroups bool `toml:"sort_validator_regexp_groups,omitempty"`
|
||||||
Placeholder string `toml:",omitempty"`
|
Placeholder string `toml:",omitempty"`
|
||||||
Help string `toml:",omitempty"`
|
Help string `toml:",omitempty"`
|
||||||
ChoicesCost int64 `toml:"choices_cost,omitempty"`
|
BonusGain int32 `toml:"bonus_gain,omitempty"`
|
||||||
|
ChoicesCost int32 `toml:"choices_cost,omitempty"`
|
||||||
Choice []ExerciceFlagChoice
|
Choice []ExerciceFlagChoice
|
||||||
LockedFile []ExerciceUnlockFile `toml:"unlock_file,omitempty"`
|
LockedFile []ExerciceUnlockFile `toml:"unlock_file,omitempty"`
|
||||||
NeedFlag []ExerciceDependency `toml:"need_flag,omitempty"`
|
NeedFlag []ExerciceDependency `toml:"need_flag,omitempty"`
|
||||||
|
|
|
@ -170,6 +170,7 @@ func buildKeyFlag(exercice *fic.Exercice, flag ExerciceFlag, flagline int, defau
|
||||||
SortReGroups: flag.SortReGroups,
|
SortReGroups: flag.SortReGroups,
|
||||||
Checksum: hashedFlag[:],
|
Checksum: hashedFlag[:],
|
||||||
ChoicesCost: flag.ChoicesCost,
|
ChoicesCost: flag.ChoicesCost,
|
||||||
|
BonusGain: flag.BonusGain,
|
||||||
})
|
})
|
||||||
f = &fl
|
f = &fl
|
||||||
|
|
||||||
|
|
|
@ -82,8 +82,7 @@ func treatSubmission(pathname string, team *fic.Team, exercice_id string) {
|
||||||
// Ensure the team didn't already solve this exercice
|
// Ensure the team didn't already solve this exercice
|
||||||
tm := team.HasSolved(exercice)
|
tm := team.HasSolved(exercice)
|
||||||
if tm != nil {
|
if tm != nil {
|
||||||
log.Printf("%s [WRN] Team %d ALREADY solved exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
log.Printf("%s [WRN] Team %d ALREADY solved exercice %d (%s : %s), continuing for eventual bonus flags\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle MCQ justifications: convert to expected keyid
|
// Handle MCQ justifications: convert to expected keyid
|
||||||
|
@ -119,7 +118,9 @@ func treatSubmission(pathname string, team *fic.Team, exercice_id string) {
|
||||||
log.Println(id, "[ERR] Can't remove file:", err)
|
log.Println(id, "[ERR] Can't remove file:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if solved {
|
if tm != nil {
|
||||||
|
genTeamQueue <- team
|
||||||
|
} else if solved {
|
||||||
log.Printf("%s Team %d SOLVED exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
log.Printf("%s Team %d SOLVED exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
||||||
if err := exercice.Solved(team); err != nil {
|
if err := exercice.Solved(team); err != nil {
|
||||||
log.Println(id, "[ERR] Unable to mark the challenge as solved:", err)
|
log.Println(id, "[ERR] Unable to mark the challenge as solved:", err)
|
||||||
|
|
|
@ -100,6 +100,11 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="form-group mb-3">
|
<div class="form-group mb-3">
|
||||||
|
{#if flag.bonus_gain}
|
||||||
|
<div class={'float-end badge bg-' + (flag.found?'success':'danger')} title={'Ce flag est optionnel, si vous le complétez il vous rapportera ' + flag.bonus_gain + ' points supplémentaires'}>
|
||||||
|
optionnel | {#if flag.bonus_gain > 0}+{/if}{flag.bonus_gain} pts
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
<label for="sol_{flag.type}{flag.id}_0">{flag.label} :</label>
|
<label for="sol_{flag.type}{flag.id}_0">{flag.label} :</label>
|
||||||
{#if flag.found && flag.value}
|
{#if flag.found && flag.value}
|
||||||
<span>{flag.value}</span>
|
<span>{flag.value}</span>
|
||||||
|
|
|
@ -161,7 +161,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</Col>
|
</Col>
|
||||||
<Col lg="6" class="mb-5">
|
<Col lg="6" class="mb-5">
|
||||||
{#if !$my.exercices[exercice.id].solved_rank && !solved[exercice.id]}
|
{#if $my.exercices[exercice.id].flags && $my.exercices[exercice.id].non_found_flags > 0 && !solved[exercice.id]}
|
||||||
<ExerciceFlags
|
<ExerciceFlags
|
||||||
{refresh_my}
|
{refresh_my}
|
||||||
{refresh_teams}
|
{refresh_teams}
|
||||||
|
@ -169,7 +169,8 @@
|
||||||
bind:forcesolved={solved[exercice.id]}
|
bind:forcesolved={solved[exercice.id]}
|
||||||
flags={$my.exercices[exercice.id].flags}
|
flags={$my.exercices[exercice.id].flags}
|
||||||
/>
|
/>
|
||||||
{:else}
|
{/if}
|
||||||
|
{#if $my.exercices[exercice.id].solved_rank || solved[exercice.id]}
|
||||||
<ExerciceSolved
|
<ExerciceSolved
|
||||||
{theme}
|
{theme}
|
||||||
exercice={$my.exercices[exercice.id]}
|
exercice={$my.exercices[exercice.id]}
|
||||||
|
|
|
@ -11,6 +11,15 @@ function createMyStore() {
|
||||||
for (let k in my.exercices) {
|
for (let k in my.exercices) {
|
||||||
my.exercices[k].id = k;
|
my.exercices[k].id = k;
|
||||||
|
|
||||||
|
if (my.exercices[k].flags) {
|
||||||
|
let nb = 0;
|
||||||
|
for (let j in my.exercices[k].flags) {
|
||||||
|
if (!my.exercices[k].flags[j].found)
|
||||||
|
nb += 1;
|
||||||
|
}
|
||||||
|
my.exercices[k].non_found_flags = nb;
|
||||||
|
}
|
||||||
|
|
||||||
if (my.team_id === 0 && my.exercices[k].hints) {
|
if (my.team_id === 0 && my.exercices[k].hints) {
|
||||||
for (let j in my.exercices[k].hints) {
|
for (let j in my.exercices[k].hints) {
|
||||||
my.exercices[k].hints[j].hidden = true;
|
my.exercices[k].hints[j].hidden = true;
|
||||||
|
|
|
@ -195,7 +195,8 @@ CREATE TABLE IF NOT EXISTS exercice_flags(
|
||||||
validator_regexp VARCHAR(255) NULL,
|
validator_regexp VARCHAR(255) NULL,
|
||||||
sort_re_grps BOOLEAN NOT NULL DEFAULT 0,
|
sort_re_grps BOOLEAN NOT NULL DEFAULT 0,
|
||||||
cksum BINARY(64) NOT NULL,
|
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)
|
FOREIGN KEY(id_exercice) REFERENCES exercices(id_exercice)
|
||||||
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
) DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||||
`); err != nil {
|
`); err != nil {
|
||||||
|
|
|
@ -471,10 +471,10 @@ func (e *Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq
|
||||||
// Check flags
|
// Check flags
|
||||||
for _, flag := range flags {
|
for _, flag := range flags {
|
||||||
if res, ok := respflags[flag.Id]; !ok && (!PartialValidation || t.HasPartiallySolved(flag) == nil) {
|
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 {
|
} else if flag.Check([]byte(res)) != 0 {
|
||||||
if !PartialValidation || t.HasPartiallySolved(flag) == nil {
|
if !PartialValidation || t.HasPartiallySolved(flag) == nil {
|
||||||
valid = false
|
valid = valid && flag.IsOptionnal()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
flag.FoundBy(t)
|
flag.FoundBy(t)
|
||||||
|
|
|
@ -338,7 +338,7 @@ func (f *EFile) GetDepends() ([]Flag, error) {
|
||||||
if err := rows.Scan(&d); err != nil {
|
if err := rows.Scan(&d); err != nil {
|
||||||
return nil, err
|
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 {
|
if err := rows.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -12,6 +12,7 @@ type Flag interface {
|
||||||
GetDepends() ([]Flag, error)
|
GetDepends() ([]Flag, error)
|
||||||
GetOrder() int8
|
GetOrder() int8
|
||||||
Check(val interface{}) int
|
Check(val interface{}) int
|
||||||
|
IsOptionnal() bool
|
||||||
FoundBy(t *Team)
|
FoundBy(t *Team)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,12 +42,14 @@ type FlagKey struct {
|
||||||
// Checksum is the expected hashed flag
|
// Checksum is the expected hashed flag
|
||||||
Checksum []byte `json:"value"`
|
Checksum []byte `json:"value"`
|
||||||
// ChoicesCost is the number of points lost to display choices.
|
// 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.
|
// GetFlagKeys returns a list of key's flags comming with the challenge.
|
||||||
func (e *Exercice) GetFlagKeys() ([]*FlagKey, error) {
|
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
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
@ -57,7 +59,7 @@ func (e *Exercice) GetFlagKeys() ([]*FlagKey, error) {
|
||||||
k := &FlagKey{}
|
k := &FlagKey{}
|
||||||
k.IdExercice = e.Id
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,21 +76,21 @@ func (e *Exercice) GetFlagKeys() ([]*FlagKey, error) {
|
||||||
// GetFlagKey returns a list of flags comming with the challenge.
|
// GetFlagKey returns a list of flags comming with the challenge.
|
||||||
func GetFlagKey(id int) (k *FlagKey, err error) {
|
func GetFlagKey(id int) (k *FlagKey, err error) {
|
||||||
k = &FlagKey{}
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFlagKey returns a flag.
|
// GetFlagKey returns a flag.
|
||||||
func (e *Exercice) GetFlagKey(id int) (k *FlagKey, err error) {
|
func (e *Exercice) GetFlagKey(id int) (k *FlagKey, err error) {
|
||||||
k = &FlagKey{}
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFlagKeyByLabel returns a flag matching the given label.
|
// GetFlagKeyByLabel returns a flag matching the given label.
|
||||||
func (e *Exercice) GetFlagKeyByLabel(label string) (k *FlagKey, err error) {
|
func (e *Exercice) GetFlagKeyByLabel(label string) (k *FlagKey, err error) {
|
||||||
k = &FlagKey{}
|
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
|
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.
|
// 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)
|
hash, err := ComputeHashedFlag(raw_value, ignorecase, notrim, validator_regexp, sortregroups)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -156,6 +158,7 @@ func (e *Exercice) AddRawFlagKey(name string, t string, placeholder string, igno
|
||||||
SortReGroups: sortregroups,
|
SortReGroups: sortregroups,
|
||||||
Checksum: hash[:],
|
Checksum: hash[:],
|
||||||
ChoicesCost: choicescost,
|
ChoicesCost: choicescost,
|
||||||
|
BonusGain: bonusgain,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = f.Create(e)
|
_, 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
|
return k, err
|
||||||
} else if kid, err := res.LastInsertId(); err != nil {
|
} else if kid, err := res.LastInsertId(); err != nil {
|
||||||
return k, err
|
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
|
return 0, err
|
||||||
} else if nb, err := res.RowsAffected(); err != nil {
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
|
@ -299,6 +302,11 @@ func (k *FlagKey) GetDepends() ([]Flag, error) {
|
||||||
return deps, nil
|
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.
|
// Check if the given val is the expected one for this flag.
|
||||||
func (k *FlagKey) Check(v interface{}) int {
|
func (k *FlagKey) Check(v interface{}) int {
|
||||||
var val []byte
|
var val []byte
|
||||||
|
|
|
@ -167,6 +167,11 @@ func (k *FlagLabel) GetDepends() ([]Flag, error) {
|
||||||
return deps, nil
|
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.
|
// Check if the given val is the expected one for this flag.
|
||||||
func (k *FlagLabel) Check(v interface{}) int {
|
func (k *FlagLabel) Check(v interface{}) int {
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -314,6 +314,11 @@ func (c *MCQ_entry) GetJustifiedFlag(e *Exercice) (*FlagKey, error) {
|
||||||
return e.GetFlagKeyByLabel(fmt.Sprintf("\\%%%d\\%%%%", c.Id))
|
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.
|
// Check if the given vals are the expected ones to validate this flag.
|
||||||
func (m *MCQ) Check(v interface{}) int {
|
func (m *MCQ) Check(v interface{}) int {
|
||||||
var vals map[int]bool
|
var vals map[int]bool
|
||||||
|
|
|
@ -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, 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
|
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
|
) 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`
|
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`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ type myTeamFlag struct {
|
||||||
PSolved *time.Time `json:"part_solved,omitempty"`
|
PSolved *time.Time `json:"part_solved,omitempty"`
|
||||||
Soluce string `json:"soluce,omitempty"`
|
Soluce string `json:"soluce,omitempty"`
|
||||||
Justify bool `json:"justify,omitempty"`
|
Justify bool `json:"justify,omitempty"`
|
||||||
|
BonusGain int64 `json:"bonus_gain,omitempty"`
|
||||||
Choices map[string]interface{} `json:"choices,omitempty"`
|
Choices map[string]interface{} `json:"choices,omitempty"`
|
||||||
ChoicesCost int64 `json:"choices_cost,omitempty"`
|
ChoicesCost int64 `json:"choices_cost,omitempty"`
|
||||||
Variant string `json:"variant,omitempty"`
|
Variant string `json:"variant,omitempty"`
|
||||||
|
@ -275,6 +276,7 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
flag.Multiline = k.Multiline
|
flag.Multiline = k.Multiline
|
||||||
|
flag.BonusGain = int64(float64(k.BonusGain) * GlobalScoreCoefficient)
|
||||||
|
|
||||||
var fl FlagMCQLabel
|
var fl FlagMCQLabel
|
||||||
if fl, err = k.GetMCQJustification(); err == nil {
|
if fl, err = k.GetMCQJustification(); err == nil {
|
||||||
|
|
Reference in a new issue