Compare commits
4 Commits
23d95c071b
...
e19eb53b1f
Author | SHA1 | Date | |
---|---|---|---|
e19eb53b1f | |||
32de7b2310 | |||
11d02b8e4b | |||
a8da2403df |
|
@ -31,6 +31,9 @@ func declareExportRoutes(router *gin.RouterGroup) {
|
||||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
s.End = nil
|
||||||
|
s.NextChangeTime = nil
|
||||||
|
s.DelegatedQA = []string{}
|
||||||
|
|
||||||
teams, err := fic.ExportTeams(false)
|
teams, err := fic.ExportTeams(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -73,7 +73,7 @@ func main() {
|
||||||
func treatDir(p string) {
|
func treatDir(p string) {
|
||||||
var expath string
|
var expath string
|
||||||
|
|
||||||
for _, f := range []string{"challenge.txt", "challenge.toml"} {
|
for _, f := range []string{"challenge.toml", "challenge.txt"} {
|
||||||
if sync.GlobalImporter.Exists(path.Join(p, f)) {
|
if sync.GlobalImporter.Exists(path.Join(p, f)) {
|
||||||
expath = p
|
expath = p
|
||||||
break
|
break
|
||||||
|
@ -108,7 +108,7 @@ func treatExercice(expath string) {
|
||||||
|
|
||||||
paramsFiles, err := sync.GetExerciceFilesParams(sync.GlobalImporter, exercice)
|
paramsFiles, err := sync.GetExerciceFilesParams(sync.GlobalImporter, exercice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Unable to read challenge.txt %q: %s", expath, err.Error())
|
log.Printf("Unable to read challenge.toml %q: %s", expath, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,9 +106,9 @@ func NewChallengeTxtError(exercice *fic.Exercice, line uint, err error, theme ..
|
||||||
|
|
||||||
func (e *ChallengeTxtError) Error() string {
|
func (e *ChallengeTxtError) Error() string {
|
||||||
if e.ChallengeTxtLine != 0 {
|
if e.ChallengeTxtLine != 0 {
|
||||||
return fmt.Sprintf("%s:%d: %s", path.Join(e.ExercicePath, "challenge.txt"), e.ChallengeTxtLine, e.ThemeError.error.Error())
|
return fmt.Sprintf("%s:%d: %s", path.Join(e.ExercicePath, "challenge.toml"), e.ChallengeTxtLine, e.ThemeError.error.Error())
|
||||||
} else {
|
} else {
|
||||||
return fmt.Sprintf("%s: %s", path.Join(e.ExercicePath, "challenge.txt"), e.ThemeError.error.Error())
|
return fmt.Sprintf("%s: %s", path.Join(e.ExercicePath, "challenge.toml"), e.ThemeError.error.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ func NewHintError(exercice *fic.Exercice, hint *fic.EHint, line int, err error,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *HintError) Error() string {
|
func (e *HintError) Error() string {
|
||||||
return fmt.Sprintf("%s: hint#%d (%s): %s", path.Join(e.ExercicePath, "challenge.txt"), e.HintId, e.HintTitle, e.ThemeError.error.Error())
|
return fmt.Sprintf("%s: hint#%d (%s): %s", path.Join(e.ExercicePath, "challenge.toml"), e.HintId, e.HintTitle, e.ThemeError.error.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
type FlagError struct {
|
type FlagError struct {
|
||||||
|
@ -144,5 +144,5 @@ func NewFlagError(exercice *fic.Exercice, flag *ExerciceFlag, line int, err erro
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *FlagError) Error() string {
|
func (e *FlagError) Error() string {
|
||||||
return fmt.Sprintf("%s: flag#%d: %s", path.Join(e.ExercicePath, "challenge.txt"), e.FlagId, e.ThemeError.error.Error())
|
return fmt.Sprintf("%s: flag#%d: %s", path.Join(e.ExercicePath, "challenge.toml"), e.FlagId, e.ThemeError.error.Error())
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,10 +26,10 @@ const sampleFile = `0-exercice-1/overview.md:spelling:Sterik
|
||||||
0-exercice-1/resolution.md:11:typo_guillemets_typographiques_doubles_fermants
|
0-exercice-1/resolution.md:11:typo_guillemets_typographiques_doubles_fermants
|
||||||
0-exercice-1/resolution.md:spelling:cronjob
|
0-exercice-1/resolution.md:spelling:cronjob
|
||||||
0-exercice-1/resolution.md:spelling:Level
|
0-exercice-1/resolution.md:spelling:Level
|
||||||
challenge.txt:spelling:time
|
challenge.toml:spelling:time
|
||||||
challenge.txt:spelling:ago
|
challenge.toml:spelling:ago
|
||||||
0-exercice-1/resolution.md:spelling:SCL
|
0-exercice-1/resolution.md:spelling:SCL
|
||||||
challenge.txt:spelling:SCL`
|
challenge.toml:spelling:SCL`
|
||||||
|
|
||||||
func TestLoadExceptions(t *testing.T) {
|
func TestLoadExceptions(t *testing.T) {
|
||||||
exceptions := ParseExceptionString(sampleFile, nil)
|
exceptions := ParseExceptionString(sampleFile, nil)
|
||||||
|
@ -47,7 +47,7 @@ func TestFilterExceptions(t *testing.T) {
|
||||||
t.Fatalf("Expected 1 exceptions, got %d", len(*filteredExceptions))
|
t.Fatalf("Expected 1 exceptions, got %d", len(*filteredExceptions))
|
||||||
}
|
}
|
||||||
|
|
||||||
filteredExceptions = exceptions.GetFileExceptions("challenge.txt")
|
filteredExceptions = exceptions.GetFileExceptions("challenge.toml")
|
||||||
if len(*filteredExceptions) != 3 {
|
if len(*filteredExceptions) != 3 {
|
||||||
t.Fatalf("Expected 3 exceptions, got %d", len(*filteredExceptions))
|
t.Fatalf("Expected 3 exceptions, got %d", len(*filteredExceptions))
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ func buildExerciceHints(i Importer, exercice *fic.Exercice, exceptions *CheckExc
|
||||||
|
|
||||||
// CheckExerciceHints checks if all hints are corrects..
|
// CheckExerciceHints checks if all hints are corrects..
|
||||||
func CheckExerciceHints(i Importer, exercice *fic.Exercice, exceptions *CheckExceptions) ([]importHint, error) {
|
func CheckExerciceHints(i Importer, exercice *fic.Exercice, exceptions *CheckExceptions) ([]importHint, error) {
|
||||||
exceptions = exceptions.GetFileExceptions("challenge.txt", "challenge.toml")
|
exceptions = exceptions.GetFileExceptions("challenge.toml", "challenge.txt")
|
||||||
|
|
||||||
hints, errs := buildExerciceHints(i, exercice, exceptions)
|
hints, errs := buildExerciceHints(i, exercice, exceptions)
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ func SyncExerciceHints(i Importer, exercice *fic.Exercice, flagsBindings map[int
|
||||||
if _, err := exercice.WipeHints(); err != nil {
|
if _, err := exercice.WipeHints(); err != nil {
|
||||||
errs = multierr.Append(errs, err)
|
errs = multierr.Append(errs, err)
|
||||||
} else {
|
} else {
|
||||||
exceptions = exceptions.GetFileExceptions("challenge.txt", "challenge.toml")
|
exceptions = exceptions.GetFileExceptions("challenge.toml", "challenge.txt")
|
||||||
|
|
||||||
hints, berrs := buildExerciceHints(i, exercice, exceptions)
|
hints, berrs := buildExerciceHints(i, exercice, exceptions)
|
||||||
errs = multierr.Append(errs, berrs)
|
errs = multierr.Append(errs, berrs)
|
||||||
|
|
|
@ -541,7 +541,7 @@ func buildExerciceFlags(i Importer, exercice *fic.Exercice, exceptions *CheckExc
|
||||||
|
|
||||||
// CheckExerciceFlags checks if all flags for the given challenge are correct.
|
// CheckExerciceFlags checks if all flags for the given challenge are correct.
|
||||||
func CheckExerciceFlags(i Importer, exercice *fic.Exercice, files []string, exceptions *CheckExceptions) (rf []fic.Flag, errs error) {
|
func CheckExerciceFlags(i Importer, exercice *fic.Exercice, files []string, exceptions *CheckExceptions) (rf []fic.Flag, errs error) {
|
||||||
exceptions = exceptions.GetFileExceptions("challenge.txt", "challenge.toml")
|
exceptions = exceptions.GetFileExceptions("challenge.toml", "challenge.txt")
|
||||||
|
|
||||||
flags, flagsids, berrs := buildExerciceFlags(i, exercice, exceptions)
|
flags, flagsids, berrs := buildExerciceFlags(i, exercice, exceptions)
|
||||||
errs = multierr.Append(errs, berrs)
|
errs = multierr.Append(errs, berrs)
|
||||||
|
@ -634,7 +634,7 @@ func SyncExerciceFlags(i Importer, exercice *fic.Exercice, exceptions *CheckExce
|
||||||
} else if _, err := exercice.WipeMCQs(); err != nil {
|
} else if _, err := exercice.WipeMCQs(); err != nil {
|
||||||
errs = multierr.Append(errs, err)
|
errs = multierr.Append(errs, err)
|
||||||
} else {
|
} else {
|
||||||
exceptions = exceptions.GetFileExceptions("challenge.txt", "challenge.toml")
|
exceptions = exceptions.GetFileExceptions("challenge.toml", "challenge.txt")
|
||||||
|
|
||||||
flags, flagids, berrs := buildExerciceFlags(i, exercice, exceptions)
|
flags, flagids, berrs := buildExerciceFlags(i, exercice, exceptions)
|
||||||
errs = multierr.Append(errs, berrs)
|
errs = multierr.Append(errs, berrs)
|
||||||
|
|
|
@ -280,7 +280,7 @@ func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*
|
||||||
|
|
||||||
e.WIP = p.WIP
|
e.WIP = p.WIP
|
||||||
if p.WIP && !AllowWIPExercice {
|
if p.WIP && !AllowWIPExercice {
|
||||||
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("exercice declared Work In Progress in challenge.txt"), theme))
|
errs = multierr.Append(errs, NewExerciceError(e, fmt.Errorf("exercice declared Work In Progress in challenge.toml"), theme))
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Gain == 0 {
|
if p.Gain == 0 {
|
||||||
|
|
8
frontend/fic/package-lock.json
generated
|
@ -15,7 +15,6 @@
|
||||||
"hash-wasm": "^4.9.0",
|
"hash-wasm": "^4.9.0",
|
||||||
"seedrandom": "^3.0.5",
|
"seedrandom": "^3.0.5",
|
||||||
"svelte-bricks": "^0.2.1",
|
"svelte-bricks": "^0.2.1",
|
||||||
"vite": "^5.0.0",
|
|
||||||
"wordcloud": "^1.2.2"
|
"wordcloud": "^1.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -2797,10 +2796,11 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.2.8",
|
"version": "5.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz",
|
||||||
"integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==",
|
"integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.20.1",
|
"esbuild": "^0.20.1",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
<a href="." style="max-width: 50%">
|
<a href="." style="max-width: 50%">
|
||||||
{#if $challengeInfo && $challengeInfo.main_logo}
|
{#if $challengeInfo && $challengeInfo.main_logo}
|
||||||
{#each $challengeInfo.main_logo as logo, i}
|
{#each $challengeInfo.main_logo as logo, i}
|
||||||
<img src={logo.replace('$FILES$', base + '/files/')} alt={'Logo principal #' + i} class={'h-100' + (i > 0?' d-none d-md-inline ms-2':'')}>
|
<img src={logo.replace('$FILES$/', base + '/files/')} alt={'Logo principal #' + i} class={'h-100' + (i > 0?' d-none d-md-inline ms-2':'')}>
|
||||||
{/each}
|
{/each}
|
||||||
{/if}
|
{/if}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -65,7 +65,7 @@
|
||||||
{#each $themesStore["0"].exercices as exercice, index}
|
{#each $themesStore["0"].exercices as exercice, index}
|
||||||
<DropdownItem href="{$themesStore["0"].urlid}/{exercice.urlid}" active={$current_theme && $current_theme.id == 0 && $current_exercice && $current_exercice.id == exercice.id}>
|
<DropdownItem href="{$themesStore["0"].urlid}/{exercice.urlid}" active={$current_theme && $current_theme.id == 0 && $current_exercice && $current_exercice.id == exercice.id}>
|
||||||
{exercice.title}
|
{exercice.title}
|
||||||
{#if exercice.solved}
|
{#if $my && $my.id_team && exercice.solved}
|
||||||
<Badge color="success" pill>
|
<Badge color="success" pill>
|
||||||
<Icon name="check" />
|
<Icon name="check" />
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
document.body.style.backgroundColor = "";
|
document.body.style.backgroundColor = "";
|
||||||
|
|
||||||
let items = [];
|
let items = [];
|
||||||
$: {
|
function refresh_items() {
|
||||||
const tmpitems = [];
|
const tmpitems = [];
|
||||||
for (const th of $themes) {
|
for (const th of $themes) {
|
||||||
if (th.id == 0) continue;
|
if (th.id == 0) continue;
|
||||||
|
@ -43,6 +43,8 @@
|
||||||
// Only apply after start
|
// Only apply after start
|
||||||
if (!($time.startIn && j < nb_ex_max && j < $settings.unlockedStandaloneExercices))
|
if (!($time.startIn && j < nb_ex_max && j < $settings.unlockedStandaloneExercices))
|
||||||
continue;
|
continue;
|
||||||
|
} else if ($my && !$my.team_id && j >= nb_ex_max) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpitems.splice(i, 0, {id: tmpitems.length, theme: $themesStore["0"], exercice: $themesStore["0"].exercices[j]});
|
tmpitems.splice(i, 0, {id: tmpitems.length, theme: $themesStore["0"], exercice: $themesStore["0"].exercices[j]});
|
||||||
|
@ -65,6 +67,7 @@
|
||||||
|
|
||||||
items = tmpitems;
|
items = tmpitems;
|
||||||
}
|
}
|
||||||
|
$: refresh_items($themes);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Container class="mt-3 mb-5">
|
<Container class="mt-3 mb-5">
|
||||||
|
|
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 10 KiB |
7
qa/ui/package-lock.json
generated
|
@ -2544,10 +2544,11 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.2.8",
|
"version": "5.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz",
|
||||||
"integrity": "sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA==",
|
"integrity": "sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.20.1",
|
"esbuild": "^0.20.1",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
|
|
|
@ -248,7 +248,7 @@ func main() {
|
||||||
nberr := 0
|
nberr := 0
|
||||||
theme, exceptions, errs := sync.BuildTheme(sync.GlobalImporter, p)
|
theme, exceptions, errs := sync.BuildTheme(sync.GlobalImporter, p)
|
||||||
|
|
||||||
if theme != nil && !sync.GlobalImporter.Exists(path.Join(p, "challenge.txt")) && !sync.GlobalImporter.Exists(path.Join(p, "challenge.toml")) {
|
if theme != nil && !sync.GlobalImporter.Exists(path.Join(p, "challenge.toml")) && !sync.GlobalImporter.Exists(path.Join(p, "challenge.txt")) {
|
||||||
thiserrors := multierr.Errors(errs)
|
thiserrors := multierr.Errors(errs)
|
||||||
nberr += len(thiserrors)
|
nberr += len(thiserrors)
|
||||||
for _, err := range thiserrors {
|
for _, err := range thiserrors {
|
||||||
|
|