2017-11-22 02:28:14 +00:00
package fic
import (
2019-01-02 20:51:09 +00:00
"errors"
2018-12-02 03:52:15 +00:00
"fmt"
2017-12-16 00:16:30 +00:00
"time"
2017-11-22 02:28:14 +00:00
)
2018-03-09 18:07:08 +00:00
// MCQ represents a flag's challenge, in the form of checkbox.
2017-11-22 02:28:14 +00:00
type MCQ struct {
2021-08-30 16:33:14 +00:00
Id int ` json:"id" `
2018-03-09 18:07:08 +00:00
// IdExercice is the identifier of the underlying challenge
2019-07-05 20:28:56 +00:00
IdExercice int64 ` json:"idExercice" `
2021-08-30 16:33:14 +00:00
// 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
2019-07-05 20:28:56 +00:00
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" `
2017-11-22 02:28:14 +00:00
}
2018-03-09 18:07:08 +00:00
// MCQ_entry represents a proposed response for a given MCQ.
2017-11-22 02:28:14 +00:00
type MCQ_entry struct {
2021-08-30 16:33:14 +00:00
Id int ` json:"id" `
2018-03-09 18:07:08 +00:00
// Label is the text displayed to players as proposed answer
2019-07-05 20:28:56 +00:00
Label string ` json:"label" `
2018-03-09 18:07:08 +00:00
// Response stores if expected checked state.
2019-07-05 20:28:56 +00:00
Response bool ` json:"response" `
2017-11-22 02:28:14 +00:00
}
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 ) {
2021-08-30 16:33:14 +00:00
if rows , err := DBQuery ( "SELECT id_mcq, id_exercice, ordre, title FROM exercice_mcq WHERE id_exercice = ?" , e . Id ) ; err != nil {
2017-11-22 02:28:14 +00:00
return nil , err
} else {
defer rows . Close ( )
2021-11-22 14:35:07 +00:00
var mcqs = [ ] * MCQ { }
2017-11-22 02:28:14 +00:00
for rows . Next ( ) {
2021-11-22 14:35:07 +00:00
m := & MCQ { }
2017-11-22 02:28:14 +00:00
m . IdExercice = e . Id
2021-08-30 16:33:14 +00:00
if err := rows . Scan ( & m . Id , & m . IdExercice , & m . Order , & m . Title ) ; err != nil {
2017-11-22 02:28:14 +00:00
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 )
2017-11-22 02:28:14 +00:00
}
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
}
2018-11-28 06:39:50 +00:00
// 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 { }
2021-08-30 16:33:14 +00:00
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
2018-11-28 06:39:50 +00:00
}
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
2018-11-28 06:39:50 +00:00
} else {
defer entries_rows . Close ( )
for entries_rows . Next ( ) {
2021-11-22 14:35:07 +00:00
e := & MCQ_entry { }
2018-11-28 06:39:50 +00:00
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
}
2019-07-05 20:28:56 +00:00
// GetId returns the MCQ identifier.
2021-11-22 14:35:07 +00:00
func ( m * MCQ ) GetId ( ) int {
2019-07-05 20:28:56 +00:00
return m . Id
}
2019-11-25 13:19:29 +00:00
// RecoverId returns the MCQ identifier as register in DB.
2021-11-22 14:35:07 +00:00
func ( m * MCQ ) RecoverId ( ) ( Flag , error ) {
2019-11-25 13:19:29 +00:00
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
2019-11-25 13:19:29 +00:00
} else {
return m , err
}
}
2019-07-05 20:28:56 +00:00
// 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 ) {
2021-08-30 16:33:14 +00:00
if res , err := DBExec ( "INSERT INTO exercice_mcq (id_exercice, ordre, title) VALUES (?, ?, ?)" , e . Id , m . Order , m . Title ) ; err != nil {
2019-07-05 20:28:56 +00:00
return m , err
2017-11-22 02:28:14 +00:00
} else if qid , err := res . LastInsertId ( ) ; err != nil {
2019-07-05 20:28:56 +00:00
return m , err
2017-11-22 02:28:14 +00:00
} else {
2021-08-30 16:33:14 +00:00
m . Id = int ( qid )
2019-07-05 20:28:56 +00:00
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
2017-11-22 02:28:14 +00:00
}
}
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 ) {
2021-08-30 16:33:14 +00:00
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 {
2017-11-22 02:28:14 +00:00
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 {
2019-01-16 05:02:06 +00:00
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
2019-01-16 05:02:06 +00:00
} 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
2019-01-16 05:02:06 +00:00
} else if res , err := DBExec ( "DELETE FROM exercice_mcq WHERE id_mcq = ?" , m . Id ) ; err != nil {
2017-11-22 02:28:14 +00:00
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 ) {
2019-07-05 20:28:56 +00:00
if res , err := DBExec ( "INSERT INTO mcq_entries (id_mcq, label, response) VALUES (?, ?, ?)" , m . Id , e . Label , e . Response ) ; err != nil {
return e , err
2017-11-22 02:28:14 +00:00
} else if nid , err := res . LastInsertId ( ) ; err != nil {
2019-07-05 20:28:56 +00:00
return e , err
2017-11-22 02:28:14 +00:00
} else {
2021-08-30 16:33:14 +00:00
e . Id = int ( nid )
2019-07-05 20:28:56 +00:00
return e , nil
2017-11-22 02:28:14 +00:00
}
}
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 ) {
2017-11-22 02:28:14 +00:00
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 ) {
2017-11-22 02:28:14 +00:00
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
2019-01-16 05:02:06 +00:00
} 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 {
2021-08-30 16:33:14 +00:00
return m . Order
}
2019-01-02 20:51:09 +00:00
// 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 {
2019-01-16 05:02:06 +00:00
_ , 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 )
2019-01-16 05:02:06 +00:00
} else {
2021-11-22 14:35:07 +00:00
err = errors . New ( "dependancy type not implemented for this flag" )
2019-01-16 05:02:06 +00:00
}
return
2019-01-02 20:51:09 +00:00
}
// 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
2019-01-16 05:02:06 +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 ( ) {
2021-08-30 16:33:14 +00:00
var d int
2019-01-16 05:02:06 +00:00
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 } )
2019-01-16 05:02:06 +00:00
}
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 ( ) {
2021-08-30 16:33:14 +00:00
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
2019-01-02 20:51:09 +00:00
}
2018-11-28 06:39:50 +00:00
// 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 ) {
2019-01-02 20:51:09 +00:00
return e . GetFlagKeyByLabel ( fmt . Sprintf ( "\\%%%d\\%%%%" , c . Id ) )
2018-11-28 06:39:50 +00:00
}
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 {
2021-08-30 16:33:14 +00:00
var vals map [ int ] bool
if va , ok := v . ( map [ int ] bool ) ; ! ok {
2019-01-02 20:51:09 +00:00
return - 1
} else {
vals = va
}
2017-11-22 02:28:14 +00:00
diff := 0
2017-12-16 00:16:30 +00:00
2017-11-22 02:28:14 +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 {
2017-11-22 02:28:14 +00:00
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.
2022-06-08 14:38:00 +00:00
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
}