fic: Add Order, Help and Type values in struct

This commit is contained in:
nemunaire 2021-08-30 18:33:14 +02:00
parent 867e9bb345
commit 74e8c3801a
16 changed files with 134 additions and 110 deletions

View File

@ -143,7 +143,7 @@ func deleteFile(file fic.EFile, _ []byte) (interface{}, error) {
return file.Delete() return file.Delete()
} }
func deleteFileDep(file fic.EFile, depid int64, _ []byte) (interface{}, error) { func deleteFileDep(file fic.EFile, depid int, _ []byte) (interface{}, error) {
return true, file.DeleteDepend(fic.FlagKey{Id: depid}) return true, file.DeleteDepend(fic.FlagKey{Id: depid})
} }

View File

@ -115,7 +115,7 @@ func teamAssocHandler(f func(fic.Team, string, []byte) (interface{}, error)) fun
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
var team fic.Team var team fic.Team
teamHandler(func (tm fic.Team, _ []byte) (interface{}, error) { teamHandler(func(tm fic.Team, _ []byte) (interface{}, error) {
team = tm team = tm
return nil, nil return nil, nil
})(ps, body) })(ps, body)
@ -193,7 +193,7 @@ func flagKeyHandler(f func(fic.FlagKey, fic.Exercice, []byte) (interface{}, erro
return nil, err return nil, err
} else { } else {
for _, flag := range flags { for _, flag := range flags {
if flag.Id == kid { if flag.Id == int(kid) {
return f(flag, exercice, body) return f(flag, exercice, body)
} }
} }
@ -212,9 +212,9 @@ func choiceHandler(f func(fic.FlagChoice, fic.Exercice, []byte) (interface{}, er
return nil, nil return nil, nil
})(ps, body) })(ps, body)
if cid, err := strconv.ParseInt(string(ps.ByName("cid")), 10, 64); err != nil { if cid, err := strconv.ParseInt(string(ps.ByName("cid")), 10, 32); err != nil {
return nil, err return nil, err
} else if choice, err := flag.GetChoice(cid); err != nil { } else if choice, err := flag.GetChoice(int(cid)); err != nil {
return nil, err return nil, err
} else { } else {
return f(choice, exercice, body) return f(choice, exercice, body)
@ -236,7 +236,7 @@ func quizHandler(f func(fic.MCQ, fic.Exercice, []byte) (interface{}, error)) fun
return nil, err return nil, err
} else { } else {
for _, mcq := range mcqs { for _, mcq := range mcqs {
if mcq.Id == int64(qid) { if mcq.Id == int(qid) {
return f(mcq, exercice, body) return f(mcq, exercice, body)
} }
} }
@ -316,13 +316,13 @@ func fileHandler(f func(fic.EFile, []byte) (interface{}, error)) func(httprouter
} }
} }
func fileDependancyHandler(f func(fic.EFile, int64, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func fileDependancyHandler(f func(fic.EFile, int, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
if depid, err := strconv.ParseInt(string(ps.ByName("depid")), 10, 64); err != nil { if depid, err := strconv.ParseInt(string(ps.ByName("depid")), 10, 64); err != nil {
return nil, err return nil, err
} else { } else {
return fileHandler(func(file fic.EFile, b []byte) (interface{}, error) { return fileHandler(func(file fic.EFile, b []byte) (interface{}, error) {
return f(file, depid, b) return f(file, int(depid), b)
})(ps, body) })(ps, body)
} }
} }

View File

@ -40,6 +40,7 @@ type ExerciceFlag struct {
CaseSensitive bool `toml:",omitempty"` CaseSensitive bool `toml:",omitempty"`
ValidatorRe string `toml:"validator_regexp,omitempty"` ValidatorRe string `toml:"validator_regexp,omitempty"`
Placeholder string `toml:",omitempty"` Placeholder string `toml:",omitempty"`
Help string `toml:",omitempty"`
ChoicesCost int64 `toml:"choices_cost,omitempty"` ChoicesCost int64 `toml:"choices_cost,omitempty"`
Choice []ExerciceFlagChoice Choice []ExerciceFlagChoice
LockedFile []ExerciceUnlockFile `toml:"unlock_file,omitempty"` LockedFile []ExerciceUnlockFile `toml:"unlock_file,omitempty"`

View File

@ -128,8 +128,10 @@ func buildKeyFlag(exercice fic.Exercice, flag ExerciceFlag, flagline int, defaul
} }
fl := fic.Flag(fic.FlagKey{ fl := fic.Flag(fic.FlagKey{
IdExercice: exercice.Id, IdExercice: exercice.Id,
Order: int8(flagline),
Label: flag.Label, Label: flag.Label,
Placeholder: flag.Placeholder, Placeholder: flag.Placeholder,
Help: flag.Help,
IgnoreCase: !flag.CaseSensitive, IgnoreCase: !flag.CaseSensitive,
Multiline: flag.Type == "text", Multiline: flag.Type == "text",
ValidatorRegexp: validatorRegexp(flag.ValidatorRe), ValidatorRegexp: validatorRegexp(flag.ValidatorRe),
@ -221,6 +223,7 @@ func buildExerciceFlag(i Importer, exercice fic.Exercice, flag ExerciceFlag, nli
} else if flag.Type == "mcq" { } else if flag.Type == "mcq" {
addedFlag := fic.MCQ{ addedFlag := fic.MCQ{
IdExercice: exercice.Id, IdExercice: exercice.Id,
Order: int8(nline + 1),
Title: flag.Label, Title: flag.Label,
Entries: []fic.MCQ_entry{}, Entries: []fic.MCQ_entry{},
} }

View File

@ -13,7 +13,7 @@ import (
) )
type wantChoices struct { type wantChoices struct {
FlagId int64 `json:"id"` FlagId int `json:"id"`
} }
func treatWantChoices(pathname string, team fic.Team) { func treatWantChoices(pathname string, team fic.Team) {

View File

@ -18,9 +18,9 @@ import (
) )
type ResponsesUpload struct { type ResponsesUpload struct {
Keys map[int64]string `json:"flags"` Keys map[int]string `json:"flags"`
MCQs map[int64]bool `json:"mcqs"` MCQs map[int]bool `json:"mcqs"`
MCQJ map[int64]string `json:"justifications"` MCQJ map[int]string `json:"justifications"`
} }
func treatSubmission(pathname string, team fic.Team, exercice_id string) { func treatSubmission(pathname string, team fic.Team, exercice_id string) {
@ -100,7 +100,7 @@ func treatSubmission(pathname string, team fic.Team, exercice_id string) {
continue continue
} else { } else {
if responses.Keys == nil { if responses.Keys == nil {
responses.Keys = map[int64]string{} responses.Keys = map[int]string{}
} }
responses.Keys[key.Id] = j responses.Keys[key.Id] = j
} }

View File

@ -176,7 +176,10 @@ CREATE TABLE IF NOT EXISTS exercice_hints(
CREATE TABLE IF NOT EXISTS exercice_flags( CREATE TABLE IF NOT EXISTS exercice_flags(
id_flag INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_flag INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
id_exercice INTEGER NOT NULL, id_exercice INTEGER NOT NULL,
ordre TINYINT NOT NULL,
label VARCHAR(255) NOT NULL,
type VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL,
placeholder VARCHAR(255) NOT NULL,
help VARCHAR(255) NOT NULL, help VARCHAR(255) NOT NULL,
ignorecase BOOLEAN NOT NULL DEFAULT 0, ignorecase BOOLEAN NOT NULL DEFAULT 0,
multiline BOOLEAN NOT NULL DEFAULT 0, multiline BOOLEAN NOT NULL DEFAULT 0,
@ -233,6 +236,7 @@ CREATE TABLE IF NOT EXISTS exercice_files_okey_deps(
CREATE TABLE IF NOT EXISTS exercice_mcq( CREATE TABLE IF NOT EXISTS exercice_mcq(
id_mcq INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, id_mcq INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
id_exercice INTEGER NOT NULL, id_exercice INTEGER NOT NULL,
ordre TINYINT NOT NULL,
title VARCHAR(255) NOT NULL, title VARCHAR(255) 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;

View File

@ -408,7 +408,7 @@ func (e Exercice) MCQSolved() (res []int64) {
// CheckResponse, given both flags and MCQ responses, figures out if thoses are correct (or if they are previously solved). // CheckResponse, given both flags and MCQ responses, figures out if thoses are correct (or if they are previously solved).
// In the meanwhile, CheckResponse registers good answers given (but it does not mark the challenge as solved at the end). // In the meanwhile, CheckResponse registers good answers given (but it does not mark the challenge as solved at the end).
func (e Exercice) CheckResponse(cksum []byte, respflags map[int64]string, respmcq map[int64]bool, t Team) (bool, error) { func (e Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq map[int]bool, t Team) (bool, error) {
if err := e.NewTry(t, cksum); err != nil { if err := e.NewTry(t, cksum); err != nil {
return false, err return false, err
} else if flags, err := e.GetFlagKeys(); err != nil { } else if flags, err := e.GetFlagKeys(); err != nil {

View File

@ -326,11 +326,11 @@ func (f EFile) GetDepends() ([]Flag, error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var d int64 var d int
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, "", "", false, false, nil, []byte{}, 0}) deps = append(deps, FlagKey{d, f.IdExercice, 0, "", "", "", "", false, false, nil, []byte{}, 0})
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
return nil, err return nil, err
@ -343,11 +343,11 @@ func (f EFile) GetDepends() ([]Flag, error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var d int64 var d int
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
deps = append(deps, MCQ{d, f.IdExercice, "", []MCQ_entry{}}) deps = append(deps, MCQ{d, f.IdExercice, 0, "", []MCQ_entry{}})
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
return nil, err return nil, err

View File

@ -3,13 +3,14 @@ package fic
import () import ()
type Flag interface { type Flag interface {
GetId() int64 GetId() int
RecoverId() (Flag, error) RecoverId() (Flag, error)
Create(e Exercice) (Flag, error) Create(e Exercice) (Flag, error)
Update() (int64, error) Update() (int64, error)
Delete() (int64, error) Delete() (int64, error)
AddDepend(d Flag) error AddDepend(d Flag) error
GetDepends() ([]Flag, error) GetDepends() ([]Flag, error)
GetOrder() int8
Check(val interface{}) int Check(val interface{}) int
FoundBy(t Team) FoundBy(t Team)
} }

View File

@ -4,9 +4,9 @@ import ()
// FlagChoice represents a choice a respond to a classic flag // FlagChoice represents a choice a respond to a classic flag
type FlagChoice struct { type FlagChoice struct {
Id int64 `json:"id"` Id int `json:"id"`
// IdFlag is the identifier of the underlying flag // IdFlag is the identifier of the underlying flag
IdFlag int64 `json:"idFlag"` IdFlag int `json:"idFlag"`
// Label is the title of the choice as displayed to players // Label is the title of the choice as displayed to players
Label string `json:"label"` Label string `json:"label"`
// Value is the raw content that'll be written as response if this choice is selected // Value is the raw content that'll be written as response if this choice is selected
@ -40,7 +40,7 @@ func (f FlagKey) GetChoices() ([]FlagChoice, error) {
} }
// GetChoice returns a choice for the given Flag. // GetChoice returns a choice for the given Flag.
func (f FlagKey) GetChoice(id int64) (c FlagChoice, err error) { func (f FlagKey) GetChoice(id int) (c FlagChoice, err error) {
if errr := DBQueryRow("SELECT id_choice, id_flag, label, response FROM flag_choices WHERE id_choice = ?", id).Scan(&c.Id, &c.IdFlag, &c.Label, &c.Value); errr != nil { if errr := DBQueryRow("SELECT id_choice, id_flag, label, response FROM flag_choices WHERE id_choice = ?", id).Scan(&c.Id, &c.IdFlag, &c.Label, &c.Value); errr != nil {
return c, errr return c, errr
} }
@ -52,7 +52,8 @@ func (f FlagKey) AddChoice(c FlagChoice) (FlagChoice, error) {
if res, err := DBExec("INSERT INTO flag_choices (id_flag, label, response) VALUES (?, ?, ?)", f.Id, c.Label, c.Value); err != nil { if res, err := DBExec("INSERT INTO flag_choices (id_flag, label, response) VALUES (?, ?, ?)", f.Id, c.Label, c.Value); err != nil {
return c, err return c, err
} else { } else {
c.Id, err = res.LastInsertId() cid, err := res.LastInsertId()
c.Id = int(cid)
return c, err return c, err
} }
} }

View File

@ -12,13 +12,19 @@ import (
// FlagKey represents a flag's challenge, stored as hash. // FlagKey represents a flag's challenge, stored as hash.
type FlagKey struct { type FlagKey struct {
Id int64 `json:"id"` Id int `json:"id"`
// IdExercice is the identifier of the underlying challenge // IdExercice is the identifier of the underlying challenge
IdExercice int64 `json:"idExercice"` IdExercice int64 `json:"idExercice"`
// Order is used to sort the flag between them
Order int8 `json:"order"`
// Label is the title of the flag as displayed to players // Label is the title of the flag as displayed to players
Label string `json:"label"` Label string `json:"label"`
// Type is the kind of flag
Type string `json:"type,omitempty"`
// Placeholder is a small piece of text that aims to add useful information like flag format, ... // Placeholder is a small piece of text that aims to add useful information like flag format, ...
Placeholder string `json:"placeholder"` Placeholder string `json:"placeholder"`
// Help is a description of the flag
Help string `json:"help"`
// IgnoreCase indicates if the case is sensitive to case or not // IgnoreCase indicates if the case is sensitive to case or not
IgnoreCase bool `json:"ignorecase"` IgnoreCase bool `json:"ignorecase"`
// Multiline indicates if the flag is stored on multiple lines // Multiline indicates if the flag is stored on multiple lines
@ -33,7 +39,7 @@ type FlagKey struct {
// 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, type, help, ignorecase, multiline, validator_regexp, 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, ignorecase, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE id_exercice = ?", e.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
@ -43,7 +49,7 @@ func (e Exercice) GetFlagKeys() ([]FlagKey, error) {
var k FlagKey var k FlagKey
k.IdExercice = e.Id k.IdExercice = e.Id
if err := rows.Scan(&k.Id, &k.IdExercice, &k.Label, &k.Placeholder, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &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.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost); err != nil {
return nil, err return nil, err
} }
@ -58,14 +64,14 @@ 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 int64) (k FlagKey, err error) { func GetFlagKey(id int) (k FlagKey, err error) {
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.Placeholder, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost) err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, ignorecase, multiline, validator_regexp, 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.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost)
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) {
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.Placeholder, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost) err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, 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.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost)
return return
} }
@ -126,13 +132,13 @@ func (e Exercice) AddRawFlagKey(name string, placeholder string, ignorecase bool
} }
// GetId returns the Flag identifier. // GetId returns the Flag identifier.
func (k FlagKey) GetId() int64 { func (k FlagKey) GetId() int {
return k.Id return k.Id
} }
// RecoverId returns the Flag identifier as register in DB. // RecoverId returns the Flag identifier as register in DB.
func (k FlagKey) RecoverId() (Flag, error) { func (k FlagKey) RecoverId() (Flag, error) {
if err := DBQueryRow("SELECT id_flag FROM exercice_flags WHERE type LIKE ? AND id_exercice = ?", k.Label, k.IdExercice).Scan(&k.Id); err != nil { if err := DBQueryRow("SELECT id_flag FROM exercice_flags WHERE label LIKE ? AND id_exercice = ?", k.Label, k.IdExercice).Scan(&k.Id); err != nil {
return FlagKey{}, err return FlagKey{}, err
} else { } else {
return k, err return k, err
@ -148,12 +154,12 @@ func (k FlagKey) Create(e Exercice) (Flag, error) {
} }
} }
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.Placeholder, k.IgnoreCase, k.Multiline, k.ValidatorRegexp, k.Checksum, k.ChoicesCost); err != nil { if res, err := DBExec("INSERT INTO exercice_flags (id_exercice, ordre, label, type, placeholder, help, ignorecase, multiline, validator_regexp, cksum, choices_cost) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", e.Id, k.Order, k.Label, k.Type, k.Placeholder, k.Help, k.IgnoreCase, k.Multiline, k.ValidatorRegexp, k.Checksum, k.ChoicesCost); 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
} else { } else {
k.Id = kid k.Id = int(kid)
k.IdExercice = e.Id k.IdExercice = e.Id
return k, nil return k, nil
} }
@ -173,7 +179,7 @@ func (k FlagKey) Update() (int64, error) {
} }
} }
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.Placeholder, k.IgnoreCase, k.Multiline, k.ValidatorRegexp, k.Checksum, k.ChoicesCost, k.Id); err != nil { if res, err := DBExec("UPDATE exercice_flags SET id_exercice = ?, ordre = ?, label = ?, type = ?, placeholder = ?, help = ?, ignorecase = ?, multiline = ?, validator_regexp = ?, cksum = ?, choices_cost = ? WHERE id_flag = ?", k.IdExercice, k.Order, k.Label, k.Type, k.Placeholder, k.Help, k.IgnoreCase, k.Multiline, k.ValidatorRegexp, k.Checksum, k.ChoicesCost, 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
@ -203,6 +209,10 @@ func (k FlagKey) Delete() (int64, error) {
} }
} }
func (k FlagKey) GetOrder() int8 {
return k.Order
}
// AddDepend insert a new dependency to a given flag. // AddDepend insert a new dependency to a given flag.
func (k FlagKey) AddDepend(j Flag) (err error) { func (k FlagKey) AddDepend(j Flag) (err error) {
if d, ok := j.(FlagKey); ok { if d, ok := j.(FlagKey); ok {
@ -225,7 +235,7 @@ func (k FlagKey) GetDepends() ([]Flag, error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var d int64 var d int
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
@ -242,7 +252,7 @@ func (k FlagKey) GetDepends() ([]Flag, error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var d int64 var d int
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }

View File

@ -152,7 +152,7 @@ func (h EHint) GetDepends() ([]Flag, error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var d int64 var d int
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
@ -169,7 +169,7 @@ func (h EHint) GetDepends() ([]Flag, error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var d int64 var d int
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }

View File

@ -8,9 +8,11 @@ import (
// MCQ represents a flag's challenge, in the form of checkbox. // MCQ represents a flag's challenge, in the form of checkbox.
type MCQ struct { type MCQ struct {
Id int64 `json:"id"` Id int `json:"id"`
// IdExercice is the identifier of the underlying challenge // IdExercice is the identifier of the underlying challenge
IdExercice int64 `json:"idExercice"` IdExercice int64 `json:"idExercice"`
// Order is used to sort the flag between them
Order int8 `json:"order"`
// Title is the label of the question // Title is the label of the question
Title string `json:"title"` Title string `json:"title"`
// Entries stores the set of proposed answers // Entries stores the set of proposed answers
@ -19,7 +21,7 @@ type MCQ struct {
// MCQ_entry represents a proposed response for a given MCQ. // MCQ_entry represents a proposed response for a given MCQ.
type MCQ_entry struct { type MCQ_entry struct {
Id int64 `json:"id"` Id int `json:"id"`
// Label is the text displayed to players as proposed answer // Label is the text displayed to players as proposed answer
Label string `json:"label"` Label string `json:"label"`
// Response stores if expected checked state. // Response stores if expected checked state.
@ -27,8 +29,8 @@ type MCQ_entry struct {
} }
// GetMCQ returns a list of flags comming with the challenge. // GetMCQ returns a list of flags comming with the challenge.
func GetMCQ(id int64) (m MCQ, err error) { func GetMCQ(id int) (m MCQ, err error) {
err = DBQueryRow("SELECT id_mcq, id_exercice, title FROM exercice_mcq WHERE id_mcq = ?", id).Scan(&m.Id, &m.IdExercice, &m.Title) err = DBQueryRow("SELECT id_mcq, id_exercice, order, title FROM exercice_mcq WHERE id_mcq = ?", id).Scan(&m.Id, &m.IdExercice, &m.Order, &m.Title)
m.fillEntries() m.fillEntries()
return return
} }
@ -55,7 +57,7 @@ func (m *MCQ) fillEntries() ([]MCQ_entry, error) {
// GetMCQ returns the MCQs coming with the challenge. // GetMCQ returns the MCQs coming with the challenge.
func (e Exercice) GetMCQ() ([]MCQ, error) { func (e Exercice) GetMCQ() ([]MCQ, error) {
if rows, err := DBQuery("SELECT id_mcq, id_exercice, title FROM exercice_mcq WHERE id_exercice = ?", e.Id); err != nil { if rows, err := DBQuery("SELECT id_mcq, id_exercice, ordre, title FROM exercice_mcq WHERE id_exercice = ?", e.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
@ -65,7 +67,7 @@ func (e Exercice) GetMCQ() ([]MCQ, error) {
var m MCQ var m MCQ
m.IdExercice = e.Id m.IdExercice = e.Id
if err := rows.Scan(&m.Id, &m.IdExercice, &m.Title); err != nil { if err := rows.Scan(&m.Id, &m.IdExercice, &m.Order, &m.Title); err != nil {
return nil, err return nil, err
} }
@ -82,8 +84,8 @@ func (e Exercice) GetMCQ() ([]MCQ, error) {
} }
// GetMCQbyChoice returns the MCQ corresponding to a choice ID. // GetMCQbyChoice returns the MCQ corresponding to a choice ID.
func GetMCQbyChoice(cid int64) (m MCQ, c MCQ_entry, err error) { func GetMCQbyChoice(cid int) (m MCQ, c MCQ_entry, err error) {
if errr := DBQueryRow("SELECT id_mcq, id_exercice, title FROM exercice_mcq WHERE id_mcq = (SELECT id_mcq FROM mcq_entries WHERE id_mcq_entry = ?)", cid).Scan(&m.Id, &m.IdExercice, &m.Title); errr != nil { if errr := DBQueryRow("SELECT id_mcq, id_exercice, ordre, title FROM exercice_mcq WHERE id_mcq = (SELECT id_mcq FROM mcq_entries WHERE id_mcq_entry = ?)", cid).Scan(&m.Id, &m.IdExercice, &m.Order, &m.Title); errr != nil {
return MCQ{}, MCQ_entry{}, errr return MCQ{}, MCQ_entry{}, errr
} }
@ -111,7 +113,7 @@ func GetMCQbyChoice(cid int64) (m MCQ, c MCQ_entry, err error) {
} }
// GetId returns the MCQ identifier. // GetId returns the MCQ identifier.
func (m MCQ) GetId() int64 { func (m MCQ) GetId() int {
return m.Id return m.Id
} }
@ -126,12 +128,12 @@ func (m MCQ) RecoverId() (Flag, error) {
// Create registers a MCQ into the database and recursively add its entries. // Create registers a MCQ into the database and recursively add its entries.
func (m MCQ) Create(e Exercice) (Flag, error) { func (m MCQ) Create(e Exercice) (Flag, error) {
if res, err := DBExec("INSERT INTO exercice_mcq (id_exercice, title) VALUES (?, ?)", e.Id, m.Title); err != nil { if res, err := DBExec("INSERT INTO exercice_mcq (id_exercice, ordre, title) VALUES (?, ?, ?)", e.Id, m.Order, m.Title); err != nil {
return m, err return m, err
} else if qid, err := res.LastInsertId(); err != nil { } else if qid, err := res.LastInsertId(); err != nil {
return m, err return m, err
} else { } else {
m.Id = qid m.Id = int(qid)
m.IdExercice = e.Id m.IdExercice = e.Id
// Add entries // Add entries
@ -149,7 +151,7 @@ func (m MCQ) Create(e Exercice) (Flag, error) {
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (m MCQ) Update() (int64, error) { func (m MCQ) Update() (int64, error) {
if res, err := DBExec("UPDATE exercice_mcq SET id_exercice = ?, title = ? WHERE id_mcq = ?", m.IdExercice, m.Title, m.Id); err != nil { if res, err := DBExec("UPDATE exercice_mcq SET id_exercice = ?, ordre = ?, title = ? WHERE id_mcq = ?", m.IdExercice, m.Order, m.Title, m.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
@ -186,7 +188,7 @@ func (m MCQ) AddEntry(e MCQ_entry) (MCQ_entry, error) {
} else if nid, err := res.LastInsertId(); err != nil { } else if nid, err := res.LastInsertId(); err != nil {
return e, err return e, err
} else { } else {
e.Id = nid e.Id = int(nid)
return e, nil return e, nil
} }
} }
@ -236,6 +238,10 @@ func (e Exercice) WipeMCQs() (int64, error) {
} }
} }
func (m MCQ) GetOrder() int8 {
return m.Order
}
// AddDepend insert a new dependency to a given flag. // AddDepend insert a new dependency to a given flag.
func (m MCQ) AddDepend(j Flag) (err error) { func (m MCQ) AddDepend(j Flag) (err error) {
if d, ok := j.(FlagKey); ok { if d, ok := j.(FlagKey); ok {
@ -258,7 +264,7 @@ func (m MCQ) GetDepends() ([]Flag, error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var d int64 var d int
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
@ -276,7 +282,7 @@ func (m MCQ) GetDepends() ([]Flag, error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var d int64 var d int
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
@ -298,8 +304,8 @@ func (c MCQ_entry) GetJustifiedFlag(e Exercice) (FlagKey, error) {
// 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[int64]bool var vals map[int]bool
if va, ok := v.(map[int64]bool); !ok { if va, ok := v.(map[int]bool); !ok {
return -1 return -1
} else { } else {
vals = va vals = va

View File

@ -2,17 +2,17 @@ package fic
import ( import (
"errors" "errors"
"strings"
"strconv" "strconv"
"strings"
) )
type FlagLabel struct { type FlagLabel struct {
Label string Label string
IdChoice int64 IdChoice int
} }
// IsMCQJustification tells you if this key represent a justification from a MCQ. // IsMCQJustification tells you if this key represent a justification from a MCQ.
func (k FlagKey) IsMCQJustification() (bool) { func (k FlagKey) IsMCQJustification() bool {
return len(k.Label) > 0 && k.Label[0] == '%' return len(k.Label) > 0 && k.Label[0] == '%'
} }
@ -20,7 +20,9 @@ func (k FlagKey) IsMCQJustification() (bool) {
func (k FlagKey) GetMCQJustification() (fl FlagLabel, err error) { func (k FlagKey) GetMCQJustification() (fl FlagLabel, err error) {
spl := strings.Split(k.Label, "%") spl := strings.Split(k.Label, "%")
if len(spl) >= 3 && len(spl[0]) == 0 { if len(spl) >= 3 && len(spl[0]) == 0 {
fl.IdChoice, err = strconv.ParseInt(spl[1], 10, 64) var idChoice int64
idChoice, err = strconv.ParseInt(spl[1], 10, 32)
fl.IdChoice = int(idChoice)
fl.Label = strings.Join(spl[2:], "%") fl.Label = strings.Join(spl[2:], "%")
} else { } else {
err = errors.New("This is not a MCQ justification") err = errors.New("This is not a MCQ justification")

View File

@ -27,50 +27,46 @@ type myTeamHint struct {
Cost int64 `json:"cost"` Cost int64 `json:"cost"`
} }
type myTeamFlag struct { type myTeamFlag struct {
Label string `json:"label"` Order int8 `json:"order"`
Placeholder string `json:"placeholder,omitempty"` Label string `json:"label"`
Separator string `json:"separator,omitempty"` Type string `json:"type,omitempty"`
NbLines uint64 `json:"nb_lines,omitempty"` Placeholder string `json:"placeholder,omitempty"`
IgnoreOrder bool `json:"ignore_order,omitempty"` Help string `json:"help,omitempty"`
IgnoreCase bool `json:"ignore_case,omitempty"` Separator string `json:"separator,omitempty"`
Multiline bool `json:"multiline,omitempty"` NbLines uint64 `json:"nb_lines,omitempty"`
ValidatorRe *string `json:"validator_regexp,omitempty"` IgnoreOrder bool `json:"ignore_order,omitempty"`
Solved *time.Time `json:"found,omitempty"` IgnoreCase bool `json:"ignore_case,omitempty"`
Soluce string `json:"soluce,omitempty"` Multiline bool `json:"multiline,omitempty"`
Choices map[string]string `json:"choices,omitempty"` ValidatorRe *string `json:"validator_regexp,omitempty"`
ChoicesCost int64 `json:"choices_cost,omitempty"` Solved *time.Time `json:"found,omitempty"`
PSolved *time.Time `json:"part_solved,omitempty"`
Soluce string `json:"soluce,omitempty"`
Justify bool `json:"justify,omitempty"`
Choices map[string]interface{} `json:"choices,omitempty"`
ChoicesCost int64 `json:"choices_cost,omitempty"`
} }
type myTeamMCQJustifiedChoice struct { type myTeamMCQJustifiedChoice struct {
Label string `json:"label"` Label string `json:"label"`
Value bool `json:"value,omitempty"` Value bool `json:"value,omitempty"`
Justification myTeamFlag `json:"justification,omitempty"` Justification myTeamFlag `json:"justification,omitempty"`
} }
type myTeamMCQ struct {
Title string `json:"title"`
Justify bool `json:"justify,omitempty"`
Choices map[int64]interface{} `json:"choices,omitempty"`
Solved *time.Time `json:"solved,omitempty"`
PSolved *time.Time `json:"part_solved,omitempty"`
Soluce string `json:"soluce,omitempty"`
}
type myTeamExercice struct { type myTeamExercice struct {
ThemeId int64 `json:"theme_id"` ThemeId int64 `json:"theme_id"`
Statement string `json:"statement"` Statement string `json:"statement"`
Overview string `json:"overview,omitempty"` Overview string `json:"overview,omitempty"`
Finished string `json:"finished,omitempty"` Finished string `json:"finished,omitempty"`
Hints []myTeamHint `json:"hints,omitempty"` Hints []myTeamHint `json:"hints,omitempty"`
Gain int `json:"gain"` Gain int `json:"gain"`
Files []myTeamFile `json:"files,omitempty"` Files []myTeamFile `json:"files,omitempty"`
Flags map[int64]myTeamFlag `json:"flags,omitempty"` Flags map[int]myTeamFlag `json:"flags,omitempty"`
MCQs map[int64]myTeamMCQ `json:"mcqs,omitempty"` SolveDist int64 `json:"solve_dist,omitempty"`
SolveDist int64 `json:"solve_dist,omitempty"` SolvedTime *time.Time `json:"solved_time,omitempty"`
SolvedTime *time.Time `json:"solved_time,omitempty"` SolvedRank int64 `json:"solved_rank,omitempty"`
SolvedRank int64 `json:"solved_rank,omitempty"` Tries int64 `json:"tries,omitempty"`
Tries int64 `json:"tries,omitempty"` TotalTries int64 `json:"total_tries,omitempty"`
TotalTries int64 `json:"total_tries,omitempty"` VideoURI string `json:"video_uri,omitempty"`
VideoURI string `json:"video_uri,omitempty"` Issue string `json:"issue,omitempty"`
Issue string `json:"issue,omitempty"` IssueKind string `json:"issuekind,omitempty"`
IssueKind string `json:"issuekind,omitempty"`
} }
type myTeam struct { type myTeam struct {
Id int64 `json:"team_id"` Id int64 `json:"team_id"`
@ -179,8 +175,8 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
// Expose exercice flags // Expose exercice flags
justifiedMCQ := map[int64]myTeamFlag{} justifiedMCQ := map[int]myTeamFlag{}
exercice.Flags = map[int64]myTeamFlag{} exercice.Flags = map[int]myTeamFlag{}
if flags, err := e.GetFlagKeys(); err != nil { if flags, err := e.GetFlagKeys(); err != nil {
return nil, err return nil, err
@ -188,6 +184,8 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
for _, k := range flags { for _, k := range flags {
var flag myTeamFlag var flag myTeamFlag
flag.Order = k.Order
if !DisplayAllFlags && t != nil && !t.CanSeeFlag(k) { if !DisplayAllFlags && t != nil && !t.CanSeeFlag(k) {
// Dependancy missing, skip the flag for now // Dependancy missing, skip the flag for now
continue continue
@ -225,7 +223,7 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
if choices, err := k.GetChoices(); err != nil { if choices, err := k.GetChoices(); err != nil {
return nil, err return nil, err
} else if t == nil || WChoiceCoefficient < 0 || k.ChoicesCost == 0 || t.SeeChoices(k) { } else if t == nil || WChoiceCoefficient < 0 || k.ChoicesCost == 0 || t.SeeChoices(k) {
flag.Choices = map[string]string{} flag.Choices = map[string]interface{}{}
for _, c := range choices { for _, c := range choices {
flag.Choices[c.Value] = c.Label flag.Choices[c.Value] = c.Label
} }
@ -243,10 +241,6 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
} }
} }
// Expose exercice MCQs
exercice.MCQs = map[int64]myTeamMCQ{}
if mcqs, err := e.GetMCQ(); err != nil { if mcqs, err := e.GetMCQ(); err != nil {
return nil, err return nil, err
} else { } else {
@ -256,9 +250,11 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
continue continue
} }
m := myTeamMCQ{ m := myTeamFlag{
Title: mcq.Title, Type: "mcq",
Choices: map[int64]interface{}{}, Label: mcq.Title,
Order: mcq.Order,
Choices: map[string]interface{}{},
} }
soluce := "" soluce := ""
@ -292,12 +288,12 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
jc.Value = e.Response jc.Value = e.Response
} }
m.Choices[e.Id] = jc m.Choices[strconv.Itoa(e.Id)] = jc
} else { } else {
m.Choices[e.Id] = e.Label m.Choices[strconv.Itoa(e.Id)] = e.Label
} }
} else { } else {
m.Choices[e.Id] = e.Label m.Choices[strconv.Itoa(e.Id)] = e.Label
} }
} }
@ -311,7 +307,7 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
m.PSolved = nil m.PSolved = nil
} }
exercice.MCQs[mcq.Id] = m exercice.Flags[mcq.Id] = m
} }
} }