Able to check MCQ
This commit is contained in:
parent
037f27c62c
commit
6903c91df2
6 changed files with 79 additions and 13 deletions
|
@ -14,17 +14,22 @@ import (
|
||||||
"srs.epita.fr/fic-server/libfic"
|
"srs.epita.fr/fic-server/libfic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type ResponsesUpload struct {
|
||||||
|
Keys map[string]string `json:"flags"`
|
||||||
|
MCQs map[int64]bool `json:"mcqs"`
|
||||||
|
}
|
||||||
|
|
||||||
func treatSubmission(pathname string, team fic.Team, exercice_id string) {
|
func treatSubmission(pathname string, team fic.Team, exercice_id string) {
|
||||||
bid := make([]byte, 5)
|
bid := make([]byte, 5)
|
||||||
binary.LittleEndian.PutUint32(bid, rand.Uint32())
|
binary.LittleEndian.PutUint32(bid, rand.Uint32())
|
||||||
id := "[" + base64.StdEncoding.EncodeToString(bid) + "]"
|
id := "[" + base64.StdEncoding.EncodeToString(bid) + "]"
|
||||||
log.Println(id, "New submission receive", pathname)
|
log.Println(id, "New submission receive", pathname)
|
||||||
|
|
||||||
var keys map[string]string
|
var responses ResponsesUpload
|
||||||
|
|
||||||
if cnt_raw, err := ioutil.ReadFile(pathname); err != nil {
|
if cnt_raw, err := ioutil.ReadFile(pathname); err != nil {
|
||||||
log.Println(id, "[ERR]", err)
|
log.Println(id, "[ERR]", err)
|
||||||
} else if err := json.Unmarshal(cnt_raw, &keys); err != nil {
|
} else if err := json.Unmarshal(cnt_raw, &responses); err != nil {
|
||||||
log.Println(id, "[ERR]", err)
|
log.Println(id, "[ERR]", err)
|
||||||
} else if eid, err := strconv.Atoi(exercice_id); err != nil {
|
} else if eid, err := strconv.Atoi(exercice_id); err != nil {
|
||||||
log.Println(id, "[ERR]", err)
|
log.Println(id, "[ERR]", err)
|
||||||
|
@ -35,7 +40,7 @@ func treatSubmission(pathname string, team fic.Team, exercice_id string) {
|
||||||
} else if s, tm, _ := team.HasSolved(exercice); s {
|
} else if s, tm, _ := team.HasSolved(exercice); s {
|
||||||
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)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
||||||
} else {
|
} else {
|
||||||
if solved, err := exercice.CheckResponse(keys, team); err != nil {
|
if solved, err := exercice.CheckResponse(responses.Keys, responses.MCQs, team); err != nil {
|
||||||
log.Println(id, "[ERR]", err)
|
log.Println(id, "[ERR]", err)
|
||||||
genTeamMyFile(team)
|
genTeamMyFile(team)
|
||||||
} else if solved {
|
} else if solved {
|
||||||
|
|
12
libfic/db.go
12
libfic/db.go
|
@ -160,6 +160,18 @@ CREATE TABLE IF NOT EXISTS mcq_entries(
|
||||||
response BOOLEAN NOT NULL,
|
response BOOLEAN NOT NULL,
|
||||||
FOREIGN KEY(id_mcq) REFERENCES exercice_mcq(id_mcq)
|
FOREIGN KEY(id_mcq) REFERENCES exercice_mcq(id_mcq)
|
||||||
);
|
);
|
||||||
|
`); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS mcq_found(
|
||||||
|
id_mcq INTEGER NOT NULL,
|
||||||
|
id_team INTEGER NOT NULL,
|
||||||
|
time TIMESTAMP NOT NULL,
|
||||||
|
CONSTRAINT uq_found UNIQUE (id_mcq,id_team),
|
||||||
|
FOREIGN KEY(id_mcq) REFERENCES exercice_mcq(id_mcq),
|
||||||
|
FOREIGN KEY(id_team) REFERENCES teams(id_team)
|
||||||
|
);
|
||||||
`); err != nil {
|
`); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var PartialValidation bool
|
var PartialValidation bool
|
||||||
|
var PartialMCQValidation bool
|
||||||
|
|
||||||
type Exercice struct {
|
type Exercice struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
|
@ -202,19 +203,41 @@ func (e Exercice) TriedCount() int64 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Exercice) CheckResponse(resps map[string]string, t Team) (bool, error) {
|
func (e Exercice) CheckResponse(respkeys map[string]string, respmcq map[int64]bool, t Team) (bool, error) {
|
||||||
if err := e.NewTry(t); err != nil {
|
if err := e.NewTry(t); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
} else if keys, err := e.GetKeys(); err != nil {
|
} else if keys, err := e.GetKeys(); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
} else {
|
} else if mcqs, err := e.GetMCQ(); err != nil {
|
||||||
if len(keys) < 1 {
|
return false, err
|
||||||
|
} else if len(keys) < 1 && len(mcqs) < 1 {
|
||||||
return true, errors.New("Exercice with no key registered")
|
return true, errors.New("Exercice with no key registered")
|
||||||
|
} else {
|
||||||
|
valid := true
|
||||||
|
diff := 0
|
||||||
|
|
||||||
|
// Check MCQs
|
||||||
|
for _, mcq := range mcqs {
|
||||||
|
if d := mcq.Check(respmcq); d > 0 {
|
||||||
|
if !PartialValidation || t.HasPartiallyRespond(mcq) == nil {
|
||||||
|
valid = false
|
||||||
|
diff += d
|
||||||
|
}
|
||||||
|
} else if !PartialMCQValidation {
|
||||||
|
mcq.FoundBy(t)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
valid := true
|
// Validate MCQs if no error
|
||||||
|
if valid {
|
||||||
|
for _, mcq := range mcqs {
|
||||||
|
mcq.FoundBy(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check keys
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
if res, ok := resps[key.Label]; !ok {
|
if res, ok := respkeys[key.Label]; !ok {
|
||||||
valid = false
|
valid = false
|
||||||
} else if !key.Check(res) {
|
} else if !key.Check(res) {
|
||||||
if !PartialValidation || t.HasPartiallySolved(key) == nil {
|
if !PartialValidation || t.HasPartiallySolved(key) == nil {
|
||||||
|
@ -225,6 +248,10 @@ func (e Exercice) CheckResponse(resps map[string]string, t Team) (bool, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if diff > 0 {
|
||||||
|
e.UpdateTry(t, diff)
|
||||||
|
}
|
||||||
|
|
||||||
return valid, nil
|
return valid, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package fic
|
package fic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MCQ struct {
|
type MCQ struct {
|
||||||
|
@ -32,13 +33,23 @@ func (e Exercice) GetMCQ() ([]MCQ, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if entries_rows, err := DBQuery("SELECT id_mcq, id_exercice, label, response FROM mcq_entries WHERE id_mcq = ?", m.Id); err != nil {
|
if entries_rows, err := DBQuery("SELECT id_mcq_entry, label, response FROM mcq_entries WHERE id_mcq = ?", m.Id); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
defer entries_rows.Close()
|
defer entries_rows.Close()
|
||||||
|
|
||||||
mcqs = append(mcqs, m)
|
for entries_rows.Next() {
|
||||||
|
var e MCQ_entry
|
||||||
|
|
||||||
|
if err := entries_rows.Scan(&e.Id, &e.Label, &e.Response); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.Entries = append(m.Entries, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mcqs = append(mcqs, m)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -110,6 +121,7 @@ func (n MCQ_entry) Delete() (int64, error) {
|
||||||
|
|
||||||
func (m MCQ) Check(vals map[int64]bool) int {
|
func (m MCQ) Check(vals map[int64]bool) int {
|
||||||
diff := 0
|
diff := 0
|
||||||
|
|
||||||
for _, n := range m.Entries {
|
for _, n := range m.Entries {
|
||||||
if v, ok := vals[n.Id]; ok && v == n.Response {
|
if v, ok := vals[n.Id]; ok && v == n.Response {
|
||||||
continue
|
continue
|
||||||
|
@ -119,3 +131,7 @@ func (m MCQ) Check(vals map[int64]bool) int {
|
||||||
|
|
||||||
return diff
|
return diff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m MCQ) FoundBy(t Team) {
|
||||||
|
DBExec("INSERT INTO mcq_found (id_mcq, id_team, time) VALUES (?, ?, ?)", m.Id, t.Id, time.Now())
|
||||||
|
}
|
||||||
|
|
|
@ -18,13 +18,13 @@ func truncateTable(tables ...string) (error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResetGame() (error) {
|
func ResetGame() (error) {
|
||||||
return truncateTable("team_hints", "key_found", "exercice_solved", "exercice_tries")
|
return truncateTable("team_hints", "key_found", "mcq_found", "exercice_solved", "exercice_tries")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResetExercices() (error) {
|
func ResetExercices() (error) {
|
||||||
return truncateTable("team_hints", "exercice_files", "key_found", "exercice_keys", "exercice_solved", "exercice_tries", "exercice_hints", "mcq_entries", "exercice_mcq", "exercices", "themes")
|
return truncateTable("team_hints", "exercice_files", "key_found", "exercice_keys", "exercice_solved", "exercice_tries", "exercice_hints", "mcq_found", "mcq_entries", "exercice_mcq", "exercices", "themes")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResetTeams() (error) {
|
func ResetTeams() (error) {
|
||||||
return truncateTable("team_hints", "key_found", "exercice_solved", "exercice_tries", "team_members", "teams")
|
return truncateTable("team_hints", "key_found", "mcq_found", "exercice_solved", "exercice_tries", "team_members", "teams")
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,3 +173,9 @@ func (t Team) HasPartiallySolved(k Key) (*time.Time) {
|
||||||
DBQueryRow("SELECT MIN(time) FROM key_found WHERE id_team = ? AND id_key = ?", t.Id, k.Id).Scan(&tm)
|
DBQueryRow("SELECT MIN(time) FROM key_found WHERE id_team = ? AND id_key = ?", t.Id, k.Id).Scan(&tm)
|
||||||
return tm
|
return tm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t Team) HasPartiallyRespond(m MCQ) (*time.Time) {
|
||||||
|
var tm *time.Time
|
||||||
|
DBQueryRow("SELECT MIN(time) FROM mcq_found WHERE id_team = ? AND id_mcq = ?", t.Id, m.Id).Scan(&tm)
|
||||||
|
return tm
|
||||||
|
}
|
||||||
|
|
Reference in a new issue