server/libfic/mcq.go

348 lines
10 KiB
Go
Raw Normal View History

package fic
import (
"errors"
"fmt"
2017-12-16 00:16:30 +00:00
"time"
)
2018-03-09 18:07:08 +00:00
// MCQ represents a flag's challenge, in the form of checkbox.
type MCQ struct {
Id int `json:"id"`
2018-03-09 18:07:08 +00:00
// IdExercice is the identifier of the underlying challenge
IdExercice int64 `json:"idExercice"`
// Order is used to sort the flag between them
Order int8 `json:"order"`
2018-03-09 18:07:08 +00:00
// Title is the label of the question
Title string `json:"title"`
2018-03-09 18:07:08 +00:00
// Entries stores the set of proposed answers
2021-11-22 14:35:07 +00:00
Entries []*MCQ_entry `json:"entries"`
}
2018-03-09 18:07:08 +00:00
// MCQ_entry represents a proposed response for a given MCQ.
type MCQ_entry struct {
Id int `json:"id"`
2018-03-09 18:07:08 +00:00
// Label is the text displayed to players as proposed answer
Label string `json:"label"`
2018-03-09 18:07:08 +00:00
// Response stores if expected checked state.
Response bool `json:"response"`
}
2020-01-20 16:28:37 +00:00
// GetMCQ returns a list of flags comming with the challenge.
2021-11-22 14:35:07 +00:00
func GetMCQ(id int) (m *MCQ, err error) {
m = &MCQ{}
2022-05-16 09:38:46 +00:00
err = DBQueryRow("SELECT id_mcq, id_exercice, ordre, title FROM exercice_mcq WHERE id_mcq = ?", id).Scan(&m.Id, &m.IdExercice, &m.Order, &m.Title)
2020-01-20 16:28:37 +00:00
m.fillEntries()
return
}
2021-11-22 14:35:07 +00:00
func (m *MCQ) fillEntries() ([]*MCQ_entry, error) {
2020-01-20 16:28:37 +00:00
if entries_rows, err := DBQuery("SELECT id_mcq_entry, label, response FROM mcq_entries WHERE id_mcq = ?", m.Id); err != nil {
return nil, err
} else {
defer entries_rows.Close()
for entries_rows.Next() {
2021-11-22 14:35:07 +00:00
e := &MCQ_entry{}
2020-01-20 16:28:37 +00:00
if err := entries_rows.Scan(&e.Id, &e.Label, &e.Response); err != nil {
return nil, err
}
m.Entries = append(m.Entries, e)
}
}
return m.Entries, nil
}
2018-03-09 18:07:08 +00:00
// GetMCQ returns the MCQs coming with the challenge.
2021-11-22 14:35:07 +00:00
func (e *Exercice) GetMCQ() ([]*MCQ, error) {
if rows, err := DBQuery("SELECT id_mcq, id_exercice, ordre, title FROM exercice_mcq WHERE id_exercice = ?", e.Id); err != nil {
return nil, err
} else {
defer rows.Close()
2021-11-22 14:35:07 +00:00
var mcqs = []*MCQ{}
for rows.Next() {
2021-11-22 14:35:07 +00:00
m := &MCQ{}
m.IdExercice = e.Id
if err := rows.Scan(&m.Id, &m.IdExercice, &m.Order, &m.Title); err != nil {
return nil, err
}
2020-01-20 16:28:37 +00:00
m.fillEntries()
2017-12-16 00:16:30 +00:00
mcqs = append(mcqs, m)
}
if err := rows.Err(); err != nil {
return nil, err
}
return mcqs, nil
}
}
2022-05-16 09:38:46 +00:00
// GetMCQById returns a MCQs.
func (e *Exercice) GetMCQById(id int) (m *MCQ, err error) {
m = &MCQ{}
err = DBQueryRow("SELECT id_mcq, id_exercice, ordre, title FROM exercice_mcq WHERE id_mcq = ? AND id_exercice = ?", id, e.Id).Scan(&m.Id, &m.IdExercice, &m.Order, &m.Title)
m.fillEntries()
return
}
// GetMCQbyChoice returns the MCQ corresponding to a choice ID.
2021-11-22 14:35:07 +00:00
func GetMCQbyChoice(cid int) (m *MCQ, c *MCQ_entry, err error) {
m = &MCQ{}
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 {
2021-11-22 14:35:07 +00:00
return nil, nil, errr
}
2020-01-18 22:45:28 +00:00
if entries_rows, errr := DBQuery("SELECT id_mcq_entry, label, response FROM mcq_entries WHERE id_mcq = ?", m.Id); errr != nil {
2021-11-22 14:35:07 +00:00
return nil, nil, errr
} else {
defer entries_rows.Close()
for entries_rows.Next() {
2021-11-22 14:35:07 +00:00
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
}
// GetId returns the MCQ identifier.
2021-11-22 14:35:07 +00:00
func (m *MCQ) GetId() int {
return m.Id
}
// RecoverId returns the MCQ identifier as register in DB.
2021-11-22 14:35:07 +00:00
func (m *MCQ) RecoverId() (Flag, error) {
if err := DBQueryRow("SELECT id_mcq FROM exercice_mcq WHERE title LIKE ? AND id_exercice = ?", m.Title, m.IdExercice).Scan(&m.Id); err != nil {
2021-11-22 14:35:07 +00:00
return nil, err
} else {
return m, err
}
}
// Create registers a MCQ into the database and recursively add its entries.
2021-11-22 14:35:07 +00:00
func (m *MCQ) Create(e *Exercice) (Flag, error) {
if res, err := DBExec("INSERT INTO exercice_mcq (id_exercice, ordre, title) VALUES (?, ?, ?)", e.Id, m.Order, m.Title); err != nil {
return m, err
} else if qid, err := res.LastInsertId(); err != nil {
return m, err
} else {
m.Id = int(qid)
m.IdExercice = e.Id
// Add entries
for k, entry := range m.Entries {
if entry, err = m.AddEntry(entry); err != nil {
return m, err
} else {
m.Entries[k] = entry
}
}
return m, nil
}
}
2018-03-09 18:07:08 +00:00
// Update applies modifications back to the database.
2021-11-22 14:35:07 +00:00
func (m *MCQ) Update() (int64, error) {
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
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
2018-03-09 18:07:08 +00:00
// Delete the MCQ from the database.
2021-11-22 14:35:07 +00:00
func (m *MCQ) Delete() (int64, error) {
2020-01-20 16:28:37 +00:00
if _, err := DBExec("DELETE FROM exercice_files_omcq_deps WHERE id_mcq = ?", m.Id); err != nil {
return 0, err
} else if _, err := DBExec("DELETE FROM exercice_mcq_okey_deps WHERE id_mcq = ?", m.Id); err != nil {
return 0, err
2020-01-20 16:29:34 +00:00
} else if _, err := DBExec("DELETE FROM exercice_mcq_omcq_deps WHERE id_mcq = ?", m.Id); err != nil {
return 0, err
} else if _, err := DBExec("DELETE FROM exercice_mcq_omcq_deps WHERE id_mcq_dep = ?", m.Id); err != nil {
return 0, err
} else if _, err := DBExec("DELETE FROM exercice_flags_omcq_deps WHERE id_mcq_dep = ?", m.Id); err != nil {
return 0, err
2021-09-02 00:25:18 +00:00
} else if _, err := DBExec("DELETE FROM exercice_hints_omcq_deps WHERE id_mcq_dep = ?", m.Id); err != nil {
return 0, err
} else if res, err := DBExec("DELETE FROM exercice_mcq WHERE id_mcq = ?", m.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
2018-03-09 18:07:08 +00:00
// AddEntry creates and fills a new struct MCQ_entry and registers it into the database.
2021-11-22 14:35:07 +00:00
func (m *MCQ) AddEntry(e *MCQ_entry) (*MCQ_entry, error) {
if res, err := DBExec("INSERT INTO mcq_entries (id_mcq, label, response) VALUES (?, ?, ?)", m.Id, e.Label, e.Response); err != nil {
return e, err
} else if nid, err := res.LastInsertId(); err != nil {
return e, err
} else {
e.Id = int(nid)
return e, nil
}
}
2018-03-09 18:07:08 +00:00
// Update applies modifications back to the database.
2021-11-22 14:35:07 +00:00
func (n *MCQ_entry) Update() (int64, error) {
if res, err := DBExec("UPDATE mcq_entries SET label = ?, response = ? WHERE id_mcq = ?", n.Label, n.Response, n.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
2018-03-09 18:07:08 +00:00
// Delete the MCQ entry from the database.
2021-11-22 14:35:07 +00:00
func (n *MCQ_entry) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM mcq_entries WHERE id_mcq_entry = ?", n.Id); err != nil {
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
2018-03-09 18:07:08 +00:00
// WipeMCQs deletes MCQs coming with the challenge.
2021-11-22 14:35:07 +00:00
func (e *Exercice) WipeMCQs() (int64, error) {
2020-01-20 16:28:37 +00:00
if _, err := DBExec("DELETE FROM exercice_files_omcq_deps WHERE id_mcq IN (SELECT id_mcq FROM exercice_mcq WHERE id_exercice = ?)", e.Id); err != nil {
return 0, err
} else if _, err := DBExec("DELETE FROM mcq_entries WHERE id_mcq IN (SELECT id_mcq FROM exercice_mcq WHERE id_exercice = ?);", e.Id); err != nil {
2018-06-24 17:09:34 +00:00
return 0, err
} else if _, err := DBExec("DELETE FROM exercice_flags_omcq_deps WHERE id_mcq_dep IN (SELECT id_mcq FROM exercice_mcq WHERE id_exercice = ?);", e.Id); err != nil {
return 0, err
} else if _, err := DBExec("DELETE FROM exercice_mcq_okey_deps WHERE id_mcq IN (SELECT id_mcq FROM exercice_mcq WHERE id_exercice = ?);", e.Id); err != nil {
return 0, err
2020-01-20 16:29:34 +00:00
} else if _, err := DBExec("DELETE FROM exercice_mcq_omcq_deps WHERE id_mcq IN (SELECT id_mcq FROM exercice_mcq WHERE id_exercice = ?);", e.Id); err != nil {
return 0, err
} else if _, err := DBExec("DELETE FROM exercice_mcq_omcq_deps WHERE id_mcq_dep IN (SELECT id_mcq FROM exercice_mcq WHERE id_exercice = ?);", e.Id); err != nil {
return 0, err
2018-06-24 17:09:34 +00:00
} else if res, err := DBExec("DELETE FROM exercice_mcq WHERE id_exercice = ?;", e.Id); err != nil {
2017-12-16 02:39:57 +00:00
return 0, err
} else if nb, err := res.RowsAffected(); err != nil {
return 0, err
} else {
return nb, err
}
}
2021-11-22 14:35:07 +00:00
func (m *MCQ) GetOrder() int8 {
return m.Order
}
// AddDepend insert a new dependency to a given flag.
2021-11-22 14:35:07 +00:00
func (m *MCQ) AddDepend(j Flag) (err error) {
if d, ok := j.(*FlagKey); ok {
_, err = DBExec("INSERT INTO exercice_mcq_okey_deps (id_mcq, id_flag_dep) VALUES (?, ?)", m.Id, d.Id)
2021-11-22 14:35:07 +00:00
} else if d, ok := j.(*MCQ); ok {
2020-01-20 16:29:34 +00:00
_, err = DBExec("INSERT INTO exercice_mcq_omcq_deps (id_mcq, id_mcq_dep) VALUES (?, ?)", m.Id, d.Id)
} else {
2021-11-22 14:35:07 +00:00
err = errors.New("dependancy type not implemented for this flag")
}
return
}
// GetDepends retrieve the flag's dependency list.
2021-11-22 14:35:07 +00:00
func (m *MCQ) GetDepends() ([]Flag, error) {
deps := []Flag{}
2020-01-20 16:29:34 +00:00
if rows, err := DBQuery("SELECT id_flag_dep FROM exercice_mcq_okey_deps WHERE id_mcq = ?", m.Id); err != nil {
return nil, err
} else {
defer rows.Close()
for rows.Next() {
var d int
if err := rows.Scan(&d); err != nil {
return nil, err
}
2021-11-22 14:35:07 +00:00
deps = append(deps, &FlagKey{Id: d, IdExercice: m.IdExercice})
}
if err := rows.Err(); err != nil {
return nil, err
}
}
2020-01-20 16:29:34 +00:00
if rows, err := DBQuery("SELECT id_mcq_dep FROM exercice_mcq_omcq_deps WHERE id_mcq = ?", m.Id); err != nil {
return nil, err
} else {
defer rows.Close()
for rows.Next() {
var d int
2020-01-20 16:29:34 +00:00
if err := rows.Scan(&d); err != nil {
return nil, err
}
2021-11-22 14:35:07 +00:00
deps = append(deps, &MCQ{Id: d, IdExercice: m.IdExercice})
2020-01-20 16:29:34 +00:00
}
if err := rows.Err(); err != nil {
return nil, err
}
}
return deps, nil
}
// GetJustifiedFlag searchs for a flag in the scope of the given exercice.
2021-11-22 14:35:07 +00:00
func (c *MCQ_entry) GetJustifiedFlag(e *Exercice) (*FlagKey, error) {
return e.GetFlagKeyByLabel(fmt.Sprintf("\\%%%d\\%%%%", c.Id))
}
2022-05-31 20:03:51 +00:00
// IsOptionnal to know if the flag can be omitted when validating the step.
func (m *MCQ) IsOptionnal() bool {
return false
}
2018-03-09 18:07:08 +00:00
// Check if the given vals are the expected ones to validate this flag.
2021-11-22 14:35:07 +00:00
func (m *MCQ) Check(v interface{}) int {
var vals map[int]bool
if va, ok := v.(map[int]bool); !ok {
return -1
} else {
vals = va
}
diff := 0
2017-12-16 00:16:30 +00:00
for _, n := range m.Entries {
2017-12-16 02:39:57 +00:00
if v, ok := vals[n.Id]; (ok || !n.Response) && v == n.Response {
continue
}
diff += 1
}
return diff
}
2017-12-16 00:16:30 +00:00
2018-03-09 18:07:08 +00:00
// FoundBy registers in the database that the given Team solved the MCQ.
func (m *MCQ) FoundBy(t *Team) (err error) {
_, err = DBExec("INSERT INTO mcq_found (id_mcq, id_team, time) VALUES (?, ?, ?)", m.Id, t.Id, time.Now())
return
2017-12-16 00:16:30 +00:00
}