2016-01-23 11:20:30 +00:00
|
|
|
package fic
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/hex"
|
2022-06-07 14:05:41 +00:00
|
|
|
"encoding/json"
|
2016-01-23 11:20:30 +00:00
|
|
|
"fmt"
|
2017-01-16 12:09:31 +00:00
|
|
|
"log"
|
2022-06-07 14:05:41 +00:00
|
|
|
"os"
|
2016-11-19 14:54:32 +00:00
|
|
|
"path"
|
2021-08-30 18:03:17 +00:00
|
|
|
"sort"
|
2019-11-25 16:45:41 +00:00
|
|
|
"strconv"
|
2018-12-02 15:24:33 +00:00
|
|
|
"strings"
|
2019-07-10 14:58:20 +00:00
|
|
|
"time"
|
2016-01-23 11:20:30 +00:00
|
|
|
)
|
|
|
|
|
2019-01-19 23:14:20 +00:00
|
|
|
// DisplayAllFlags doesn't respect the predefined constraint existing between flags.
|
|
|
|
var DisplayAllFlags bool
|
|
|
|
|
2022-01-20 15:06:27 +00:00
|
|
|
// DisplayMCQBadCount activates the report of MCQ bad responses counter.
|
|
|
|
var DisplayMCQBadCount bool
|
|
|
|
|
2023-11-05 09:59:10 +00:00
|
|
|
// HideCaseSensitivity never tells the user if the flag is case sensitive or not.
|
|
|
|
var HideCaseSensitivity bool
|
|
|
|
|
2024-03-16 10:28:59 +00:00
|
|
|
// UnlockedStandaloneExercices unlock this number of standalone exercice.
|
|
|
|
var UnlockedStandaloneExercices int
|
|
|
|
|
2024-03-17 09:17:39 +00:00
|
|
|
// UnlockedStandaloneExercicesByThemeStepValidation unlock this number of standalone exercice for each theme step validated.
|
|
|
|
var UnlockedStandaloneExercicesByThemeStepValidation float64
|
|
|
|
|
|
|
|
// UnlockedStandaloneExercicesByStandaloneExerciceValidation unlock this number of standalone exercice for each standalone exercice validated.
|
|
|
|
var UnlockedStandaloneExercicesByStandaloneExerciceValidation float64
|
2024-03-16 10:28:59 +00:00
|
|
|
|
2016-01-23 11:20:30 +00:00
|
|
|
type myTeamFile struct {
|
2023-04-03 21:46:01 +00:00
|
|
|
Path string `json:"path"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Checksum string `json:"checksum"`
|
|
|
|
Compressed bool `json:"compressed,omitempty"`
|
|
|
|
Size int64 `json:"size"`
|
2016-01-23 11:20:30 +00:00
|
|
|
}
|
2016-12-04 18:15:39 +00:00
|
|
|
type myTeamHint struct {
|
2019-07-10 14:58:20 +00:00
|
|
|
HintId int64 `json:"id"`
|
|
|
|
Title string `json:"title"`
|
|
|
|
Content string `json:"content,omitempty"`
|
|
|
|
File string `json:"file,omitempty"`
|
|
|
|
Cost int64 `json:"cost"`
|
2016-12-04 18:15:39 +00:00
|
|
|
}
|
2018-11-28 01:27:51 +00:00
|
|
|
type myTeamFlag struct {
|
2022-01-21 12:06:37 +00:00
|
|
|
Id int `json:"id,omitempty"`
|
2021-08-30 16:33:14 +00:00
|
|
|
Label string `json:"label"`
|
|
|
|
Type string `json:"type,omitempty"`
|
|
|
|
Placeholder string `json:"placeholder,omitempty"`
|
|
|
|
Help string `json:"help,omitempty"`
|
2021-11-12 22:52:22 +00:00
|
|
|
Unit string `json:"unit,omitempty"`
|
2021-08-30 16:33:14 +00:00
|
|
|
Separator string `json:"separator,omitempty"`
|
|
|
|
NbLines uint64 `json:"nb_lines,omitempty"`
|
|
|
|
IgnoreOrder bool `json:"ignore_order,omitempty"`
|
|
|
|
IgnoreCase bool `json:"ignore_case,omitempty"`
|
|
|
|
Multiline bool `json:"multiline,omitempty"`
|
2024-03-27 10:24:54 +00:00
|
|
|
CaptureRe *string `json:"capture_regexp,omitempty"`
|
2021-08-30 16:33:14 +00:00
|
|
|
Solved *time.Time `json:"found,omitempty"`
|
|
|
|
PSolved *time.Time `json:"part_solved,omitempty"`
|
|
|
|
Soluce string `json:"soluce,omitempty"`
|
|
|
|
Justify bool `json:"justify,omitempty"`
|
2022-05-31 20:03:51 +00:00
|
|
|
BonusGain int64 `json:"bonus_gain,omitempty"`
|
2021-08-30 16:33:14 +00:00
|
|
|
Choices map[string]interface{} `json:"choices,omitempty"`
|
|
|
|
ChoicesCost int64 `json:"choices_cost,omitempty"`
|
2022-01-21 12:06:37 +00:00
|
|
|
Variant string `json:"variant,omitempty"`
|
2021-11-12 20:36:27 +00:00
|
|
|
Min *float64 `json:"min,omitempty"`
|
|
|
|
Max *float64 `json:"max,omitempty"`
|
|
|
|
Step *float64 `json:"step,omitempty"`
|
2022-07-08 21:11:11 +00:00
|
|
|
order int8
|
2018-11-28 01:27:51 +00:00
|
|
|
}
|
2019-01-17 21:30:39 +00:00
|
|
|
type myTeamMCQJustifiedChoice struct {
|
|
|
|
Label string `json:"label"`
|
|
|
|
Value bool `json:"value,omitempty"`
|
|
|
|
Justification myTeamFlag `json:"justification,omitempty"`
|
|
|
|
}
|
2016-01-23 11:20:30 +00:00
|
|
|
type myTeamExercice struct {
|
2024-03-12 09:12:40 +00:00
|
|
|
ThemeId int64 `json:"theme_id,omitempty"`
|
2023-04-06 13:38:53 +00:00
|
|
|
Disabled bool `json:"disabled,omitempty"`
|
2022-11-05 14:26:57 +00:00
|
|
|
WIP bool `json:"wip,omitempty"`
|
2021-08-30 18:03:17 +00:00
|
|
|
Statement string `json:"statement"`
|
|
|
|
Overview string `json:"overview,omitempty"`
|
|
|
|
Finished string `json:"finished,omitempty"`
|
|
|
|
Hints []myTeamHint `json:"hints,omitempty"`
|
|
|
|
Gain int `json:"gain"`
|
|
|
|
Files []myTeamFile `json:"files,omitempty"`
|
|
|
|
Flags []myTeamFlag `json:"flags,omitempty"`
|
2021-08-31 23:38:39 +00:00
|
|
|
NbFlags int `json:"nb_flags,omitempty"`
|
2021-08-30 18:03:17 +00:00
|
|
|
SolveDist int64 `json:"solve_dist,omitempty"`
|
|
|
|
SolvedTime *time.Time `json:"solved_time,omitempty"`
|
|
|
|
SolvedRank int64 `json:"solved_rank,omitempty"`
|
|
|
|
Tries int64 `json:"tries,omitempty"`
|
|
|
|
TotalTries int64 `json:"total_tries,omitempty"`
|
|
|
|
VideoURI string `json:"video_uri,omitempty"`
|
2022-05-24 15:53:44 +00:00
|
|
|
Resolution string `json:"resolution,omitempty"`
|
2021-08-30 18:03:17 +00:00
|
|
|
Issue string `json:"issue,omitempty"`
|
|
|
|
IssueKind string `json:"issuekind,omitempty"`
|
2016-01-23 11:20:30 +00:00
|
|
|
}
|
2022-06-07 14:05:41 +00:00
|
|
|
type MyTeam struct {
|
2016-01-23 11:20:30 +00:00
|
|
|
Id int64 `json:"team_id"`
|
2016-01-24 13:23:04 +00:00
|
|
|
Name string `json:"name"`
|
2016-01-23 18:53:17 +00:00
|
|
|
Points int64 `json:"score"`
|
2024-03-19 12:59:28 +00:00
|
|
|
Points100 int64 `json:"score100"`
|
2021-11-22 14:35:07 +00:00
|
|
|
Members []*Member `json:"members,omitempty"`
|
2016-01-23 11:20:30 +00:00
|
|
|
Exercices map[string]myTeamExercice `json:"exercices"`
|
|
|
|
}
|
|
|
|
|
2021-08-30 18:03:17 +00:00
|
|
|
type ByOrder []myTeamFlag
|
|
|
|
|
|
|
|
func (a ByOrder) Len() int { return len(a) }
|
|
|
|
func (a ByOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
|
|
func (a ByOrder) Less(i, j int) bool { return a[i].order < a[j].order }
|
|
|
|
|
2016-01-23 11:20:30 +00:00
|
|
|
func MyJSONTeam(t *Team, started bool) (interface{}, error) {
|
2022-06-07 14:05:41 +00:00
|
|
|
ret := MyTeam{}
|
2016-12-04 18:15:39 +00:00
|
|
|
|
|
|
|
// Fill information about the team
|
2016-01-23 11:20:30 +00:00
|
|
|
if t == nil {
|
|
|
|
ret.Id = 0
|
|
|
|
} else {
|
2016-01-24 13:23:04 +00:00
|
|
|
ret.Name = t.Name
|
2016-01-23 11:20:30 +00:00
|
|
|
ret.Id = t.Id
|
2017-01-12 10:52:51 +00:00
|
|
|
points, _ := t.GetPoints()
|
2021-09-06 09:58:03 +00:00
|
|
|
ret.Points = int64(float64(points) * GlobalScoreCoefficient)
|
2024-03-19 12:59:28 +00:00
|
|
|
ret.Points100 = int64(float64(points) * GlobalScoreCoefficient * 100)
|
2016-01-24 10:42:26 +00:00
|
|
|
if members, err := t.GetMembers(); err == nil {
|
|
|
|
ret.Members = members
|
|
|
|
}
|
2016-01-23 11:20:30 +00:00
|
|
|
}
|
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
// Retrieve themes
|
|
|
|
themes, err := GetThemes()
|
|
|
|
if err != nil {
|
|
|
|
return ret, err
|
|
|
|
}
|
|
|
|
|
|
|
|
mapthemes := map[int64]*Theme{}
|
|
|
|
for _, theme := range themes {
|
|
|
|
mapthemes[theme.Id] = theme
|
|
|
|
}
|
|
|
|
|
2016-12-04 18:15:39 +00:00
|
|
|
// Fill exercices, only if the challenge is started
|
|
|
|
ret.Exercices = map[string]myTeamExercice{}
|
2023-04-01 15:11:40 +00:00
|
|
|
if exos, err := GetDiscountedExercices(); err != nil {
|
2016-01-23 11:20:30 +00:00
|
|
|
return ret, err
|
|
|
|
} else if started {
|
|
|
|
for _, e := range exos {
|
2024-03-12 09:12:40 +00:00
|
|
|
if t == nil || ((!e.Disabled || (e.IdTheme != nil && !mapthemes[*e.IdTheme].Locked)) && t.HasAccess(e)) {
|
2016-01-23 11:20:30 +00:00
|
|
|
exercice := myTeamExercice{}
|
2023-04-06 13:38:53 +00:00
|
|
|
exercice.Disabled = e.Disabled
|
2022-11-05 14:26:57 +00:00
|
|
|
exercice.WIP = e.WIP
|
2024-03-15 16:46:50 +00:00
|
|
|
if e.IdTheme != nil {
|
|
|
|
exercice.ThemeId = *e.IdTheme
|
|
|
|
}
|
2018-11-21 01:20:37 +00:00
|
|
|
|
2018-12-02 15:24:33 +00:00
|
|
|
exercice.Statement = strings.Replace(e.Statement, "$FILES$", FilesDir, -1)
|
2018-11-21 01:20:37 +00:00
|
|
|
|
|
|
|
if len(e.Issue) > 0 {
|
|
|
|
exercice.Issue = e.Issue
|
|
|
|
exercice.IssueKind = e.IssueKind
|
|
|
|
}
|
|
|
|
|
2016-01-23 11:20:30 +00:00
|
|
|
if t == nil {
|
2018-12-02 15:24:33 +00:00
|
|
|
exercice.Overview = strings.Replace(e.Overview, "$FILES$", FilesDir, -1)
|
2018-12-02 16:53:26 +00:00
|
|
|
exercice.Finished = strings.Replace(e.Finished, "$FILES$", FilesDir, -1)
|
2022-06-12 10:15:39 +00:00
|
|
|
exercice.VideoURI = strings.Replace(e.VideoURI, "$FILES$", FilesDir, -1)
|
2022-05-24 15:53:44 +00:00
|
|
|
exercice.Resolution = strings.Replace(e.Resolution, "$FILES$", FilesDir, -1)
|
2019-02-03 20:00:41 +00:00
|
|
|
exercice.TotalTries = e.TriedCount()
|
2021-09-06 09:58:03 +00:00
|
|
|
exercice.Gain = int(float64(e.Gain) * e.Coefficient * GlobalScoreCoefficient)
|
2016-01-23 11:20:30 +00:00
|
|
|
} else {
|
2021-11-22 14:35:07 +00:00
|
|
|
stime := t.HasSolved(e)
|
|
|
|
exercice.SolvedTime = stime
|
2017-01-16 12:09:31 +00:00
|
|
|
|
2021-11-22 14:35:07 +00:00
|
|
|
if stime != nil {
|
2018-12-04 21:25:38 +00:00
|
|
|
exercice.SolvedRank, _ = t.GetSolvedRank(e)
|
2018-12-02 16:53:26 +00:00
|
|
|
exercice.Finished = e.Finished
|
2017-01-16 12:09:31 +00:00
|
|
|
exercice.Tries, _ = t.CountTries(e)
|
|
|
|
} else {
|
2023-04-02 15:24:25 +00:00
|
|
|
var ttime *time.Time
|
|
|
|
exercice.Tries, ttime = t.CountTries(e)
|
|
|
|
exercice.SolvedTime = ttime
|
2022-01-21 12:06:37 +00:00
|
|
|
if DisplayMCQBadCount && exercice.Tries > 0 {
|
|
|
|
exercice.SolveDist = t.LastTryDist(e)
|
2017-12-17 01:48:02 +00:00
|
|
|
}
|
2017-01-16 12:09:31 +00:00
|
|
|
}
|
|
|
|
|
2018-12-04 21:25:38 +00:00
|
|
|
if exercice.SolvedTime != nil && exercice.SolvedTime.Equal(time.Unix(0, 0)) {
|
|
|
|
exercice.SolvedTime = nil
|
|
|
|
}
|
|
|
|
|
2021-11-22 14:35:07 +00:00
|
|
|
if gain, err := e.EstimateGain(t, stime != nil); err == nil {
|
2021-09-06 09:58:03 +00:00
|
|
|
exercice.Gain = int(gain * GlobalScoreCoefficient)
|
2017-01-16 12:09:31 +00:00
|
|
|
} else {
|
2022-02-03 16:36:59 +00:00
|
|
|
log.Printf("ERROR during gain estimation (tid=%d ; eid=%d): %s", t.Id, e.Id, err.Error())
|
2022-02-04 16:32:55 +00:00
|
|
|
exercice.Gain = int(float64(e.Gain) * GlobalScoreCoefficient)
|
2017-01-16 12:09:31 +00:00
|
|
|
}
|
2016-01-23 11:20:30 +00:00
|
|
|
}
|
|
|
|
|
2016-12-04 18:15:39 +00:00
|
|
|
// Expose exercice files
|
2016-01-23 11:20:30 +00:00
|
|
|
|
2016-12-04 18:15:39 +00:00
|
|
|
exercice.Files = []myTeamFile{}
|
|
|
|
|
|
|
|
if files, err := e.GetFiles(); err != nil {
|
2016-01-23 11:20:30 +00:00
|
|
|
return nil, err
|
|
|
|
} else {
|
2016-12-04 18:15:39 +00:00
|
|
|
for _, f := range files {
|
2018-09-07 18:53:08 +00:00
|
|
|
if t == nil || t.CanDownload(f) {
|
2022-10-31 17:29:41 +00:00
|
|
|
cksum := f.Checksum
|
2023-04-03 21:46:01 +00:00
|
|
|
compressed := false
|
2022-10-31 17:29:41 +00:00
|
|
|
if len(f.ChecksumShown) > 0 {
|
|
|
|
cksum = f.ChecksumShown
|
2023-04-03 21:46:01 +00:00
|
|
|
compressed = true
|
2022-10-31 17:29:41 +00:00
|
|
|
}
|
2023-04-03 21:46:01 +00:00
|
|
|
exercice.Files = append(exercice.Files, myTeamFile{path.Join(FilesDir, f.Path), f.Name, hex.EncodeToString(cksum), compressed, f.Size})
|
2018-09-07 18:53:08 +00:00
|
|
|
}
|
2016-12-04 18:15:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Expose exercice hints
|
|
|
|
|
|
|
|
exercice.Hints = []myTeamHint{}
|
|
|
|
|
|
|
|
if hints, err := e.GetHints(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
for _, h := range hints {
|
2019-01-17 11:03:18 +00:00
|
|
|
if t == nil || HintCoefficient < 0 || t.HasHint(h) {
|
2021-09-06 09:58:03 +00:00
|
|
|
exercice.Hints = append(exercice.Hints, myTeamHint{h.Id, h.Title, h.Content, h.File, int64(float64(h.Cost) * GlobalScoreCoefficient)})
|
2019-10-26 09:33:30 +00:00
|
|
|
} else if t.CanSeeHint(h) {
|
2021-09-06 09:58:03 +00:00
|
|
|
exercice.Hints = append(exercice.Hints, myTeamHint{h.Id, h.Title, "", "", int64(float64(h.Cost) * GlobalScoreCoefficient)})
|
2016-01-23 11:20:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-21 03:40:32 +00:00
|
|
|
// Expose exercice flags
|
2017-12-16 01:12:44 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if !e.Disabled {
|
|
|
|
justifiedMCQ := map[int]myTeamFlag{}
|
2017-12-16 01:12:44 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if labels, err := e.GetFlagLabels(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
for _, l := range labels {
|
|
|
|
if !DisplayAllFlags && t != nil && !t.CanSeeFlag(l) {
|
|
|
|
// Dependancy missing, skip the flag for now
|
|
|
|
continue
|
|
|
|
}
|
2022-01-21 12:06:37 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
exercice.Flags = append(exercice.Flags, myTeamFlag{
|
|
|
|
order: l.Order,
|
|
|
|
Label: l.Label,
|
|
|
|
Variant: l.Variant,
|
|
|
|
})
|
|
|
|
}
|
2022-01-21 12:06:37 +00:00
|
|
|
}
|
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if flags, err := e.GetFlagKeys(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
for _, k := range flags {
|
|
|
|
if !strings.HasPrefix(k.Type, "label") {
|
|
|
|
exercice.NbFlags += 1
|
|
|
|
}
|
2021-08-31 23:38:39 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if !DisplayAllFlags && t != nil && !t.CanSeeFlag(k) {
|
|
|
|
// Dependancy missing, skip the flag for now
|
|
|
|
continue
|
|
|
|
}
|
2021-08-31 23:38:39 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
flag := myTeamFlag{
|
|
|
|
Id: k.Id,
|
|
|
|
Type: k.Type,
|
|
|
|
order: k.Order,
|
|
|
|
Help: k.Help,
|
|
|
|
Unit: k.Unit,
|
|
|
|
}
|
2021-08-30 16:33:14 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if strings.HasPrefix(flag.Type, "number") {
|
|
|
|
flag.Min, flag.Max, flag.Step, err = AnalyzeNumberFlag(flag.Type)
|
|
|
|
flag.Type = "number"
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-11-12 20:36:27 +00:00
|
|
|
}
|
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
// Retrieve solved state or solution for public iface
|
|
|
|
if t == nil {
|
|
|
|
flag.IgnoreCase = k.IgnoreCase
|
2023-05-16 07:59:59 +00:00
|
|
|
flag.CaptureRe = k.CaptureRegexp
|
2023-04-06 13:41:14 +00:00
|
|
|
flag.Soluce = hex.EncodeToString(k.Checksum)
|
2023-11-05 09:59:10 +00:00
|
|
|
} else {
|
|
|
|
if PartialValidation {
|
|
|
|
flag.Solved = t.HasPartiallySolved(k)
|
|
|
|
}
|
|
|
|
if !HideCaseSensitivity {
|
|
|
|
flag.IgnoreCase = k.IgnoreCase
|
|
|
|
}
|
2023-04-06 13:41:14 +00:00
|
|
|
}
|
2018-11-28 01:27:51 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
flag.Multiline = k.Multiline
|
|
|
|
flag.BonusGain = int64(float64(k.BonusGain) * GlobalScoreCoefficient)
|
2020-01-16 14:33:28 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
var fl FlagMCQLabel
|
|
|
|
if fl, err = k.GetMCQJustification(); err == nil {
|
|
|
|
k.Label = fl.Label
|
|
|
|
}
|
2019-01-17 21:30:39 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
// Treat array flags
|
|
|
|
flag.Label, flag.Separator, flag.IgnoreOrder, flag.NbLines = k.AnalyzeFlagLabel()
|
|
|
|
|
|
|
|
// Fill more information if the flag is displaied
|
|
|
|
if flag.Solved == nil {
|
|
|
|
flag.Placeholder = k.Placeholder
|
|
|
|
if choices, err := k.GetChoices(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if t == nil || WChoiceCoefficient < 0 || k.ChoicesCost == 0 || t.SeeChoices(k) {
|
|
|
|
flag.Choices = map[string]interface{}{}
|
|
|
|
for _, c := range choices {
|
|
|
|
flag.Choices[c.Value] = c.Label
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
flag.ChoicesCost = int64(float64(k.ChoicesCost) * GlobalScoreCoefficient)
|
2018-11-28 03:37:08 +00:00
|
|
|
}
|
|
|
|
}
|
2018-11-28 01:27:51 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
// Append to corresponding flags' map
|
|
|
|
if fl.IdChoice != 0 {
|
|
|
|
justifiedMCQ[fl.IdChoice] = flag
|
|
|
|
} else {
|
|
|
|
exercice.Flags = append(exercice.Flags, flag)
|
|
|
|
}
|
2019-01-17 21:30:39 +00:00
|
|
|
}
|
2017-12-16 01:12:44 +00:00
|
|
|
}
|
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if mcqs, err := e.GetMCQ(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
for _, mcq := range mcqs {
|
|
|
|
exercice.NbFlags += 1
|
2019-01-16 05:02:06 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if !DisplayAllFlags && t != nil && !t.CanSeeFlag(mcq) {
|
|
|
|
// Dependancy missing, skip the flag for now
|
|
|
|
continue
|
|
|
|
}
|
2018-11-28 03:15:14 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
m := myTeamFlag{
|
|
|
|
Id: mcq.Id,
|
|
|
|
Type: "mcq",
|
|
|
|
order: mcq.Order,
|
|
|
|
Label: mcq.Title,
|
|
|
|
Choices: map[string]interface{}{},
|
|
|
|
}
|
2018-11-28 03:15:14 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
soluce := ""
|
|
|
|
fullySolved := true
|
|
|
|
if t != nil {
|
|
|
|
m.PSolved = t.HasPartiallySolved(mcq)
|
2018-11-28 03:15:14 +00:00
|
|
|
}
|
2018-12-02 03:52:15 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
for _, e := range mcq.Entries {
|
|
|
|
if e.Response {
|
|
|
|
soluce += "t"
|
|
|
|
} else {
|
|
|
|
soluce += "f"
|
|
|
|
}
|
2018-11-28 05:39:38 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if v, ok := justifiedMCQ[e.Id]; ok {
|
|
|
|
m.Justify = true
|
2018-11-28 01:27:51 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if m.PSolved != nil || v.Solved != nil {
|
|
|
|
jc := myTeamMCQJustifiedChoice{
|
|
|
|
Label: e.Label,
|
|
|
|
Value: v.Solved != nil,
|
|
|
|
Justification: v,
|
|
|
|
}
|
2018-12-02 03:52:15 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if v.Solved == nil {
|
|
|
|
fullySolved = false
|
|
|
|
}
|
2018-12-02 03:52:15 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if PartialValidation && m.PSolved != nil {
|
|
|
|
jc.Value = e.Response
|
|
|
|
}
|
|
|
|
|
|
|
|
m.Choices[strconv.Itoa(e.Id)] = jc
|
|
|
|
} else {
|
|
|
|
m.Choices[strconv.Itoa(e.Id)] = e.Label
|
|
|
|
}
|
2018-12-02 03:52:15 +00:00
|
|
|
} else {
|
2021-08-30 16:33:14 +00:00
|
|
|
m.Choices[strconv.Itoa(e.Id)] = e.Label
|
2018-11-28 06:09:05 +00:00
|
|
|
}
|
2018-11-28 05:39:38 +00:00
|
|
|
}
|
2018-12-02 03:52:15 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if t == nil {
|
|
|
|
h, _ := ComputeHashedFlag([]byte(soluce), false, false, nil, false)
|
|
|
|
m.Soluce = hex.EncodeToString(h[:])
|
|
|
|
}
|
2018-11-28 01:27:51 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
if fullySolved {
|
|
|
|
m.Solved = m.PSolved
|
|
|
|
m.PSolved = nil
|
|
|
|
}
|
2018-12-02 03:52:15 +00:00
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
exercice.Flags = append(exercice.Flags, m)
|
|
|
|
}
|
2016-01-23 11:20:30 +00:00
|
|
|
}
|
|
|
|
|
2023-04-06 13:41:14 +00:00
|
|
|
// Sort flags by order
|
|
|
|
sort.Sort(ByOrder(exercice.Flags))
|
|
|
|
}
|
2021-08-30 18:03:17 +00:00
|
|
|
|
2016-12-04 18:15:39 +00:00
|
|
|
// Hash table ordered by exercice Id
|
2016-01-23 11:20:30 +00:00
|
|
|
ret.Exercices[fmt.Sprintf("%d", e.Id)] = exercice
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret, nil
|
|
|
|
}
|
2022-06-07 14:05:41 +00:00
|
|
|
|
|
|
|
func ReadMyJSON(fd *os.File) (my MyTeam, err error) {
|
|
|
|
jdec := json.NewDecoder(fd)
|
|
|
|
|
|
|
|
err = jdec.Decode(&my)
|
|
|
|
return
|
|
|
|
}
|