diff --git a/backend/submission.go b/backend/submission.go index 12f9c1fa..5d4b922a 100644 --- a/backend/submission.go +++ b/backend/submission.go @@ -19,6 +19,7 @@ import ( type ResponsesUpload struct { Keys map[int64]string `json:"flags"` MCQs map[int64]bool `json:"mcqs"` + MCQJ map[int64]string `json:"justifications"` } func treatSubmission(pathname string, team fic.Team, exercice_id string) { @@ -78,6 +79,25 @@ func treatSubmission(pathname string, team fic.Team, exercice_id string) { return } + // Handle MCQ justifications: convert to expected keyid + for cid, j := range responses.MCQJ { + if mcq, choice, err := fic.GetMCQbyChoice(cid); err != nil { + log.Println(id, "[ERR] Unable to retrieve mcq from justification:", err) + return + } else if mcq.IdExercice != exercice.Id { + log.Println(id, "[ERR] We retrieve an invalid MCQ: from exercice", mcq.IdExercice, "whereas expected from exercice", exercice.Id) + return + } else if key, err := mcq.GetJustifiedFlag(exercice, choice); err != nil { + log.Println(id, "[ERR] Unable to retrieve mcq justification flag:", err) + return + } else { + if responses.Keys == nil { + responses.Keys = map[int64]string{} + } + responses.Keys[key.Id] = j + } + } + // Check given answers solved, err := exercice.CheckResponse(cksum[:], responses.Keys, responses.MCQs, team) if err != nil { diff --git a/frontend/static/js/challenge.js b/frontend/static/js/challenge.js index 11ba9d54..0d755ab2 100644 --- a/frontend/static/js/challenge.js +++ b/frontend/static/js/challenge.js @@ -268,11 +268,12 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"]) }); $scope.ssubmit = function() { - var resp = {"flags":{}} + var resp = {} var check = undefined if ($scope.my.exercices[$rootScope.current_exercice].flags && Object.keys($scope.my.exercices[$rootScope.current_exercice].flags).length) { + resp["flags"] = {}; angular.forEach($scope.my.exercices[$rootScope.current_exercice].flags, function(flag,kid) { if (flag.found == null) { if (flag.soluce !== undefined) { @@ -293,7 +294,6 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"]) var soluce = ""; resp["mcqs"] = {}; angular.forEach($scope.my.exercices[$rootScope.current_exercice].mcqs, function(mcq) { - var nid = 0; if (mcq.solved == null) { angular.forEach(mcq.choices, function(choice, cid) { if (mcq.soluce !== undefined) { @@ -304,10 +304,10 @@ angular.module("FICApp", ["ngRoute", "ngSanitize"]) if (choice.value) { resp["mcqs"][cid] = choice.value; if (mcq.justify !== undefined) { + if (resp["justifications"] == undefined) + resp["justifications"] = {}; if (choice.justify) - resp["flags"][mcq.justify[nid++]] = choice.justify; - else if (!choice.solved) - nid++; + resp["justifications"][cid] = choice.justify; } } } diff --git a/frontend/static/views/defi.html b/frontend/static/views/defi.html index c893db2e..aa3cdbe1 100644 --- a/frontend/static/views/defi.html +++ b/frontend/static/views/defi.html @@ -94,7 +94,7 @@
- +

diff --git a/libfic/flag.go b/libfic/flag.go index e13b8e60..10249ad6 100644 --- a/libfic/flag.go +++ b/libfic/flag.go @@ -52,6 +52,12 @@ func (e Exercice) GetFlags() ([]Flag, error) { } } +// GetFlagByLabel returns a flag matching the given label. +func (e Exercice) GetFlagByLabel(label string) (k Flag, err error) { + err = DBQueryRow("SELECT id_flag, id_exercice, type, help, ignorecase, validator_regexp, cksum FROM exercice_flags WHERE type = ? AND id_exercice = ?", label, e.Id).Scan(&k.Id, &k.IdExercice, &k.Label, &k.Help, &k.IgnoreCase, &k.ValidatorRegexp, &k.Checksum) + return +} + // getHashedFlag calculates the expected checksum for the given raw_value. func getHashedFlag(raw_value []byte) [blake2b.Size]byte { hash := blake2b.Sum512(raw_value) diff --git a/libfic/mcq.go b/libfic/mcq.go index 205da856..067858af 100644 --- a/libfic/mcq.go +++ b/libfic/mcq.go @@ -66,6 +66,35 @@ func (e Exercice) GetMCQ() ([]MCQ, error) { } } +// GetMCQbyChoice returns the MCQ corresponding to a choice ID. +func GetMCQbyChoice(cid int64) (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); err != nil { + return MCQ{}, MCQ_entry{}, errr + } + + if entries_rows, errr := DBQuery("SELECT id_mcq_entry, label, response FROM mcq_entries WHERE id_mcq = ?", m.Id); err != nil { + return MCQ{}, MCQ_entry{}, errr + } else { + defer entries_rows.Close() + + for entries_rows.Next() { + var e MCQ_entry + + if err = entries_rows.Scan(&e.Id, &e.Label, &e.Response); err != nil { + return + } + + if e.Id == cid { + c = e + } + + m.Entries = append(m.Entries, e) + } + } + + return +} + // AddMCQ creates and fills a new struct MCQ and registers it into the database. func (e Exercice) AddMCQ(title string) (MCQ, error) { if res, err := DBExec("INSERT INTO exercice_mcq (id_exercice, title) VALUES (?, ?)", e.Id, title); err != nil { @@ -145,6 +174,11 @@ func (e Exercice) WipeMCQs() (int64, error) { } } +// GetJustifiedFlag searchs for a flag in the scope of the given exercice. +func (m MCQ) GetJustifiedFlag(e Exercice, c MCQ_entry) (Flag, error) { + return e.GetFlagByLabel("%" + m.Title + "%" + c.Label) +} + // Check if the given vals are the expected ones to validate this flag. func (m MCQ) Check(vals map[int64]bool) int { diff := 0 diff --git a/libfic/team_my.go b/libfic/team_my.go index 48e4ea8e..da3220c5 100644 --- a/libfic/team_my.go +++ b/libfic/team_my.go @@ -23,7 +23,7 @@ type myTeamHint struct { } type myTeamMCQ struct { Title string `json:"title"` - Justify []int64 `json:"justify,omitempty"` + Justify bool `json:"justify,omitempty"` Choices map[int64]string `json:"choices,omitempty"` Solved *time.Time `json:"solved,omitempty"` PSolved map[int64]int `json:"checks_solved,omitempty"` @@ -211,8 +211,6 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) { soluce := "" solved_justify := true - var nb_gen_justify_id int64 - var max_justify_id int64 for _, e := range mcq.Entries { m.Choices[e.Id] = e.Label @@ -222,31 +220,18 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) { soluce += "f" } if v, ok := justifiedMCQ[m.Title + "%" + e.Label]; ok { - if m.Justify == nil { - m.Justify = []int64{} - } + m.Justify = true if t == nil { soluce += hex.EncodeToString(v) } - if v, ok := justifiedMCQ_ids[m.Title + "%" + e.Label]; ok { + if _, ok := justifiedMCQ_ids[m.Title + "%" + e.Label]; ok { solved_justify = false - m.Justify = append(m.Justify, v) - if v > max_justify_id { - max_justify_id = v - } } - } else { - nb_gen_justify_id += 1 } } - // Fill the rest of the array with factice values in order to hide number of valid choices - for i := int64(0); i < nb_gen_justify_id; i++ { - m.Justify = append(m.Justify, max_justify_id + 1 + i) - } - if t != nil { if solved_justify { m.Solved = t.HasPartiallyRespond(mcq)