Implement flag type 'text': this is like keys, but on multiple lines

This commit is contained in:
nemunaire 2020-01-16 15:33:28 +01:00
parent 8f998485bb
commit 47ba134b55
9 changed files with 30 additions and 14 deletions

View File

@ -325,6 +325,7 @@ type uploadedFlag struct {
Label string
Help string
IgnoreCase bool
Multiline bool
ValidatorRe *string `json:"validator_regexp"`
Flag string
Value []byte
@ -346,7 +347,7 @@ func createExerciceFlag(exercice fic.Exercice, body []byte) (interface{}, error)
vre = uk.ValidatorRe
}
return exercice.AddRawFlagKey(uk.Label, uk.Help, uk.IgnoreCase, vre, []byte(uk.Flag), uk.ChoicesCost)
return exercice.AddRawFlagKey(uk.Label, uk.Help, uk.IgnoreCase, uk.Multiline, vre, []byte(uk.Flag), uk.ChoicesCost)
}
func showExerciceFlag(flag fic.FlagKey, _ fic.Exercice, body []byte) (interface{}, error) {

View File

@ -146,6 +146,10 @@
<input type="checkbox" class="custom-control-input" id="kicase{{flag.id}}" ng-model="flag.ignorecase">
<label class="custom-control-label" for="kicase{{flag.id}}">Ignore case</label>
</div>
<div class="col-auto custom-control custom-checkbox ml-1">
<input type="checkbox" class="custom-control-input" id="kicase{{flag.id}}" ng-model="flag.multiline">
<label class="custom-control-label" for="kmline{{flag.id}}">Multiline</label>
</div>
</div>
<div class="row">
<input type="text" id="kvre{{flag.id}}" ng-model="flag.validator_regexp" class="col form-control form-control-sm" placeholder="Regexp selecting validation string" title="Regexp selecting validation string">

View File

@ -116,7 +116,7 @@ func buildKeyFlag(exercice fic.Exercice, flag ExerciceFlag, flagline int, defaul
}
flag.Label = prep + flag.Label
if !isFullGraphic(raw) {
if (flag.Type == "text" && !isFullGraphic(strings.Replace(raw, "\n", "", -1))) || (flag.Type != "text" && !isFullGraphic(raw)) {
errs = append(errs, fmt.Sprintf("%q: WARNING flag #%d: non-printable characters in flag, is this really expected?", path.Base(exercice.Path), flagline))
}
@ -130,6 +130,7 @@ func buildKeyFlag(exercice fic.Exercice, flag ExerciceFlag, flagline int, defaul
Label: flag.Label,
Help: flag.Help,
IgnoreCase: !flag.CaseSensitive,
Multiline: flag.Type == "text",
ValidatorRegexp: validatorRegexp(flag.ValidatorRe),
Checksum: hashedFlag[:],
ChoicesCost: flag.ChoicesCost,
@ -191,6 +192,8 @@ func buildExerciceFlag(i Importer, exercice fic.Exercice, flag ExerciceFlag, nli
flag.Type = "key"
case "key":
flag.Type = "key"
case "text":
flag.Type = "text"
case "vector":
flag.Type = "vector"
case "ucq":
@ -198,11 +201,11 @@ func buildExerciceFlag(i Importer, exercice fic.Exercice, flag ExerciceFlag, nli
case "mcq":
flag.Type = "mcq"
default:
errs = append(errs, fmt.Sprintf("%q: flag #%d: invalid type of flag: should be 'key', 'mcq', 'ucq' or 'vector'.", path.Base(exercice.Path), nline+1))
errs = append(errs, fmt.Sprintf("%q: flag #%d: invalid type of flag: should be 'key', 'text', 'mcq', 'ucq' or 'vector'.", path.Base(exercice.Path), nline+1))
return
}
if flag.Type == "key" || flag.Type == "ucq" || flag.Type == "vector" {
if flag.Type == "key" || flag.Type == "text" || flag.Type == "ucq" || flag.Type == "vector" {
addedFlag, choices, berrs := buildKeyFlag(exercice, flag, nline+1, "Flag")
if len(berrs) > 0 {
errs = append(errs, berrs...)

View File

@ -125,7 +125,8 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"])
<label for="sol_{{ $ctrl.kid }}_0" ng-class="{'text-light': !$ctrl.key.found}">{{ $ctrl.key.label }}&nbsp;:</label>
<span ng-if="$ctrl.key.found && $ctrl.key.value" ng-bind="$ctrl.key.value"></span>
<div class="input-group" ng-repeat="v in $ctrl.key.values track by $index" ng-class="{'mt-1': !$first}" ng-if="!$ctrl.key.found">
<input type="text" class="form-control flag" id="sol_{{ $ctrl.kid }}_{{ $index }}" autocomplete="off" name="sol_{{ $ctrl.kid }}_{{ $index }}" ng-model="$ctrl.key.values[$index]" ng-if="!$ctrl.key.choices" placeholder="{{ $ctrl.key.help }}" title="{{ $ctrl.key.help }}">
<input type="text" class="form-control flag" id="sol_{{ $ctrl.kid }}_{{ $index }}" autocomplete="off" name="sol_{{ $ctrl.kid }}_{{ $index }}" ng-model="$ctrl.key.values[$index]" ng-if="!$ctrl.key.choices && !$ctrl.key.multiline" placeholder="{{ $ctrl.key.help }}" title="{{ $ctrl.key.help }}">
<textarea class="form-control flag" id="sol_{{ $ctrl.kid }}_{{ $index }}" autocomplete="off" name="sol_{{ $ctrl.kid }}_{{ $index }}" ng-model="$ctrl.key.values[$index]" ng-if="!$ctrl.key.choices && $ctrl.key.multiline" placeholder="{{ $ctrl.key.help }}" title="{{ $ctrl.key.help }}"></textarea>
<select class="custom-select" id="sol_{{ $ctrl.kid }}" name="sol_{{ $ctrl.kid }}" ng-model="$ctrl.key.values[$index]" ng-if="$ctrl.key.choices" ng-options="l as v for (l, v) in $ctrl.key.choices"></select>
<div class="input-group-append" ng-if="$ctrl.key.choices_cost">
<button class="btn btn-success" type="button" ng-click="$ctrl.wantchoices($ctrl.kid)" ng-class="{disabled: $ctrl.key.wcsubmitted}" title="Cliquez pour échanger ce champ de texte par une liste de choix. L'opération vous coûtera {{ $ctrl.key.choices_cost * $ctrl.settings.wchoiceCurrentCoefficient }} points.">

View File

@ -35,7 +35,7 @@ func (c submissionChecker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
http.Error(w, "{\"errmsg\":\"Requête invalide.\"}", http.StatusBadRequest)
return
} else if r.ContentLength < 0 || r.ContentLength > 1023 {
} else if r.ContentLength < 0 || r.ContentLength > 2047 {
http.Error(w, "{\"errmsg\":\"Requête trop longue ou de taille inconnue\"}", http.StatusRequestEntityTooLarge)
return
}

View File

@ -174,6 +174,7 @@ CREATE TABLE IF NOT EXISTS exercice_flags(
type VARCHAR(255) NOT NULL,
help VARCHAR(255) NOT NULL,
ignorecase BOOLEAN NOT NULL DEFAULT 0,
multiline BOOLEAN NOT NULL DEFAULT 0,
validator_regexp VARCHAR(255) NULL,
cksum BINARY(64) NOT NULL,
choices_cost INTEGER NOT NULL,

View File

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

View File

@ -21,6 +21,8 @@ type FlagKey struct {
Help string `json:"help"`
// IgnoreCase indicates if the case is sensitive to case or not
IgnoreCase bool `json:"ignorecase"`
// Multiline indicates if the flag is stored on multiple lines
Multiline bool `json:"multiline"`
// ValidatorRegexp extracts a subset of the player's answer, that will be checked.
ValidatorRegexp *string `json:"validator_regexp"`
// Checksum is the expected hashed flag
@ -31,7 +33,7 @@ type FlagKey struct {
// 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, type, help, ignorecase, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE id_exercice = ?", e.Id); err != nil {
if rows, err := DBQuery("SELECT id_flag, id_exercice, type, help, ignorecase, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE id_exercice = ?", e.Id); err != nil {
return nil, err
} else {
defer rows.Close()
@ -41,7 +43,7 @@ func (e Exercice) GetFlagKeys() ([]FlagKey, error) {
var k FlagKey
k.IdExercice = e.Id
if err := rows.Scan(&k.Id, &k.IdExercice, &k.Label, &k.Help, &k.IgnoreCase, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost); err != nil {
if err := rows.Scan(&k.Id, &k.IdExercice, &k.Label, &k.Help, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost); err != nil {
return nil, err
}
@ -57,13 +59,13 @@ func (e Exercice) GetFlagKeys() ([]FlagKey, error) {
// GetFlagKey returns a list of flags comming with the challenge.
func GetFlagKey(id int64) (k FlagKey, err error) {
err = DBQueryRow("SELECT id_flag, id_exercice, type, help, ignorecase, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE id_flag = ?", id).Scan(&k.Id, &k.IdExercice, &k.Label, &k.Help, &k.IgnoreCase, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost)
err = DBQueryRow("SELECT id_flag, id_exercice, type, help, ignorecase, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE id_flag = ?", id).Scan(&k.Id, &k.IdExercice, &k.Label, &k.Help, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost)
return
}
// GetFlagKeyByLabel returns a flag matching the given label.
func (e Exercice) GetFlagKeyByLabel(label string) (k FlagKey, err error) {
err = DBQueryRow("SELECT id_flag, id_exercice, type, help, ignorecase, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE type LIKE ? AND id_exercice = ?", label, e.Id).Scan(&k.Id, &k.IdExercice, &k.Label, &k.Help, &k.IgnoreCase, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost)
err = DBQueryRow("SELECT id_flag, id_exercice, type, help, ignorecase, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE type LIKE ? AND id_exercice = ?", label, e.Id).Scan(&k.Id, &k.IdExercice, &k.Label, &k.Help, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost)
return
}
@ -103,7 +105,7 @@ func ExecValidatorRegexp(vre string, val []byte, ignorecase bool) ([]byte, error
}
// 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, help string, ignorecase bool, validator_regexp *string, raw_value []byte, choicescost int64) (f FlagKey, err error) {
func (e Exercice) AddRawFlagKey(name string, help string, ignorecase bool, multiline bool, validator_regexp *string, raw_value []byte, choicescost int64) (f FlagKey, err error) {
hash, errr := ComputeHashedFlag(raw_value, ignorecase, validator_regexp)
if errr != nil {
return f, err
@ -113,6 +115,7 @@ func (e Exercice) AddRawFlagKey(name string, help string, ignorecase bool, valid
Label: name,
Help: help,
IgnoreCase: ignorecase,
Multiline: multiline,
ValidatorRegexp: validator_regexp,
Checksum: hash[:],
ChoicesCost: choicescost,
@ -145,7 +148,7 @@ func (k FlagKey) Create(e Exercice) (Flag, error) {
}
}
if res, err := DBExec("INSERT INTO exercice_flags (id_exercice, type, help, ignorecase, validator_regexp, cksum, choices_cost) VALUES (?, ?, ?, ?, ?, ?, ?)", e.Id, k.Label, k.Help, k.IgnoreCase, k.ValidatorRegexp, k.Checksum, k.ChoicesCost); err != nil {
if res, err := DBExec("INSERT INTO exercice_flags (id_exercice, type, help, ignorecase, multiline, validator_regexp, cksum, choices_cost) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", e.Id, k.Label, k.Help, k.IgnoreCase, k.Multiline, k.ValidatorRegexp, k.Checksum, k.ChoicesCost); err != nil {
return k, err
} else if kid, err := res.LastInsertId(); err != nil {
return k, err
@ -170,7 +173,7 @@ func (k FlagKey) Update() (int64, error) {
}
}
if res, err := DBExec("UPDATE exercice_flags SET id_exercice = ?, type = ?, help = ?, ignorecase = ?, validator_regexp = ?, cksum = ?, choices_cost = ? WHERE id_flag = ?", k.IdExercice, k.Label, k.Help, k.IgnoreCase, k.ValidatorRegexp, k.Checksum, k.ChoicesCost, k.Id); err != nil {
if res, err := DBExec("UPDATE exercice_flags SET id_exercice = ?, type = ?, help = ?, ignorecase = ?, multiline = ?, validator_regexp = ?, cksum = ?, choices_cost = ? WHERE id_flag = ?", k.IdExercice, k.Label, k.Help, k.IgnoreCase, k.Multiline, k.ValidatorRegexp, k.Checksum, k.ChoicesCost, k.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err

View File

@ -33,6 +33,7 @@ type myTeamFlag struct {
NbLines uint64 `json:"nb_lines,omitempty"`
IgnoreOrder bool `json:"ignore_order,omitempty"`
IgnoreCase bool `json:"ignore_case,omitempty"`
Multiline bool `json:"multiline,omitempty"`
ValidatorRe *string `json:"validator_regexp,omitempty"`
Solved *time.Time `json:"found,omitempty"`
Soluce string `json:"soluce,omitempty"`
@ -201,6 +202,8 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
flag.Solved = t.HasPartiallySolved(k)
}
flag.Multiline = k.Multiline
var fl FlagLabel
if fl, err = k.GetMCQJustification(); err == nil {
k.Label = fl.Label