Theme can be optional: exercices can be standalone
This commit is contained in:
parent
3519f7416d
commit
a0bc832910
@ -279,14 +279,20 @@ func exportResolutionMovies(c *gin.Context) {
|
|||||||
|
|
||||||
export := []map[string]string{}
|
export := []map[string]string{}
|
||||||
for _, exercice := range exercices {
|
for _, exercice := range exercices {
|
||||||
if theme, err := fic.GetTheme(exercice.IdTheme); err != nil {
|
var tname string
|
||||||
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
if exercice.IdTheme != nil {
|
||||||
return
|
theme, err := fic.GetTheme(*exercice.IdTheme)
|
||||||
} else if len(exercice.VideoURI) > 0 {
|
if err != nil {
|
||||||
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tname = theme.Name
|
||||||
|
}
|
||||||
|
if len(exercice.VideoURI) > 0 {
|
||||||
level, _ := exercice.GetLevel()
|
level, _ := exercice.GetLevel()
|
||||||
export = append(export, map[string]string{
|
export = append(export, map[string]string{
|
||||||
"videoURI": strings.Replace(exercice.VideoURI, "$FILES$/", "files/", 1),
|
"videoURI": strings.Replace(exercice.VideoURI, "$FILES$/", "files/", 1),
|
||||||
"theme": theme.Name,
|
"theme": tname,
|
||||||
"title": exercice.Title,
|
"title": exercice.Title,
|
||||||
"level": fmt.Sprintf("%d", level),
|
"level": fmt.Sprintf("%d", level),
|
||||||
})
|
})
|
||||||
|
@ -47,13 +47,19 @@ func treatOpeningHint(pathname string, team *fic.Team) {
|
|||||||
} else if err = team.OpenHint(hint); err != nil && !fic.DBIsDuplicateKeyError(err) { // Skip DUPLICATE KEY errors
|
} else if err = team.OpenHint(hint); err != nil && !fic.DBIsDuplicateKeyError(err) { // Skip DUPLICATE KEY errors
|
||||||
log.Printf("%s [ERR] Unable to open hint: %s\n", id, err)
|
log.Printf("%s [ERR] Unable to open hint: %s\n", id, err)
|
||||||
} else {
|
} else {
|
||||||
// Write event
|
if exercice.IdTheme == nil {
|
||||||
if lvl, err := exercice.GetLevel(); err != nil {
|
if _, err = fic.NewEvent(fmt.Sprintf("L'équipe %s a dévoilé un indice pour le défi %s !", html.EscapeString(team.Name), exercice.Title), "info"); err != nil {
|
||||||
log.Printf("%s [WRN] %s\n", id, err)
|
log.Printf("%s [WRN] Unable to create event: %s\n", id, err)
|
||||||
} else if theme, err := fic.GetTheme(exercice.IdTheme); err != nil {
|
}
|
||||||
log.Printf("%s [WRN] %s\n", id, err)
|
} else {
|
||||||
} else if _, err = fic.NewEvent(fmt.Sprintf("L'équipe %s a dévoilé un indice pour le <strong>%d<sup>e</sup></strong> défi %s !", html.EscapeString(team.Name), lvl, theme.Name), "info"); err != nil {
|
// Write event
|
||||||
log.Printf("%s [WRN] Unable to create event: %s\n", id, err)
|
if lvl, err := exercice.GetLevel(); err != nil {
|
||||||
|
log.Printf("%s [WRN] %s\n", id, err)
|
||||||
|
} else if theme, err := fic.GetTheme(*exercice.IdTheme); err != nil {
|
||||||
|
log.Printf("%s [WRN] %s\n", id, err)
|
||||||
|
} else if _, err = fic.NewEvent(fmt.Sprintf("L'équipe %s a dévoilé un indice pour le <strong>%d<sup>e</sup></strong> défi %s !", html.EscapeString(team.Name), lvl, theme.Name), "info"); err != nil {
|
||||||
|
log.Printf("%s [WRN] Unable to create event: %s\n", id, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
|
@ -65,16 +65,19 @@ func treatSubmission(pathname string, team *fic.Team, exercice_id string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the corresponding theme
|
// Find the corresponding theme
|
||||||
theme, err := fic.GetTheme(exercice.IdTheme)
|
var theme *fic.Theme
|
||||||
if err != nil {
|
if exercice.IdTheme != nil {
|
||||||
log.Printf("%s [ERR] Unable to retrieve theme for exercice %d: %s\n", id, eid, err)
|
theme, err = fic.GetTheme(*exercice.IdTheme)
|
||||||
return
|
if err != nil {
|
||||||
}
|
log.Printf("%s [ERR] Unable to retrieve theme for exercice %d: %s\n", id, eid, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Theme should not be locked
|
// Theme should not be locked
|
||||||
if theme.Locked {
|
if theme.Locked {
|
||||||
log.Printf("%s [!!!] Submission received for locked theme %d (eid=%d): %s\n", id, exercice.IdTheme, eid, theme.Name)
|
log.Printf("%s [!!!] Submission received for locked theme %d (eid=%d): %s\n", id, exercice.IdTheme, eid, theme.Name)
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read received file
|
// Read received file
|
||||||
@ -102,7 +105,11 @@ func treatSubmission(pathname string, team *fic.Team, exercice_id string) {
|
|||||||
// Ensure the team didn't already solve this exercice
|
// Ensure the team didn't already solve this exercice
|
||||||
tm := team.HasSolved(exercice)
|
tm := team.HasSolved(exercice)
|
||||||
if tm != nil {
|
if tm != nil {
|
||||||
log.Printf("%s [WRN] Team %d ALREADY solved exercice %d (%s : %s), continuing for eventual bonus flags\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
if theme == nil {
|
||||||
|
log.Printf("%s [WRN] Team %d ALREADY solved standalone exercice %d (%s), continuing for eventual bonus flags\n", id, team.Id, exercice.Id, exercice.Title)
|
||||||
|
} else {
|
||||||
|
log.Printf("%s [WRN] Team %d ALREADY solved exercice %d (%s : %s), continuing for eventual bonus flags\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle MCQ justifications: convert to expected keyid
|
// Handle MCQ justifications: convert to expected keyid
|
||||||
@ -141,29 +148,50 @@ func treatSubmission(pathname string, team *fic.Team, exercice_id string) {
|
|||||||
if tm != nil {
|
if tm != nil {
|
||||||
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
} else if solved {
|
} else if solved {
|
||||||
log.Printf("%s Team %d SOLVED exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
if theme == nil {
|
||||||
|
log.Printf("%s Team %d SOLVED exercice %d (%s)\n", id, team.Id, exercice.Id, exercice.Title)
|
||||||
|
} else {
|
||||||
|
log.Printf("%s Team %d SOLVED exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
||||||
|
|
||||||
|
}
|
||||||
if err := exercice.Solved(team); err != nil {
|
if err := exercice.Solved(team); err != nil {
|
||||||
log.Println(id, "[ERR] Unable to mark the challenge as solved:", err)
|
log.Println(id, "[ERR] Unable to mark the challenge as solved:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write event
|
// Write event
|
||||||
if lvl, err := exercice.GetLevel(); err != nil {
|
if theme == nil {
|
||||||
log.Println(id, "[ERR] Unable to get exercice level:", err)
|
if _, err := fic.NewEvent(fmt.Sprintf("L'équipe %s a résolu le défi %s !", html.EscapeString(team.Name), exercice.Title), "success"); err != nil {
|
||||||
} else if _, err := fic.NewEvent(fmt.Sprintf("L'équipe %s a résolu le <strong>%d<sup>e</sup></strong> défi %s !", html.EscapeString(team.Name), lvl, theme.Name), "success"); err != nil {
|
log.Println(id, "[WRN] Unable to create event:", err)
|
||||||
log.Println(id, "[WRN] Unable to create event:", err)
|
}
|
||||||
|
} else {
|
||||||
|
if lvl, err := exercice.GetLevel(); err != nil {
|
||||||
|
log.Println(id, "[ERR] Unable to get exercice level:", err)
|
||||||
|
} else if _, err := fic.NewEvent(fmt.Sprintf("L'équipe %s a résolu le <strong>%d<sup>e</sup></strong> défi %s !", html.EscapeString(team.Name), lvl, theme.Name), "success"); err != nil {
|
||||||
|
log.Println(id, "[WRN] Unable to create event:", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenThemes})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenThemes})
|
||||||
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeams})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeams})
|
||||||
} else {
|
} else {
|
||||||
log.Printf("%s Team %d submit an invalid solution for exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
if theme == nil {
|
||||||
|
log.Printf("%s Team %d submit an invalid solution for exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
|
||||||
|
} else {
|
||||||
|
log.Printf("%s Team %d submit an invalid solution for exercice %d (%s)\n", id, team.Id, exercice.Id, exercice.Title)
|
||||||
|
}
|
||||||
|
|
||||||
// Write event (only on first try)
|
// Write event (only on first try)
|
||||||
if tm == nil {
|
if tm == nil {
|
||||||
if lvl, err := exercice.GetLevel(); err != nil {
|
if theme == nil {
|
||||||
log.Println(id, "[ERR] Unable to get exercice level:", err)
|
if _, err := fic.NewEvent(fmt.Sprintf("L'équipe %s tente le défi %s !", html.EscapeString(team.Name), exercice.Title), "warning"); err != nil {
|
||||||
} else if _, err := fic.NewEvent(fmt.Sprintf("L'équipe %s tente le <strong>%d<sup>e</sup></strong> défi %s !", html.EscapeString(team.Name), lvl, theme.Name), "warning"); err != nil {
|
log.Println(id, "[WRN] Unable to create event:", err)
|
||||||
log.Println(id, "[WRN] Unable to create event:", err)
|
}
|
||||||
|
} else {
|
||||||
|
if lvl, err := exercice.GetLevel(); err != nil {
|
||||||
|
log.Println(id, "[ERR] Unable to get exercice level:", err)
|
||||||
|
} else if _, err := fic.NewEvent(fmt.Sprintf("L'équipe %s tente le <strong>%d<sup>e</sup></strong> défi %s !", html.EscapeString(team.Name), lvl, theme.Name), "warning"); err != nil {
|
||||||
|
log.Println(id, "[WRN] Unable to create event:", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
appendGenQueue(fic.GenStruct{Id: id, Type: fic.GenTeam, TeamId: team.Id})
|
||||||
|
@ -140,7 +140,7 @@ CREATE TABLE IF NOT EXISTS team_members(
|
|||||||
if _, err := db.Exec(`
|
if _, err := db.Exec(`
|
||||||
CREATE TABLE IF NOT EXISTS exercices(
|
CREATE TABLE IF NOT EXISTS exercices(
|
||||||
id_exercice INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
id_exercice INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
id_theme INTEGER NOT NULL,
|
id_theme INTEGER NULL,
|
||||||
title VARCHAR(255) NOT NULL,
|
title VARCHAR(255) NOT NULL,
|
||||||
authors TEXT NOT NULL,
|
authors TEXT NOT NULL,
|
||||||
image VARCHAR(255) NOT NULL,
|
image VARCHAR(255) NOT NULL,
|
||||||
|
@ -22,7 +22,7 @@ var ExerciceCurrentCoefficient = 1.0
|
|||||||
// Exercice represents a challenge inside a Theme.
|
// Exercice represents a challenge inside a Theme.
|
||||||
type Exercice struct {
|
type Exercice struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id"`
|
||||||
IdTheme int64 `json:"id_theme"`
|
IdTheme *int64 `json:"id_theme"`
|
||||||
Language string `json:"lang,omitempty"`
|
Language string `json:"lang,omitempty"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Authors string `json:"authors"`
|
Authors string `json:"authors"`
|
||||||
|
@ -68,7 +68,7 @@ type myTeamMCQJustifiedChoice struct {
|
|||||||
Justification myTeamFlag `json:"justification,omitempty"`
|
Justification myTeamFlag `json:"justification,omitempty"`
|
||||||
}
|
}
|
||||||
type myTeamExercice struct {
|
type myTeamExercice struct {
|
||||||
ThemeId int64 `json:"theme_id"`
|
ThemeId int64 `json:"theme_id,omitempty"`
|
||||||
Disabled bool `json:"disabled,omitempty"`
|
Disabled bool `json:"disabled,omitempty"`
|
||||||
WIP bool `json:"wip,omitempty"`
|
WIP bool `json:"wip,omitempty"`
|
||||||
Statement string `json:"statement"`
|
Statement string `json:"statement"`
|
||||||
@ -136,11 +136,11 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
|
|||||||
return ret, err
|
return ret, err
|
||||||
} else if started {
|
} else if started {
|
||||||
for _, e := range exos {
|
for _, e := range exos {
|
||||||
if t == nil || ((!e.Disabled || !mapthemes[e.IdTheme].Locked) && t.HasAccess(e)) {
|
if t == nil || ((!e.Disabled || (e.IdTheme != nil && !mapthemes[*e.IdTheme].Locked)) && t.HasAccess(e)) {
|
||||||
exercice := myTeamExercice{}
|
exercice := myTeamExercice{}
|
||||||
exercice.Disabled = e.Disabled
|
exercice.Disabled = e.Disabled
|
||||||
exercice.WIP = e.WIP
|
exercice.WIP = e.WIP
|
||||||
exercice.ThemeId = e.IdTheme
|
exercice.ThemeId = *e.IdTheme
|
||||||
|
|
||||||
exercice.Statement = strings.Replace(e.Statement, "$FILES$", FilesDir, -1)
|
exercice.Statement = strings.Replace(e.Statement, "$FILES$", FilesDir, -1)
|
||||||
|
|
||||||
|
@ -393,7 +393,9 @@ func (t *Team) MyIssueFile() (ret []teamIssueFile, err error) {
|
|||||||
|
|
||||||
if exo, err := claim.GetExercice(); err == nil && exo != nil {
|
if exo, err := claim.GetExercice(); err == nil && exo != nil {
|
||||||
exercice = &exo.Title
|
exercice = &exo.Title
|
||||||
if theme, err := GetTheme(exo.IdTheme); err == nil {
|
if exo.IdTheme == nil {
|
||||||
|
url = path.Join("_", exo.URLId)
|
||||||
|
} else if theme, err := GetTheme(*exo.IdTheme); err == nil {
|
||||||
url = path.Join(theme.URLId, exo.URLId)
|
url = path.Join(theme.URLId, exo.URLId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ func exerciceHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if th, ok := c.Get("theme"); ok {
|
if th, ok := c.Get("theme"); ok {
|
||||||
if exercice.IdTheme != th.(*fic.Theme).Id {
|
if exercice.IdTheme == nil || *exercice.IdTheme != th.(*fic.Theme).Id {
|
||||||
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Exercice not found."})
|
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Exercice not found."})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user