2016-12-04 18:15:39 +00:00
package fic
import (
2019-10-26 09:33:30 +00:00
"fmt"
2017-01-05 01:21:32 +00:00
"path"
"strings"
2016-12-04 18:15:39 +00:00
)
2019-01-17 11:03:18 +00:00
// HintCoefficient is the current coefficient applied on its cost lost per showing
var HintCoefficient = 1.0
2018-03-09 18:07:08 +00:00
// EHint represents a challenge hint.
2016-12-04 18:15:39 +00:00
type EHint struct {
2020-04-15 05:39:38 +00:00
Id int64 ` json:"id" `
2018-03-09 18:07:08 +00:00
// IdExercice is the identifier of the underlying challenge
2020-04-15 05:39:38 +00:00
IdExercice int64 ` json:"idExercice" `
2018-03-09 18:07:08 +00:00
// Title is the hint name displayed to players
2020-04-15 05:39:38 +00:00
Title string ` json:"title" `
2018-03-09 18:07:08 +00:00
// Content is the actual content of small text hints (mutually exclusive with File field)
// When File is filled, Content contains the hexadecimal file's hash.
2020-04-15 05:39:38 +00:00
Content string ` json:"content" `
2018-03-09 18:07:08 +00:00
// File is path, relative to FilesDir where the file hint is stored (mutually exclusive with Content field)
2020-04-15 05:39:38 +00:00
File string ` json:"file" `
2018-03-09 18:07:08 +00:00
// Cost is the amount of points the player will loose if it unlocks the hint
2020-04-15 05:39:38 +00:00
Cost int64 ` json:"cost" `
2016-12-04 18:15:39 +00:00
}
2018-03-09 18:07:08 +00:00
// treatHintContent reads Content to detect if this is a hint file in order to convert to such hint.
2017-01-14 14:03:25 +00:00
func treatHintContent ( h * EHint ) {
if strings . HasPrefix ( h . Content , "$FILES" ) {
2018-01-07 22:40:11 +00:00
fpath := strings . TrimPrefix ( h . Content , "$FILES" )
h . Content = fpath [ : 128 ]
fpath = fpath [ 128 : ]
h . File = path . Join ( FilesDir , fpath )
2017-01-05 01:21:32 +00:00
}
}
2018-03-09 18:07:08 +00:00
// GetHint retrieves the hint with the given id.
2021-11-22 14:35:07 +00:00
func GetHint ( id int64 ) ( * EHint , error ) {
h := & EHint { }
2016-12-09 10:49:29 +00:00
if err := DBQueryRow ( "SELECT id_hint, id_exercice, title, content, cost FROM exercice_hints WHERE id_hint = ?" , id ) . Scan ( & h . Id , & h . IdExercice , & h . Title , & h . Content , & h . Cost ) ; err != nil {
2021-11-22 14:35:07 +00:00
return nil , err
2016-12-09 10:49:29 +00:00
}
2021-11-22 14:35:07 +00:00
treatHintContent ( h )
2016-12-09 10:49:29 +00:00
return h , nil
}
2022-05-16 09:38:46 +00:00
// GetHint retrieves the hint with the given id.
func ( e * Exercice ) GetHint ( id int64 ) ( * EHint , error ) {
h := & EHint { }
if err := DBQueryRow ( "SELECT id_hint, id_exercice, title, content, cost FROM exercice_hints WHERE id_hint = ? AND id_exercice = ?" , id , e . Id ) . Scan ( & h . Id , & h . IdExercice , & h . Title , & h . Content , & h . Cost ) ; err != nil {
return nil , err
}
treatHintContent ( h )
return h , nil
}
2019-11-25 13:19:29 +00:00
// GetHintByTitle retrieves the hint with the given id.
2021-11-22 14:35:07 +00:00
func ( e * Exercice ) GetHintByTitle ( id int64 ) ( * EHint , error ) {
h := & EHint { }
2019-11-25 13:19:29 +00:00
if err := DBQueryRow ( "SELECT id_hint, id_exercice, title, content, cost FROM exercice_hints WHERE title = ? AND id_exercice = ?" , id , e . Id ) . Scan ( & h . Id , & h . IdExercice , & h . Title , & h . Content , & h . Cost ) ; err != nil {
2021-11-22 14:35:07 +00:00
return nil , err
2019-11-25 13:19:29 +00:00
}
2021-11-22 14:35:07 +00:00
treatHintContent ( h )
2019-11-25 13:19:29 +00:00
return h , nil
}
2018-03-09 18:07:08 +00:00
// GetHints returns a list of hints comming with the challenge.
2021-11-22 14:35:07 +00:00
func ( e * Exercice ) GetHints ( ) ( [ ] * EHint , error ) {
2016-12-04 18:15:39 +00:00
if rows , err := DBQuery ( "SELECT id_hint, title, content, cost FROM exercice_hints WHERE id_exercice = ?" , e . Id ) ; err != nil {
return nil , err
} else {
defer rows . Close ( )
2021-11-22 14:35:07 +00:00
var hints [ ] * EHint
2016-12-04 18:15:39 +00:00
for rows . Next ( ) {
2021-11-22 14:35:07 +00:00
h := & EHint { }
2016-12-04 18:15:39 +00:00
h . IdExercice = e . Id
if err := rows . Scan ( & h . Id , & h . Title , & h . Content , & h . Cost ) ; err != nil {
return nil , err
}
2021-11-22 14:35:07 +00:00
treatHintContent ( h )
2016-12-04 18:15:39 +00:00
hints = append ( hints , h )
}
if err := rows . Err ( ) ; err != nil {
return nil , err
}
return hints , nil
}
}
2018-03-09 18:07:08 +00:00
// AddHint creates and fills a new struct EHint and registers it into the database.
2021-11-22 14:35:07 +00:00
func ( e * Exercice ) AddHint ( title string , content string , cost int64 ) ( * EHint , error ) {
2016-12-04 18:15:39 +00:00
if res , err := DBExec ( "INSERT INTO exercice_hints (id_exercice, title, content, cost) VALUES (?, ?, ?, ?)" , e . Id , title , content , cost ) ; err != nil {
2021-11-22 14:35:07 +00:00
return nil , err
2016-12-04 18:15:39 +00:00
} else if hid , err := res . LastInsertId ( ) ; err != nil {
2021-11-22 14:35:07 +00:00
return nil , err
2016-12-04 18:15:39 +00:00
} else {
2021-11-22 14:35:07 +00:00
return & EHint { hid , e . Id , title , content , "" , cost } , nil
2016-12-04 18:15:39 +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 ( h * EHint ) Update ( ) ( int64 , error ) {
2016-12-04 18:15:39 +00:00
if res , err := DBExec ( "UPDATE exercice_hints SET id_exercice = ?, title = ?, content = ?, cost = ? WHERE id_hint = ?" , h . IdExercice , h . Title , h . Content , h . Cost , h . 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 hint from the database.
2021-11-22 14:35:07 +00:00
func ( h * EHint ) Delete ( ) ( int64 , error ) {
2016-12-04 18:15:39 +00:00
if res , err := DBExec ( "DELETE FROM exercice_hints WHERE id_hint = ?" , h . Id ) ; err != nil {
return 0 , err
} else if nb , err := res . RowsAffected ( ) ; err != nil {
return 0 , err
} else {
return nb , err
}
}
2017-01-24 01:18:05 +00:00
2018-03-09 18:07:08 +00:00
// WipeHints deletes (only in the database, not on disk) hints coming with the challenge.
2021-11-22 14:35:07 +00:00
func ( e * Exercice ) WipeHints ( ) ( int64 , error ) {
2020-01-23 11:39:53 +00:00
if _ , err := DBExec ( "DELETE FROM exercice_hints_okey_deps WHERE id_hint IN (SELECT id_hint FROM exercice_hints WHERE id_exercice = ?)" , e . Id ) ; err != nil {
return 0 , err
} else if _ , err := DBExec ( "DELETE FROM exercice_hints_omcq_deps WHERE id_hint IN (SELECT id_hint FROM exercice_hints WHERE id_exercice = ?)" , e . Id ) ; err != nil {
2019-10-26 09:33:30 +00:00
return 0 , err
} else if res , err := DBExec ( "DELETE FROM exercice_hints WHERE id_exercice = ?" , e . Id ) ; err != nil {
2017-12-08 23:52:43 +00:00
return 0 , err
} else if nb , err := res . RowsAffected ( ) ; err != nil {
return 0 , err
} else {
return nb , err
}
}
2019-10-26 09:33:30 +00:00
// AddDepend insert a new dependency to a given flag.
2021-11-22 14:35:07 +00:00
func ( h * EHint ) AddDepend ( f Flag ) ( err error ) {
if d , ok := f . ( * FlagKey ) ; ok {
2020-01-23 11:39:53 +00:00
_ , err = DBExec ( "INSERT INTO exercice_hints_okey_deps (id_hint, id_flag_dep) VALUES (?, ?)" , h . Id , d . Id )
2021-11-22 14:35:07 +00:00
} else if d , ok := f . ( * MCQ ) ; ok {
2020-01-23 11:39:53 +00:00
_ , err = DBExec ( "INSERT INTO exercice_hints_omcq_deps (id_hint, id_mcq_dep) VALUES (?, ?)" , h . Id , d . Id )
2019-10-26 09:33:30 +00:00
} else {
2021-11-22 14:35:07 +00:00
err = fmt . Errorf ( "dependancy type for key (%T) not implemented for this flag" , f )
2019-10-26 09:33:30 +00:00
}
return
}
// GetDepends retrieve the flag's dependency list.
2021-11-22 14:35:07 +00:00
func ( h * EHint ) GetDepends ( ) ( [ ] Flag , error ) {
var deps [ ] Flag
2019-10-26 09:33:30 +00:00
2020-01-23 11:39:53 +00:00
if rows , err := DBQuery ( "SELECT id_flag_dep FROM exercice_hints_okey_deps WHERE id_hint = ?" , h . Id ) ; err != nil {
2019-10-26 09:33:30 +00:00
return nil , err
} else {
defer rows . Close ( )
for rows . Next ( ) {
2021-08-30 16:33:14 +00:00
var d int
2019-10-26 09:33:30 +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 : h . IdExercice } )
2019-10-26 09:33:30 +00:00
}
if err := rows . Err ( ) ; err != nil {
return nil , err
}
}
2020-01-23 11:39:53 +00:00
if rows , err := DBQuery ( "SELECT id_mcq_dep FROM exercice_hints_omcq_deps WHERE id_hint = ?" , h . 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-23 11:39:53 +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 : h . IdExercice } )
2020-01-23 11:39:53 +00:00
}
if err := rows . Err ( ) ; err != nil {
return nil , err
}
}
2019-10-26 09:33:30 +00:00
return deps , nil
}
2018-03-09 18:07:08 +00:00
// GetExercice returns the parent Exercice where this hint can be found.
2021-11-22 14:35:07 +00:00
func ( h * EHint ) GetExercice ( ) ( * Exercice , error ) {
2017-01-24 01:18:05 +00:00
var eid int64
if err := DBQueryRow ( "SELECT id_exercice FROM exercice_hints WHERE id_hint = ?" , h . Id ) . Scan ( & eid ) ; err != nil {
2021-11-22 14:35:07 +00:00
return nil , err
2017-01-24 01:18:05 +00:00
}
return GetExercice ( eid )
}