Use pointer receiver more offen

This commit is contained in:
nemunaire 2021-11-22 15:35:07 +01:00
parent 6999b4e728
commit c7569b5e54
59 changed files with 688 additions and 672 deletions

View file

@ -67,7 +67,7 @@ func init() {
})) }))
router.GET("/api/teams/:tid/certificates", apiHandler(teamHandler( router.GET("/api/teams/:tid/certificates", apiHandler(teamHandler(
func(team fic.Team, _ []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
if serials, err := pki.GetTeamSerials(TeamsDir, team.Id); err != nil { if serials, err := pki.GetTeamSerials(TeamsDir, team.Id); err != nil {
return nil, err return nil, err
} else { } else {
@ -84,18 +84,18 @@ func init() {
}))) })))
router.GET("/api/teams/:tid/associations", apiHandler(teamHandler( router.GET("/api/teams/:tid/associations", apiHandler(teamHandler(
func(team fic.Team, _ []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
return pki.GetTeamAssociations(TeamsDir, team.Id) return pki.GetTeamAssociations(TeamsDir, team.Id)
}))) })))
router.POST("/api/teams/:tid/associations/:assoc", apiHandler(teamAssocHandler( router.POST("/api/teams/:tid/associations/:assoc", apiHandler(teamAssocHandler(
func(team fic.Team, assoc string, _ []byte) (interface{}, error) { func(team *fic.Team, assoc string, _ []byte) (interface{}, error) {
if err := os.Symlink(fmt.Sprintf("%d", team.Id), path.Join(TeamsDir, assoc)); err != nil { if err := os.Symlink(fmt.Sprintf("%d", team.Id), path.Join(TeamsDir, assoc)); err != nil {
return nil, err return nil, err
} }
return "\"" + assoc + "\"", nil return "\"" + assoc + "\"", nil
}))) })))
router.DELETE("/api/teams/:tid/associations/:assoc", apiHandler(teamAssocHandler( router.DELETE("/api/teams/:tid/associations/:assoc", apiHandler(teamAssocHandler(
func(team fic.Team, assoc string, _ []byte) (interface{}, error) { func(team *fic.Team, assoc string, _ []byte) (interface{}, error) {
if err := os.Remove(path.Join(TeamsDir, assoc)); err != nil { if err := os.Remove(path.Join(TeamsDir, assoc)); err != nil {
return nil, err return nil, err
} }
@ -110,11 +110,11 @@ func init() {
router.GET("/api/certs/:certid", apiHandler(certificateHandler(getTeamP12File))) router.GET("/api/certs/:certid", apiHandler(certificateHandler(getTeamP12File)))
router.PUT("/api/certs/:certid", apiHandler(certificateHandler(updateCertificateAssociation))) router.PUT("/api/certs/:certid", apiHandler(certificateHandler(updateCertificateAssociation)))
router.DELETE("/api/certs/:certid", apiHandler(certificateHandler( router.DELETE("/api/certs/:certid", apiHandler(certificateHandler(
func(cert fic.Certificate, _ []byte) (interface{}, error) { return cert.Revoke() }))) func(cert *fic.Certificate, _ []byte) (interface{}, error) { return cert.Revoke() })))
} }
func genHtpasswd(ssha bool) (ret string, err error) { func genHtpasswd(ssha bool) (ret string, err error) {
var teams []fic.Team var teams []*fic.Team
teams, err = fic.GetTeams() teams, err = fic.GetTeams()
if err != nil { if err != nil {
return return
@ -133,7 +133,7 @@ func genHtpasswd(ssha bool) (ret string, err error) {
} }
for _, serial := range serials { for _, serial := range serials {
var cert fic.Certificate var cert *fic.Certificate
cert, err = fic.GetCertificate(serial) cert, err = fic.GetCertificate(serial)
if err != nil { if err != nil {
// Ignore invalid/incorrect/non-existant certificates // Ignore invalid/incorrect/non-existant certificates
@ -219,7 +219,7 @@ func getCAPEM(_ httprouter.Params, _ []byte) (interface{}, error) {
} }
} }
func getTeamP12File(cert fic.Certificate, _ []byte) (interface{}, error) { func getTeamP12File(cert *fic.Certificate, _ []byte) (interface{}, error) {
// Create p12 if necessary // Create p12 if necessary
if _, err := os.Stat(pki.ClientP12Path(cert.Id)); os.IsNotExist(err) { if _, err := os.Stat(pki.ClientP12Path(cert.Id)); os.IsNotExist(err) {
if err := pki.WriteP12(cert.Id, cert.Password); err != nil { if err := pki.WriteP12(cert.Id, cert.Password); err != nil {
@ -308,7 +308,7 @@ type CertUploaded struct {
Team *int64 `json:"id_team"` Team *int64 `json:"id_team"`
} }
func updateCertificateAssociation(cert fic.Certificate, body []byte) (interface{}, error) { func updateCertificateAssociation(cert *fic.Certificate, body []byte) (interface{}, error) {
var uc CertUploaded var uc CertUploaded
if err := json.Unmarshal(body, &uc); err != nil { if err := json.Unmarshal(body, &uc); err != nil {
return nil, err return nil, err

View file

@ -15,7 +15,7 @@ import (
func init() { func init() {
router.GET("/api/teams/:tid/issue.json", apiHandler(teamHandler( router.GET("/api/teams/:tid/issue.json", apiHandler(teamHandler(
func(team fic.Team, _ []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
return team.MyIssueFile() return team.MyIssueFile()
}))) })))
@ -48,35 +48,35 @@ func getClaims(_ httprouter.Params, _ []byte) (interface{}, error) {
return fic.GetClaims() return fic.GetClaims()
} }
func getTeamClaims(team fic.Team, _ []byte) (interface{}, error) { func getTeamClaims(team *fic.Team, _ []byte) (interface{}, error) {
return team.GetClaims() return team.GetClaims()
} }
func getExerciceClaims(exercice fic.Exercice, _ []byte) (interface{}, error) { func getExerciceClaims(exercice *fic.Exercice, _ []byte) (interface{}, error) {
return exercice.GetClaims() return exercice.GetClaims()
} }
func getClaimLastUpdate(claim fic.Claim, _ []byte) (interface{}, error) { func getClaimLastUpdate(claim *fic.Claim, _ []byte) (interface{}, error) {
return claim.GetLastUpdate() return claim.GetLastUpdate()
} }
type ClaimExported struct { type ClaimExported struct {
Id int64 `json:"id"` Id int64 `json:"id"`
Subject string `json:"subject"` Subject string `json:"subject"`
IdTeam *int64 `json:"id_team"` IdTeam *int64 `json:"id_team"`
Team *fic.Team `json:"team"` Team *fic.Team `json:"team"`
IdExercice *int64 `json:"id_exercice"` IdExercice *int64 `json:"id_exercice"`
Exercice *fic.Exercice `json:"exercice"` Exercice *fic.Exercice `json:"exercice"`
IdAssignee *int64 `json:"id_assignee"` IdAssignee *int64 `json:"id_assignee"`
Assignee *fic.ClaimAssignee `json:"assignee"` Assignee *fic.ClaimAssignee `json:"assignee"`
Creation time.Time `json:"creation"` Creation time.Time `json:"creation"`
LastUpdate time.Time `json:"last_update"` LastUpdate time.Time `json:"last_update"`
State string `json:"state"` State string `json:"state"`
Priority string `json:"priority"` Priority string `json:"priority"`
Descriptions []fic.ClaimDescription `json:"descriptions"` Descriptions []*fic.ClaimDescription `json:"descriptions"`
} }
func showClaim(claim fic.Claim, _ []byte) (interface{}, error) { func showClaim(claim *fic.Claim, _ []byte) (interface{}, error) {
var e ClaimExported var e ClaimExported
var err error var err error
if e.Team, err = claim.GetTeam(); err != nil { if e.Team, err = claim.GetTeam(); err != nil {
@ -130,7 +130,7 @@ func newClaim(_ httprouter.Params, body []byte) (interface{}, error) {
if team, err := fic.GetTeam(*uc.IdTeam); err != nil { if team, err := fic.GetTeam(*uc.IdTeam); err != nil {
return nil, fmt.Errorf("Unable to get associated team: %w", err) return nil, fmt.Errorf("Unable to get associated team: %w", err)
} else { } else {
t = &team t = team
} }
} else { } else {
t = nil t = nil
@ -141,7 +141,7 @@ func newClaim(_ httprouter.Params, body []byte) (interface{}, error) {
if exercice, err := fic.GetExercice(*uc.IdExercice); err != nil { if exercice, err := fic.GetExercice(*uc.IdExercice); err != nil {
return nil, fmt.Errorf("Unable to get associated exercice: %w", err) return nil, fmt.Errorf("Unable to get associated exercice: %w", err)
} else { } else {
e = &exercice e = exercice
} }
} else { } else {
e = nil e = nil
@ -152,7 +152,7 @@ func newClaim(_ httprouter.Params, body []byte) (interface{}, error) {
if assignee, err := fic.GetAssignee(*uc.IdAssignee); err != nil { if assignee, err := fic.GetAssignee(*uc.IdAssignee); err != nil {
return nil, fmt.Errorf("Unable to get associated assignee: %w", err) return nil, fmt.Errorf("Unable to get associated assignee: %w", err)
} else { } else {
a = &assignee a = assignee
} }
} else { } else {
a = nil a = nil
@ -180,7 +180,7 @@ func generateTeamIssuesFile(team fic.Team) error {
return nil return nil
} }
func addClaimDescription(claim fic.Claim, body []byte) (interface{}, error) { func addClaimDescription(claim *fic.Claim, body []byte) (interface{}, error) {
var ud fic.ClaimDescription var ud fic.ClaimDescription
if err := json.Unmarshal(body, &ud); err != nil { if err := json.Unmarshal(body, &ud); err != nil {
return nil, fmt.Errorf("Unable to decode JSON: %w", err) return nil, fmt.Errorf("Unable to decode JSON: %w", err)
@ -199,7 +199,7 @@ func addClaimDescription(claim fic.Claim, body []byte) (interface{}, error) {
} }
} }
func updateClaimDescription(claim fic.Claim, body []byte) (interface{}, error) { func updateClaimDescription(claim *fic.Claim, body []byte) (interface{}, error) {
var ud fic.ClaimDescription var ud fic.ClaimDescription
if err := json.Unmarshal(body, &ud); err != nil { if err := json.Unmarshal(body, &ud); err != nil {
return nil, fmt.Errorf("Unable to decode JSON: %w", err) return nil, fmt.Errorf("Unable to decode JSON: %w", err)
@ -216,7 +216,7 @@ func updateClaimDescription(claim fic.Claim, body []byte) (interface{}, error) {
} }
} }
func updateClaim(claim fic.Claim, body []byte) (interface{}, error) { func updateClaim(claim *fic.Claim, body []byte) (interface{}, error) {
var uc ClaimUploaded var uc ClaimUploaded
if err := json.Unmarshal(body, &uc); err != nil { if err := json.Unmarshal(body, &uc); err != nil {
return nil, fmt.Errorf("Unable to decode JSON: %w", err) return nil, fmt.Errorf("Unable to decode JSON: %w", err)
@ -261,7 +261,7 @@ func updateClaim(claim fic.Claim, body []byte) (interface{}, error) {
} }
} }
func deleteClaim(claim fic.Claim, _ []byte) (interface{}, error) { func deleteClaim(claim *fic.Claim, _ []byte) (interface{}, error) {
return claim.Delete() return claim.Delete()
} }
@ -269,7 +269,7 @@ func getAssignees(_ httprouter.Params, _ []byte) (interface{}, error) {
return fic.GetAssignees() return fic.GetAssignees()
} }
func showClaimAssignee(assignee fic.ClaimAssignee, _ []byte) (interface{}, error) { func showClaimAssignee(assignee *fic.ClaimAssignee, _ []byte) (interface{}, error) {
return assignee, nil return assignee, nil
} }
func newAssignee(_ httprouter.Params, body []byte) (interface{}, error) { func newAssignee(_ httprouter.Params, body []byte) (interface{}, error) {
@ -281,7 +281,7 @@ func newAssignee(_ httprouter.Params, body []byte) (interface{}, error) {
return fic.NewClaimAssignee(ua.Name) return fic.NewClaimAssignee(ua.Name)
} }
func updateClaimAssignee(assignee fic.ClaimAssignee, body []byte) (interface{}, error) { func updateClaimAssignee(assignee *fic.ClaimAssignee, body []byte) (interface{}, error) {
var ua fic.ClaimAssignee var ua fic.ClaimAssignee
if err := json.Unmarshal(body, &ua); err != nil { if err := json.Unmarshal(body, &ua); err != nil {
return nil, fmt.Errorf("Unable to decode JSON: %w", err) return nil, fmt.Errorf("Unable to decode JSON: %w", err)
@ -296,6 +296,6 @@ func updateClaimAssignee(assignee fic.ClaimAssignee, body []byte) (interface{},
} }
} }
func deleteClaimAssignee(assignee fic.ClaimAssignee, _ []byte) (interface{}, error) { func deleteClaimAssignee(assignee *fic.ClaimAssignee, _ []byte) (interface{}, error) {
return assignee.Delete() return assignee.Delete()
} }

View file

@ -49,7 +49,7 @@ func getLastEvents(_ httprouter.Params, _ []byte) (interface{}, error) {
} }
} }
func showEvent(event fic.Event, _ []byte) (interface{}, error) { func showEvent(event *fic.Event, _ []byte) (interface{}, error) {
return event, nil return event, nil
} }
@ -71,7 +71,7 @@ func clearEvents(_ httprouter.Params, _ []byte) (interface{}, error) {
return fic.ClearEvents() return fic.ClearEvents()
} }
func updateEvent(event fic.Event, body []byte) (interface{}, error) { func updateEvent(event *fic.Event, body []byte) (interface{}, error) {
var ue fic.Event var ue fic.Event
if err := json.Unmarshal(body, &ue); err != nil { if err := json.Unmarshal(body, &ue); err != nil {
return nil, err return nil, err
@ -87,7 +87,7 @@ func updateEvent(event fic.Event, body []byte) (interface{}, error) {
} }
} }
func deleteEvent(event fic.Event, _ []byte) (interface{}, error) { func deleteEvent(event *fic.Event, _ []byte) (interface{}, error) {
if i, err := event.Delete(); err != nil { if i, err := event.Delete(); err != nil {
return i, err return i, err
} else { } else {

View file

@ -66,24 +66,24 @@ func init() {
// Synchronize // Synchronize
router.POST("/api/sync/themes/:thid/exercices/:eid", apiHandler(themedExerciceHandler( router.POST("/api/sync/themes/:thid/exercices/:eid", apiHandler(themedExerciceHandler(
func(theme fic.Theme, exercice fic.Exercice, _ []byte) (interface{}, error) { func(theme *fic.Theme, exercice *fic.Exercice, _ []byte) (interface{}, error) {
_, _, errs := sync.SyncExercice(sync.GlobalImporter, theme, exercice.Path, nil) _, _, errs := sync.SyncExercice(sync.GlobalImporter, theme, exercice.Path, nil)
return errs, nil return errs, nil
}))) })))
router.POST("/api/sync/exercices/:eid/hints", apiHandler(exerciceHandler( router.POST("/api/sync/exercices/:eid/hints", apiHandler(exerciceHandler(
func(exercice fic.Exercice, _ []byte) (interface{}, error) { func(exercice *fic.Exercice, _ []byte) (interface{}, error) {
_, errs := sync.SyncExerciceHints(sync.GlobalImporter, exercice, sync.ExerciceFlagsMap(sync.GlobalImporter, exercice)) _, errs := sync.SyncExerciceHints(sync.GlobalImporter, exercice, sync.ExerciceFlagsMap(sync.GlobalImporter, exercice))
return errs, nil return errs, nil
}))) })))
router.POST("/api/sync/exercices/:eid/flags", apiHandler(exerciceHandler( router.POST("/api/sync/exercices/:eid/flags", apiHandler(exerciceHandler(
func(exercice fic.Exercice, _ []byte) (interface{}, error) { func(exercice *fic.Exercice, _ []byte) (interface{}, error) {
_, errs := sync.SyncExerciceFlags(sync.GlobalImporter, exercice) _, errs := sync.SyncExerciceFlags(sync.GlobalImporter, exercice)
_, herrs := sync.SyncExerciceHints(sync.GlobalImporter, exercice, sync.ExerciceFlagsMap(sync.GlobalImporter, exercice)) _, herrs := sync.SyncExerciceHints(sync.GlobalImporter, exercice, sync.ExerciceFlagsMap(sync.GlobalImporter, exercice))
return append(errs, herrs...), nil return append(errs, herrs...), nil
}))) })))
router.POST("/api/sync/exercices/:eid/fixurlid", apiHandler(exerciceHandler( router.POST("/api/sync/exercices/:eid/fixurlid", apiHandler(exerciceHandler(
func(exercice fic.Exercice, _ []byte) (interface{}, error) { func(exercice *fic.Exercice, _ []byte) (interface{}, error) {
if exercice.FixURLId() { if exercice.FixURLId() {
return exercice.Update() return exercice.Update()
} }
@ -125,13 +125,13 @@ func loadFlags(n func() ([]fic.Flag, error)) (interface{}, error) {
var ret []fic.Flag var ret []fic.Flag
for _, flag := range flags { for _, flag := range flags {
if f, ok := flag.(fic.FlagKey); ok { if f, ok := flag.(*fic.FlagKey); ok {
if k, err := fic.GetFlagKey(f.Id); err != nil { if k, err := fic.GetFlagKey(f.Id); err != nil {
return nil, err return nil, err
} else { } else {
ret = append(ret, k) ret = append(ret, k)
} }
} else if f, ok := flag.(fic.MCQ); ok { } else if f, ok := flag.(*fic.MCQ); ok {
if m, err := fic.GetMCQ(f.Id); err != nil { if m, err := fic.GetMCQ(f.Id); err != nil {
return nil, err return nil, err
} else { } else {
@ -146,27 +146,27 @@ func loadFlags(n func() ([]fic.Flag, error)) (interface{}, error) {
} }
} }
func listExerciceHints(exercice fic.Exercice, body []byte) (interface{}, error) { func listExerciceHints(exercice *fic.Exercice, body []byte) (interface{}, error) {
return exercice.GetHints() return exercice.GetHints()
} }
func listExerciceFlags(exercice fic.Exercice, body []byte) (interface{}, error) { func listExerciceFlags(exercice *fic.Exercice, body []byte) (interface{}, error) {
return exercice.GetFlagKeys() return exercice.GetFlagKeys()
} }
func listFlagChoices(flag fic.FlagKey, _ fic.Exercice, body []byte) (interface{}, error) { func listFlagChoices(flag *fic.FlagKey, _ *fic.Exercice, body []byte) (interface{}, error) {
return flag.GetChoices() return flag.GetChoices()
} }
func listExerciceQuiz(exercice fic.Exercice, body []byte) (interface{}, error) { func listExerciceQuiz(exercice *fic.Exercice, body []byte) (interface{}, error) {
return exercice.GetMCQ() return exercice.GetMCQ()
} }
func showExercice(exercice fic.Exercice, body []byte) (interface{}, error) { func showExercice(exercice *fic.Exercice, body []byte) (interface{}, error) {
return exercice, nil return exercice, nil
} }
func getExerciceHistory(exercice fic.Exercice, body []byte) (interface{}, error) { func getExerciceHistory(exercice *fic.Exercice, body []byte) (interface{}, error) {
return exercice.GetHistory() return exercice.GetHistory()
} }
@ -179,7 +179,7 @@ type exerciceStats struct {
MCQSolved []int64 `json:"mcq_solved"` MCQSolved []int64 `json:"mcq_solved"`
} }
func getExerciceStats(e fic.Exercice, body []byte) (interface{}, error) { func getExerciceStats(e *fic.Exercice, body []byte) (interface{}, error) {
return exerciceStats{ return exerciceStats{
TeamTries: e.TriedTeamCount(), TeamTries: e.TriedTeamCount(),
TotalTries: e.TriedCount(), TotalTries: e.TriedCount(),
@ -216,7 +216,7 @@ type uploadedExerciceHistory struct {
Coeff float32 Coeff float32
} }
func updateExerciceHistory(exercice fic.Exercice, body []byte) (interface{}, error) { func updateExerciceHistory(exercice *fic.Exercice, body []byte) (interface{}, error) {
var uh uploadedExerciceHistory var uh uploadedExerciceHistory
if err := json.Unmarshal(body, &uh); err != nil { if err := json.Unmarshal(body, &uh); err != nil {
return nil, err return nil, err
@ -225,7 +225,7 @@ func updateExerciceHistory(exercice fic.Exercice, body []byte) (interface{}, err
return exercice.UpdateHistoryItem(uh.Coeff, uh.IdTeam, uh.Kind, uh.Time, uh.Secondary) return exercice.UpdateHistoryItem(uh.Coeff, uh.IdTeam, uh.Kind, uh.Time, uh.Secondary)
} }
func delExerciceHistory(exercice fic.Exercice, body []byte) (interface{}, error) { func delExerciceHistory(exercice *fic.Exercice, body []byte) (interface{}, error) {
var uh uploadedExerciceHistory var uh uploadedExerciceHistory
if err := json.Unmarshal(body, &uh); err != nil { if err := json.Unmarshal(body, &uh); err != nil {
return nil, err return nil, err
@ -234,11 +234,11 @@ func delExerciceHistory(exercice fic.Exercice, body []byte) (interface{}, error)
return exercice.DelHistoryItem(uh.IdTeam, uh.Kind, uh.Time, uh.Secondary) return exercice.DelHistoryItem(uh.IdTeam, uh.Kind, uh.Time, uh.Secondary)
} }
func deleteExercice(exercice fic.Exercice, _ []byte) (interface{}, error) { func deleteExercice(exercice *fic.Exercice, _ []byte) (interface{}, error) {
return exercice.DeleteCascade() return exercice.DeleteCascade()
} }
func updateExercice(exercice fic.Exercice, body []byte) (interface{}, error) { func updateExercice(exercice *fic.Exercice, body []byte) (interface{}, error) {
var ue fic.Exercice var ue fic.Exercice
if err := json.Unmarshal(body, &ue); err != nil { if err := json.Unmarshal(body, &ue); err != nil {
return nil, err return nil, err
@ -257,7 +257,7 @@ func updateExercice(exercice fic.Exercice, body []byte) (interface{}, error) {
return ue, nil return ue, nil
} }
func partUpdateExercice(exercice fic.Exercice, body []byte) (interface{}, error) { func partUpdateExercice(exercice *fic.Exercice, body []byte) (interface{}, error) {
var ue fic.Exercice var ue fic.Exercice
if err := json.Unmarshal(body, &ue); err != nil { if err := json.Unmarshal(body, &ue); err != nil {
return nil, err return nil, err
@ -318,7 +318,7 @@ func partUpdateExercice(exercice fic.Exercice, body []byte) (interface{}, error)
return exercice, nil return exercice, nil
} }
func createExercice(theme fic.Theme, body []byte) (interface{}, error) { func createExercice(theme *fic.Theme, body []byte) (interface{}, error) {
// Create a new exercice // Create a new exercice
var ue fic.Exercice var ue fic.Exercice
if err := json.Unmarshal(body, &ue); err != nil { if err := json.Unmarshal(body, &ue); err != nil {
@ -334,7 +334,7 @@ func createExercice(theme fic.Theme, body []byte) (interface{}, error) {
if d, err := fic.GetExercice(*ue.Depend); err != nil { if d, err := fic.GetExercice(*ue.Depend); err != nil {
return nil, err return nil, err
} else { } else {
depend = &d depend = d
} }
} }
@ -349,7 +349,7 @@ type uploadedHint struct {
URI string URI string
} }
func createExerciceHint(exercice fic.Exercice, body []byte) (interface{}, error) { func createExerciceHint(exercice *fic.Exercice, body []byte) (interface{}, error) {
var uh uploadedHint var uh uploadedHint
if err := json.Unmarshal(body, &uh); err != nil { if err := json.Unmarshal(body, &uh); err != nil {
return nil, err return nil, err
@ -367,15 +367,15 @@ func createExerciceHint(exercice fic.Exercice, body []byte) (interface{}, error)
} }
} }
func showExerciceHint(hint fic.EHint, body []byte) (interface{}, error) { func showExerciceHint(hint *fic.EHint, body []byte) (interface{}, error) {
return hint, nil return hint, nil
} }
func showExerciceHintDeps(hint fic.EHint, body []byte) (interface{}, error) { func showExerciceHintDeps(hint *fic.EHint, body []byte) (interface{}, error) {
return loadFlags(hint.GetDepends) return loadFlags(hint.GetDepends)
} }
func updateExerciceHint(hint fic.EHint, body []byte) (interface{}, error) { func updateExerciceHint(hint *fic.EHint, body []byte) (interface{}, error) {
var uh fic.EHint var uh fic.EHint
if err := json.Unmarshal(body, &uh); err != nil { if err := json.Unmarshal(body, &uh); err != nil {
return nil, err return nil, err
@ -394,7 +394,7 @@ func updateExerciceHint(hint fic.EHint, body []byte) (interface{}, error) {
return uh, nil return uh, nil
} }
func deleteExerciceHint(hint fic.EHint, _ []byte) (interface{}, error) { func deleteExerciceHint(hint *fic.EHint, _ []byte) (interface{}, error) {
return hint.Delete() return hint.Delete()
} }
@ -410,7 +410,7 @@ type uploadedFlag struct {
ChoicesCost int64 `json:"choices_cost"` ChoicesCost int64 `json:"choices_cost"`
} }
func createExerciceFlag(exercice fic.Exercice, body []byte) (interface{}, error) { func createExerciceFlag(exercice *fic.Exercice, body []byte) (interface{}, error) {
var uk uploadedFlag var uk uploadedFlag
if err := json.Unmarshal(body, &uk); err != nil { if err := json.Unmarshal(body, &uk); err != nil {
return nil, err return nil, err
@ -428,15 +428,15 @@ func createExerciceFlag(exercice fic.Exercice, body []byte) (interface{}, error)
return exercice.AddRawFlagKey(uk.Label, uk.Type, uk.Placeholder, uk.IgnoreCase, uk.Multiline, vre, []byte(uk.Flag), uk.ChoicesCost) return exercice.AddRawFlagKey(uk.Label, uk.Type, uk.Placeholder, uk.IgnoreCase, uk.Multiline, vre, []byte(uk.Flag), uk.ChoicesCost)
} }
func showExerciceFlag(flag fic.FlagKey, _ fic.Exercice, body []byte) (interface{}, error) { func showExerciceFlag(flag *fic.FlagKey, _ *fic.Exercice, body []byte) (interface{}, error) {
return flag, nil return flag, nil
} }
func showExerciceFlagDeps(flag fic.FlagKey, _ fic.Exercice, body []byte) (interface{}, error) { func showExerciceFlagDeps(flag *fic.FlagKey, _ *fic.Exercice, body []byte) (interface{}, error) {
return loadFlags(flag.GetDepends) return loadFlags(flag.GetDepends)
} }
func tryExerciceFlag(flag fic.FlagKey, _ fic.Exercice, body []byte) (interface{}, error) { func tryExerciceFlag(flag *fic.FlagKey, _ *fic.Exercice, body []byte) (interface{}, error) {
var uk uploadedFlag var uk uploadedFlag
if err := json.Unmarshal(body, &uk); err != nil { if err := json.Unmarshal(body, &uk); err != nil {
return nil, err return nil, err
@ -453,7 +453,7 @@ func tryExerciceFlag(flag fic.FlagKey, _ fic.Exercice, body []byte) (interface{}
} }
} }
func updateExerciceFlag(flag fic.FlagKey, exercice fic.Exercice, body []byte) (interface{}, error) { func updateExerciceFlag(flag *fic.FlagKey, exercice *fic.Exercice, body []byte) (interface{}, error) {
var uk uploadedFlag var uk uploadedFlag
if err := json.Unmarshal(body, &uk); err != nil { if err := json.Unmarshal(body, &uk); err != nil {
return nil, err return nil, err
@ -492,11 +492,11 @@ func updateExerciceFlag(flag fic.FlagKey, exercice fic.Exercice, body []byte) (i
return flag, nil return flag, nil
} }
func deleteExerciceFlag(flag fic.FlagKey, _ fic.Exercice, _ []byte) (interface{}, error) { func deleteExerciceFlag(flag *fic.FlagKey, _ *fic.Exercice, _ []byte) (interface{}, error) {
return flag.Delete() return flag.Delete()
} }
func createFlagChoice(flag fic.FlagKey, exercice fic.Exercice, body []byte) (interface{}, error) { func createFlagChoice(flag *fic.FlagKey, exercice *fic.Exercice, body []byte) (interface{}, error) {
var uc fic.FlagChoice var uc fic.FlagChoice
if err := json.Unmarshal(body, &uc); err != nil { if err := json.Unmarshal(body, &uc); err != nil {
return nil, err return nil, err
@ -506,14 +506,14 @@ func createFlagChoice(flag fic.FlagKey, exercice fic.Exercice, body []byte) (int
uc.Label = uc.Value uc.Label = uc.Value
} }
return flag.AddChoice(uc) return flag.AddChoice(&uc)
} }
func showFlagChoice(choice fic.FlagChoice, _ fic.Exercice, body []byte) (interface{}, error) { func showFlagChoice(choice *fic.FlagChoice, _ *fic.Exercice, body []byte) (interface{}, error) {
return choice, nil return choice, nil
} }
func updateFlagChoice(choice fic.FlagChoice, _ fic.Exercice, body []byte) (interface{}, error) { func updateFlagChoice(choice *fic.FlagChoice, _ *fic.Exercice, body []byte) (interface{}, error) {
var uc fic.FlagChoice var uc fic.FlagChoice
if err := json.Unmarshal(body, &uc); err != nil { if err := json.Unmarshal(body, &uc); err != nil {
return nil, err return nil, err
@ -534,19 +534,19 @@ func updateFlagChoice(choice fic.FlagChoice, _ fic.Exercice, body []byte) (inter
return choice, nil return choice, nil
} }
func deleteFlagChoice(choice fic.FlagChoice, _ fic.Exercice, _ []byte) (interface{}, error) { func deleteFlagChoice(choice *fic.FlagChoice, _ *fic.Exercice, _ []byte) (interface{}, error) {
return choice.Delete() return choice.Delete()
} }
func showExerciceQuiz(quiz fic.MCQ, _ fic.Exercice, body []byte) (interface{}, error) { func showExerciceQuiz(quiz *fic.MCQ, _ *fic.Exercice, body []byte) (interface{}, error) {
return quiz, nil return quiz, nil
} }
func showExerciceQuizDeps(quiz fic.MCQ, _ fic.Exercice, body []byte) (interface{}, error) { func showExerciceQuizDeps(quiz *fic.MCQ, _ *fic.Exercice, body []byte) (interface{}, error) {
return loadFlags(quiz.GetDepends) return loadFlags(quiz.GetDepends)
} }
func updateExerciceQuiz(quiz fic.MCQ, exercice fic.Exercice, body []byte) (interface{}, error) { func updateExerciceQuiz(quiz *fic.MCQ, exercice *fic.Exercice, body []byte) (interface{}, error) {
var uq fic.MCQ var uq fic.MCQ
if err := json.Unmarshal(body, &uq); err != nil { if err := json.Unmarshal(body, &uq); err != nil {
return nil, err return nil, err
@ -604,7 +604,7 @@ func updateExerciceQuiz(quiz fic.MCQ, exercice fic.Exercice, body []byte) (inter
return quiz, nil return quiz, nil
} }
func deleteExerciceQuiz(quiz fic.MCQ, _ fic.Exercice, _ []byte) (interface{}, error) { func deleteExerciceQuiz(quiz *fic.MCQ, _ *fic.Exercice, _ []byte) (interface{}, error) {
for _, choice := range quiz.Entries { for _, choice := range quiz.Entries {
if _, err := choice.Delete(); err != nil { if _, err := choice.Delete(); err != nil {
return nil, err return nil, err
@ -614,11 +614,11 @@ func deleteExerciceQuiz(quiz fic.MCQ, _ fic.Exercice, _ []byte) (interface{}, er
return quiz.Delete() return quiz.Delete()
} }
func listExerciceTags(exercice fic.Exercice, _ []byte) (interface{}, error) { func listExerciceTags(exercice *fic.Exercice, _ []byte) (interface{}, error) {
return exercice.GetTags() return exercice.GetTags()
} }
func addExerciceTag(exercice fic.Exercice, body []byte) (interface{}, error) { func addExerciceTag(exercice *fic.Exercice, body []byte) (interface{}, error) {
var ut []string var ut []string
if err := json.Unmarshal(body, &ut); err != nil { if err := json.Unmarshal(body, &ut); err != nil {
return nil, err return nil, err
@ -634,7 +634,7 @@ func addExerciceTag(exercice fic.Exercice, body []byte) (interface{}, error) {
return ut, nil return ut, nil
} }
func updateExerciceTags(exercice fic.Exercice, body []byte) (interface{}, error) { func updateExerciceTags(exercice *fic.Exercice, body []byte) (interface{}, error) {
exercice.WipeTags() exercice.WipeTags()
return addExerciceTag(exercice, body) return addExerciceTag(exercice, body)
} }

View file

@ -36,17 +36,17 @@ func init() {
// Synchronize // Synchronize
router.POST("/api/sync/exercices/:eid/files", apiHandler(exerciceHandler( router.POST("/api/sync/exercices/:eid/files", apiHandler(exerciceHandler(
func(exercice fic.Exercice, _ []byte) (interface{}, error) { func(exercice *fic.Exercice, _ []byte) (interface{}, error) {
return sync.SyncExerciceFiles(sync.GlobalImporter, exercice), nil return sync.SyncExerciceFiles(sync.GlobalImporter, exercice), nil
}))) })))
} }
type APIFile struct { type APIFile struct {
fic.EFile *fic.EFile
Depends []fic.Flag `json:"depends,omitempty"` Depends []fic.Flag `json:"depends,omitempty"`
} }
func genFileList(in []fic.EFile, e error) (out []APIFile, err error) { func genFileList(in []*fic.EFile, e error) (out []APIFile, err error) {
if e != nil { if e != nil {
return nil, e return nil, e
} }
@ -61,14 +61,14 @@ func genFileList(in []fic.EFile, e error) (out []APIFile, err error) {
} }
for _, d := range deps { for _, d := range deps {
if k, ok := d.(fic.FlagKey); ok { if k, ok := d.(*fic.FlagKey); ok {
k, err = fic.GetFlagKey(k.Id) k, err = fic.GetFlagKey(k.Id)
if err != nil { if err != nil {
return return
} }
g.Depends = append(g.Depends, k) g.Depends = append(g.Depends, k)
} else if m, ok := d.(fic.MCQ); ok { } else if m, ok := d.(*fic.MCQ); ok {
m, err = fic.GetMCQ(m.Id) m, err = fic.GetMCQ(m.Id)
if err != nil { if err != nil {
return return
@ -91,7 +91,7 @@ func listFiles(_ httprouter.Params, body []byte) (interface{}, error) {
return genFileList(fic.GetFiles()) return genFileList(fic.GetFiles())
} }
func listExerciceFiles(exercice fic.Exercice, body []byte) (interface{}, error) { func listExerciceFiles(exercice *fic.Exercice, body []byte) (interface{}, error) {
return genFileList(exercice.GetFiles()) return genFileList(exercice.GetFiles())
} }
@ -99,7 +99,7 @@ func clearFiles(_ httprouter.Params, _ []byte) (interface{}, error) {
return fic.ClearFiles() return fic.ClearFiles()
} }
func showFile(file fic.EFile, _ []byte) (interface{}, error) { func showFile(file *fic.EFile, _ []byte) (interface{}, error) {
return file, nil return file, nil
} }
@ -108,7 +108,7 @@ type uploadedFile struct {
Digest string Digest string
} }
func createExerciceFile(exercice fic.Exercice, body []byte) (interface{}, error) { func createExerciceFile(exercice *fic.Exercice, body []byte) (interface{}, error) {
var uf uploadedFile var uf uploadedFile
if err := json.Unmarshal(body, &uf); err != nil { if err := json.Unmarshal(body, &uf); err != nil {
return nil, err return nil, err
@ -124,7 +124,7 @@ func createExerciceFile(exercice fic.Exercice, body []byte) (interface{}, error)
}) })
} }
func updateFile(file fic.EFile, body []byte) (interface{}, error) { func updateFile(file *fic.EFile, body []byte) (interface{}, error) {
var uf fic.EFile var uf fic.EFile
if err := json.Unmarshal(body, &uf); err != nil { if err := json.Unmarshal(body, &uf); err != nil {
return nil, err return nil, err
@ -139,14 +139,14 @@ func updateFile(file fic.EFile, body []byte) (interface{}, error) {
} }
} }
func deleteFile(file fic.EFile, _ []byte) (interface{}, error) { func deleteFile(file *fic.EFile, _ []byte) (interface{}, error) {
return file.Delete() return file.Delete()
} }
func deleteFileDep(file fic.EFile, depid int, _ []byte) (interface{}, error) { func deleteFileDep(file *fic.EFile, depid int, _ []byte) (interface{}, error) {
return true, file.DeleteDepend(fic.FlagKey{Id: depid}) return true, file.DeleteDepend(&fic.FlagKey{Id: depid})
} }
func checkFile(file fic.EFile, _ []byte) (interface{}, error) { func checkFile(file *fic.EFile, _ []byte) (interface{}, error) {
return true, file.CheckFileOnDisk() return true, file.CheckFileOnDisk()
} }

View file

@ -94,12 +94,12 @@ func teamPublicHandler(f func(*fic.Team, []byte) (interface{}, error)) func(http
} else if team, err := fic.GetTeam(tid); err != nil { } else if team, err := fic.GetTeam(tid); err != nil {
return nil, err return nil, err
} else { } else {
return f(&team, body) return f(team, body)
} }
} }
} }
func teamHandler(f func(fic.Team, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func teamHandler(f func(*fic.Team, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
if tid, err := strconv.ParseInt(string(ps.ByName("tid")), 10, 64); err != nil { if tid, err := strconv.ParseInt(string(ps.ByName("tid")), 10, 64); err != nil {
return nil, err return nil, err
@ -111,11 +111,11 @@ func teamHandler(f func(fic.Team, []byte) (interface{}, error)) func(httprouter.
} }
} }
func teamAssocHandler(f func(fic.Team, string, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func teamAssocHandler(f func(*fic.Team, string, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
var team fic.Team var team *fic.Team
teamHandler(func(tm fic.Team, _ []byte) (interface{}, error) { teamHandler(func(tm *fic.Team, _ []byte) (interface{}, error) {
team = tm team = tm
return nil, nil return nil, nil
})(ps, body) })(ps, body)
@ -124,7 +124,7 @@ func teamAssocHandler(f func(fic.Team, string, []byte) (interface{}, error)) fun
} }
} }
func themeHandler(f func(fic.Theme, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func themeHandler(f func(*fic.Theme, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
if thid, err := strconv.ParseInt(string(ps.ByName("thid")), 10, 64); err != nil { if thid, err := strconv.ParseInt(string(ps.ByName("thid")), 10, 64); err != nil {
return nil, err return nil, err
@ -136,7 +136,7 @@ func themeHandler(f func(fic.Theme, []byte) (interface{}, error)) func(httproute
} }
} }
func exerciceHandler(f func(fic.Exercice, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func exerciceHandler(f func(*fic.Exercice, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
if eid, err := strconv.ParseInt(string(ps.ByName("eid")), 10, 64); err != nil { if eid, err := strconv.ParseInt(string(ps.ByName("eid")), 10, 64); err != nil {
return nil, err return nil, err
@ -148,17 +148,17 @@ func exerciceHandler(f func(fic.Exercice, []byte) (interface{}, error)) func(htt
} }
} }
func themedExerciceHandler(f func(fic.Theme, fic.Exercice, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func themedExerciceHandler(f func(*fic.Theme, *fic.Exercice, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
var theme fic.Theme var theme *fic.Theme
var exercice fic.Exercice var exercice *fic.Exercice
themeHandler(func(th fic.Theme, _ []byte) (interface{}, error) { themeHandler(func(th *fic.Theme, _ []byte) (interface{}, error) {
theme = th theme = th
return nil, nil return nil, nil
})(ps, body) })(ps, body)
exerciceHandler(func(ex fic.Exercice, _ []byte) (interface{}, error) { exerciceHandler(func(ex *fic.Exercice, _ []byte) (interface{}, error) {
exercice = ex exercice = ex
return nil, nil return nil, nil
})(ps, body) })(ps, body)
@ -167,7 +167,7 @@ func themedExerciceHandler(f func(fic.Theme, fic.Exercice, []byte) (interface{},
} }
} }
func hintHandler(f func(fic.EHint, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func hintHandler(f func(*fic.EHint, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
if hid, err := strconv.ParseInt(string(ps.ByName("hid")), 10, 64); err != nil { if hid, err := strconv.ParseInt(string(ps.ByName("hid")), 10, 64); err != nil {
return nil, err return nil, err
@ -179,10 +179,10 @@ func hintHandler(f func(fic.EHint, []byte) (interface{}, error)) func(httprouter
} }
} }
func flagKeyHandler(f func(fic.FlagKey, fic.Exercice, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func flagKeyHandler(f func(*fic.FlagKey, *fic.Exercice, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
var exercice fic.Exercice var exercice *fic.Exercice
exerciceHandler(func(ex fic.Exercice, _ []byte) (interface{}, error) { exerciceHandler(func(ex *fic.Exercice, _ []byte) (interface{}, error) {
exercice = ex exercice = ex
return nil, nil return nil, nil
})(ps, body) })(ps, body)
@ -202,11 +202,11 @@ func flagKeyHandler(f func(fic.FlagKey, fic.Exercice, []byte) (interface{}, erro
} }
} }
func choiceHandler(f func(fic.FlagChoice, fic.Exercice, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func choiceHandler(f func(*fic.FlagChoice, *fic.Exercice, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
var exercice fic.Exercice var exercice *fic.Exercice
var flag fic.FlagKey var flag *fic.FlagKey
flagKeyHandler(func(fl fic.FlagKey, ex fic.Exercice, _ []byte) (interface{}, error) { flagKeyHandler(func(fl *fic.FlagKey, ex *fic.Exercice, _ []byte) (interface{}, error) {
exercice = ex exercice = ex
flag = fl flag = fl
return nil, nil return nil, nil
@ -222,10 +222,10 @@ func choiceHandler(f func(fic.FlagChoice, fic.Exercice, []byte) (interface{}, er
} }
} }
func quizHandler(f func(fic.MCQ, fic.Exercice, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func quizHandler(f func(*fic.MCQ, *fic.Exercice, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
var exercice fic.Exercice var exercice *fic.Exercice
exerciceHandler(func(ex fic.Exercice, _ []byte) (interface{}, error) { exerciceHandler(func(ex *fic.Exercice, _ []byte) (interface{}, error) {
exercice = ex exercice = ex
return nil, nil return nil, nil
})(ps, body) })(ps, body)
@ -245,10 +245,10 @@ func quizHandler(f func(fic.MCQ, fic.Exercice, []byte) (interface{}, error)) fun
} }
} }
func exerciceFileHandler(f func(fic.EFile, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func exerciceFileHandler(f func(*fic.EFile, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
var exercice fic.Exercice var exercice *fic.Exercice
exerciceHandler(func(ex fic.Exercice, _ []byte) (interface{}, error) { exerciceHandler(func(ex *fic.Exercice, _ []byte) (interface{}, error) {
exercice = ex exercice = ex
return nil, nil return nil, nil
})(ps, body) })(ps, body)
@ -268,7 +268,7 @@ func exerciceFileHandler(f func(fic.EFile, []byte) (interface{}, error)) func(ht
} }
} }
func eventHandler(f func(fic.Event, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func eventHandler(f func(*fic.Event, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
if evid, err := strconv.ParseInt(string(ps.ByName("evid")), 10, 64); err != nil { if evid, err := strconv.ParseInt(string(ps.ByName("evid")), 10, 64); err != nil {
return nil, err return nil, err
@ -280,7 +280,7 @@ func eventHandler(f func(fic.Event, []byte) (interface{}, error)) func(httproute
} }
} }
func claimHandler(f func(fic.Claim, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func claimHandler(f func(*fic.Claim, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
if cid, err := strconv.ParseInt(string(ps.ByName("cid")), 10, 64); err != nil { if cid, err := strconv.ParseInt(string(ps.ByName("cid")), 10, 64); err != nil {
return nil, fmt.Errorf("Invalid claim id: %w", err) return nil, fmt.Errorf("Invalid claim id: %w", err)
@ -292,7 +292,7 @@ func claimHandler(f func(fic.Claim, []byte) (interface{}, error)) func(httproute
} }
} }
func claimAssigneeHandler(f func(fic.ClaimAssignee, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func claimAssigneeHandler(f func(*fic.ClaimAssignee, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
if aid, err := strconv.ParseInt(string(ps.ByName("aid")), 10, 64); err != nil { if aid, err := strconv.ParseInt(string(ps.ByName("aid")), 10, 64); err != nil {
return nil, err return nil, err
@ -304,7 +304,7 @@ func claimAssigneeHandler(f func(fic.ClaimAssignee, []byte) (interface{}, error)
} }
} }
func fileHandler(f func(fic.EFile, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func fileHandler(f func(*fic.EFile, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
if fileid, err := strconv.ParseInt(string(ps.ByName("fileid")), 10, 64); err != nil { if fileid, err := strconv.ParseInt(string(ps.ByName("fileid")), 10, 64); err != nil {
return nil, err return nil, err
@ -316,19 +316,19 @@ func fileHandler(f func(fic.EFile, []byte) (interface{}, error)) func(httprouter
} }
} }
func fileDependancyHandler(f func(fic.EFile, int, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func fileDependancyHandler(f func(*fic.EFile, int, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
if depid, err := strconv.ParseInt(string(ps.ByName("depid")), 10, 64); err != nil { if depid, err := strconv.ParseInt(string(ps.ByName("depid")), 10, 64); err != nil {
return nil, err return nil, err
} else { } else {
return fileHandler(func(file fic.EFile, b []byte) (interface{}, error) { return fileHandler(func(file *fic.EFile, b []byte) (interface{}, error) {
return f(file, int(depid), b) return f(file, int(depid), b)
})(ps, body) })(ps, body)
} }
} }
} }
func certificateHandler(f func(fic.Certificate, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func certificateHandler(f func(*fic.Certificate, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
var cid uint64 var cid uint64
var err error var err error

View file

@ -25,11 +25,11 @@ func init() {
} }
})) }))
router.GET("/api/teams/:tid/password", apiHandler(teamHandler( router.GET("/api/teams/:tid/password", apiHandler(teamHandler(
func(team fic.Team, _ []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
return team.Password, nil return team.Password, nil
}))) })))
router.POST("/api/teams/:tid/password", apiHandler(teamHandler( router.POST("/api/teams/:tid/password", apiHandler(teamHandler(
func(team fic.Team, _ []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
if passwd, err := fic.GeneratePassword(); err != nil { if passwd, err := fic.GeneratePassword(); err != nil {
return nil, err return nil, err
} else { } else {
@ -145,7 +145,7 @@ type dexConfigClient struct {
type dexConfig struct { type dexConfig struct {
Clients []dexConfigClient Clients []dexConfigClient
Teams []fic.Team Teams []*fic.Team
} }
func genDexConfig() ([]byte, error) { func genDexConfig() ([]byte, error) {

View file

@ -15,7 +15,7 @@ func init() {
router.POST("/api/qa/:qid/comments", apiHandler(qaHandler(importQAComment))) router.POST("/api/qa/:qid/comments", apiHandler(qaHandler(importQAComment)))
} }
func qaHandler(f func(fic.QAQuery, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { func qaHandler(f func(*fic.QAQuery, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) {
if qid, err := strconv.ParseInt(string(ps.ByName("qid")), 10, 64); err != nil { if qid, err := strconv.ParseInt(string(ps.ByName("qid")), 10, 64); err != nil {
return nil, err return nil, err
@ -34,7 +34,7 @@ func importExerciceQA(_ httprouter.Params, body []byte) (interface{}, error) {
return nil, err return nil, err
} }
var exercice fic.Exercice var exercice *fic.Exercice
var err error var err error
if uq.IdExercice == 0 { if uq.IdExercice == 0 {
return nil, errors.New("id_exercice not filled") return nil, errors.New("id_exercice not filled")
@ -62,7 +62,7 @@ func importExerciceQA(_ httprouter.Params, body []byte) (interface{}, error) {
} }
} }
func importQAComment(query fic.QAQuery, body []byte) (interface{}, error) { func importQAComment(query *fic.QAQuery, body []byte) (interface{}, error) {
// Create a new query // Create a new query
var uc fic.QAComment var uc fic.QAComment
if err := json.Unmarshal(body, &uc); err != nil { if err := json.Unmarshal(body, &uc); err != nil {

View file

@ -48,17 +48,17 @@ func init() {
router.POST("/api/teams/", apiHandler(createTeam)) router.POST("/api/teams/", apiHandler(createTeam))
router.GET("/api/teams/:tid/", apiHandler(teamHandler( router.GET("/api/teams/:tid/", apiHandler(teamHandler(
func(team fic.Team, _ []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
return team, nil return team, nil
}))) })))
router.PUT("/api/teams/:tid/", apiHandler(teamHandler(updateTeam))) router.PUT("/api/teams/:tid/", apiHandler(teamHandler(updateTeam)))
router.POST("/api/teams/:tid/", apiHandler(teamHandler(addTeamMember))) router.POST("/api/teams/:tid/", apiHandler(teamHandler(addTeamMember)))
router.DELETE("/api/teams/:tid/", apiHandler(teamHandler( router.DELETE("/api/teams/:tid/", apiHandler(teamHandler(
func(team fic.Team, _ []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
return team.Delete() return team.Delete()
}))) })))
router.GET("/api/teams/:tid/score-grid.json", apiHandler(teamHandler( router.GET("/api/teams/:tid/score-grid.json", apiHandler(teamHandler(
func(team fic.Team, _ []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
return team.ScoreGrid() return team.ScoreGrid()
}))) })))
router.GET("/api/teams/:tid/my.json", apiHandler(teamPublicHandler( router.GET("/api/teams/:tid/my.json", apiHandler(teamPublicHandler(
@ -91,7 +91,7 @@ func init() {
return fic.GetTries(team, nil) return fic.GetTries(team, nil)
}))) })))
router.GET("/api/teams/:tid/members", apiHandler(teamHandler( router.GET("/api/teams/:tid/members", apiHandler(teamHandler(
func(team fic.Team, _ []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
return team.GetMembers() return team.GetMembers()
}))) })))
router.POST("/api/teams/:tid/members", apiHandler(teamHandler(addTeamMember))) router.POST("/api/teams/:tid/members", apiHandler(teamHandler(addTeamMember)))
@ -163,7 +163,7 @@ func createTeam(_ httprouter.Params, body []byte) (interface{}, error) {
return fic.CreateTeam(strings.TrimSpace(ut.Name), ut.Color, ut.ExternalId) return fic.CreateTeam(strings.TrimSpace(ut.Name), ut.Color, ut.ExternalId)
} }
func updateTeam(team fic.Team, body []byte) (interface{}, error) { func updateTeam(team *fic.Team, body []byte) (interface{}, error) {
var ut fic.Team var ut fic.Team
if err := json.Unmarshal(body, &ut); err != nil { if err := json.Unmarshal(body, &ut); err != nil {
return nil, err return nil, err
@ -229,7 +229,7 @@ func enableAllTeams(_ httprouter.Params, _ []byte) (interface{}, error) {
} }
} }
func addTeamMember(team fic.Team, body []byte) (interface{}, error) { func addTeamMember(team *fic.Team, body []byte) (interface{}, error) {
var members []fic.Member var members []fic.Member
if err := json.Unmarshal(body, &members); err != nil { if err := json.Unmarshal(body, &members); err != nil {
return nil, err return nil, err
@ -242,7 +242,7 @@ func addTeamMember(team fic.Team, body []byte) (interface{}, error) {
return team.GetMembers() return team.GetMembers()
} }
func setTeamMember(team fic.Team, body []byte) (interface{}, error) { func setTeamMember(team *fic.Team, body []byte) (interface{}, error) {
var members []fic.Member var members []fic.Member
if err := json.Unmarshal(body, &members); err != nil { if err := json.Unmarshal(body, &members); err != nil {
return nil, err return nil, err

View file

@ -72,7 +72,7 @@ func init() {
return sync.SyncDeep(sync.GlobalImporter), nil return sync.SyncDeep(sync.GlobalImporter), nil
})) }))
router.POST("/api/sync/deep/:thid", apiHandler(themeHandler( router.POST("/api/sync/deep/:thid", apiHandler(themeHandler(
func(theme fic.Theme, _ []byte) (interface{}, error) { func(theme *fic.Theme, _ []byte) (interface{}, error) {
st := sync.SyncThemeDeep(sync.GlobalImporter, theme, 0, 250) st := sync.SyncThemeDeep(sync.GlobalImporter, theme, 0, 250)
sync.EditDeepReport(map[string][]string{theme.Name: st}, false) sync.EditDeepReport(map[string][]string{theme.Name: st}, false)
sync.DeepSyncProgress = 255 sync.DeepSyncProgress = 255
@ -126,27 +126,27 @@ func init() {
return sync.SyncThemes(sync.GlobalImporter), nil return sync.SyncThemes(sync.GlobalImporter), nil
})) }))
router.POST("/api/sync/themes/:thid/exercices", apiHandler(themeHandler( router.POST("/api/sync/themes/:thid/exercices", apiHandler(themeHandler(
func(theme fic.Theme, _ []byte) (interface{}, error) { func(theme *fic.Theme, _ []byte) (interface{}, error) {
return sync.SyncExercices(sync.GlobalImporter, theme), nil return sync.SyncExercices(sync.GlobalImporter, theme), nil
}))) })))
router.POST("/api/sync/themes/:thid/exercices/:eid/files", apiHandler(exerciceHandler( router.POST("/api/sync/themes/:thid/exercices/:eid/files", apiHandler(exerciceHandler(
func(exercice fic.Exercice, _ []byte) (interface{}, error) { func(exercice *fic.Exercice, _ []byte) (interface{}, error) {
return sync.SyncExerciceFiles(sync.GlobalImporter, exercice), nil return sync.SyncExerciceFiles(sync.GlobalImporter, exercice), nil
}))) })))
router.POST("/api/sync/themes/:thid/exercices/:eid/hints", apiHandler(exerciceHandler( router.POST("/api/sync/themes/:thid/exercices/:eid/hints", apiHandler(exerciceHandler(
func(exercice fic.Exercice, _ []byte) (interface{}, error) { func(exercice *fic.Exercice, _ []byte) (interface{}, error) {
_, errs := sync.SyncExerciceHints(sync.GlobalImporter, exercice, sync.ExerciceFlagsMap(sync.GlobalImporter, exercice)) _, errs := sync.SyncExerciceHints(sync.GlobalImporter, exercice, sync.ExerciceFlagsMap(sync.GlobalImporter, exercice))
return errs, nil return errs, nil
}))) })))
router.POST("/api/sync/themes/:thid/exercices/:eid/keys", apiHandler(exerciceHandler( router.POST("/api/sync/themes/:thid/exercices/:eid/keys", apiHandler(exerciceHandler(
func(exercice fic.Exercice, _ []byte) (interface{}, error) { func(exercice *fic.Exercice, _ []byte) (interface{}, error) {
_, errs := sync.SyncExerciceFlags(sync.GlobalImporter, exercice) _, errs := sync.SyncExerciceFlags(sync.GlobalImporter, exercice)
_, herrs := sync.SyncExerciceHints(sync.GlobalImporter, exercice, sync.ExerciceFlagsMap(sync.GlobalImporter, exercice)) _, herrs := sync.SyncExerciceHints(sync.GlobalImporter, exercice, sync.ExerciceFlagsMap(sync.GlobalImporter, exercice))
return append(errs, herrs...), nil return append(errs, herrs...), nil
}))) })))
router.POST("/api/sync/themes/:thid/fixurlid", apiHandler(themeHandler( router.POST("/api/sync/themes/:thid/fixurlid", apiHandler(themeHandler(
func(theme fic.Theme, _ []byte) (interface{}, error) { func(theme *fic.Theme, _ []byte) (interface{}, error) {
if theme.FixURLId() { if theme.FixURLId() {
return theme.Update() return theme.Update()
} }
@ -190,13 +190,13 @@ func bindingFiles(_ httprouter.Params, body []byte) (interface{}, error) {
} }
} }
func getExercice(args []string) (fic.Exercice, error) { func getExercice(args []string) (*fic.Exercice, error) {
if tid, err := strconv.ParseInt(string(args[0]), 10, 64); err != nil { if tid, err := strconv.ParseInt(string(args[0]), 10, 64); err != nil {
return fic.Exercice{}, err return nil, err
} else if theme, err := fic.GetTheme(tid); err != nil { } else if theme, err := fic.GetTheme(tid); err != nil {
return fic.Exercice{}, err return nil, err
} else if eid, err := strconv.Atoi(string(args[1])); err != nil { } else if eid, err := strconv.Atoi(string(args[1])); err != nil {
return fic.Exercice{}, err return nil, err
} else { } else {
return theme.GetExercice(eid) return theme.GetExercice(eid)
} }
@ -210,15 +210,15 @@ func exportThemes(_ httprouter.Params, _ []byte) (interface{}, error) {
return fic.ExportThemes() return fic.ExportThemes()
} }
func showTheme(theme fic.Theme, _ []byte) (interface{}, error) { func showTheme(theme *fic.Theme, _ []byte) (interface{}, error) {
return theme, nil return theme, nil
} }
func listThemedExercices(theme fic.Theme, _ []byte) (interface{}, error) { func listThemedExercices(theme *fic.Theme, _ []byte) (interface{}, error) {
return theme.GetExercices() return theme.GetExercices()
} }
func showThemedExercice(theme fic.Theme, exercice fic.Exercice, body []byte) (interface{}, error) { func showThemedExercice(theme *fic.Theme, exercice fic.Exercice, body []byte) (interface{}, error) {
return exercice, nil return exercice, nil
} }
@ -232,10 +232,10 @@ func createTheme(_ httprouter.Params, body []byte) (interface{}, error) {
return nil, errors.New("Theme's name not filled") return nil, errors.New("Theme's name not filled")
} }
return fic.CreateTheme(ut) return fic.CreateTheme(&ut)
} }
func updateTheme(theme fic.Theme, body []byte) (interface{}, error) { func updateTheme(theme *fic.Theme, body []byte) (interface{}, error) {
var ut fic.Theme var ut fic.Theme
if err := json.Unmarshal(body, &ut); err != nil { if err := json.Unmarshal(body, &ut); err != nil {
return nil, err return nil, err
@ -254,11 +254,11 @@ func updateTheme(theme fic.Theme, body []byte) (interface{}, error) {
} }
} }
func deleteTheme(theme fic.Theme, _ []byte) (interface{}, error) { func deleteTheme(theme *fic.Theme, _ []byte) (interface{}, error) {
return theme.Delete() return theme.Delete()
} }
func getThemedExercicesStats(theme fic.Theme, body []byte) (interface{}, error) { func getThemedExercicesStats(theme *fic.Theme, body []byte) (interface{}, error) {
if exercices, err := theme.GetExercices(); err != nil { if exercices, err := theme.GetExercices(); err != nil {
return nil, err return nil, err
} else { } else {

View file

@ -83,7 +83,7 @@ func parseExerciceParams(i Importer, exPath string) (p ExerciceParams, md toml.M
} }
// getExerciceParams returns normalized // getExerciceParams returns normalized
func getExerciceParams(i Importer, exercice fic.Exercice) (params ExerciceParams, errs []string) { func getExerciceParams(i Importer, exercice *fic.Exercice) (params ExerciceParams, errs []string) {
var err error var err error
if params, _, err = parseExerciceParams(i, exercice.Path); err != nil { if params, _, err = parseExerciceParams(i, exercice.Path); err != nil {
errs = append(errs, fmt.Sprintf("%q: challenge.txt: %s", path.Base(exercice.Path), err)) errs = append(errs, fmt.Sprintf("%q: challenge.txt: %s", path.Base(exercice.Path), err))

View file

@ -13,7 +13,7 @@ import (
"srs.epita.fr/fic-server/libfic" "srs.epita.fr/fic-server/libfic"
) )
func BuildFilesListInto(i Importer, exercice fic.Exercice, into string) (files []string, digests map[string][]byte, errs []string) { func BuildFilesListInto(i Importer, exercice *fic.Exercice, into string) (files []string, digests map[string][]byte, errs []string) {
// If no files directory, don't display error // If no files directory, don't display error
if !i.exists(path.Join(exercice.Path, into)) { if !i.exists(path.Join(exercice.Path, into)) {
return return
@ -72,7 +72,7 @@ func BuildFilesListInto(i Importer, exercice fic.Exercice, into string) (files [
} }
// CheckExerciceFilesPresence limits remote checks to presence, don't get it to check digest. // CheckExerciceFilesPresence limits remote checks to presence, don't get it to check digest.
func CheckExerciceFilesPresence(i Importer, exercice fic.Exercice) (files []string, errs []string) { func CheckExerciceFilesPresence(i Importer, exercice *fic.Exercice) (files []string, errs []string) {
flist, digests, berrs := BuildFilesListInto(i, exercice, "files") flist, digests, berrs := BuildFilesListInto(i, exercice, "files")
errs = append(errs, berrs...) errs = append(errs, berrs...)
@ -96,7 +96,7 @@ func CheckExerciceFilesPresence(i Importer, exercice fic.Exercice) (files []stri
} }
// CheckExerciceFiles checks that remote files have the right digest. // CheckExerciceFiles checks that remote files have the right digest.
func CheckExerciceFiles(i Importer, exercice fic.Exercice) (files []string, errs []string) { func CheckExerciceFiles(i Importer, exercice *fic.Exercice) (files []string, errs []string) {
flist, digests, berrs := BuildFilesListInto(i, exercice, "files") flist, digests, berrs := BuildFilesListInto(i, exercice, "files")
errs = append(errs, berrs...) errs = append(errs, berrs...)
@ -117,7 +117,7 @@ func CheckExerciceFiles(i Importer, exercice fic.Exercice) (files []string, errs
// SyncExerciceFiles reads the content of files/ directory and import it as EFile for the given challenge. // SyncExerciceFiles reads the content of files/ directory and import it as EFile for the given challenge.
// It takes care of DIGESTS.txt and ensure imported files match. // It takes care of DIGESTS.txt and ensure imported files match.
func SyncExerciceFiles(i Importer, exercice fic.Exercice) (errs []string) { func SyncExerciceFiles(i Importer, exercice *fic.Exercice) (errs []string) {
if _, err := exercice.WipeFiles(); err != nil { if _, err := exercice.WipeFiles(); err != nil {
errs = append(errs, err.Error()) errs = append(errs, err.Error())
} }
@ -138,7 +138,7 @@ func SyncExerciceFiles(i Importer, exercice fic.Exercice) (errs []string) {
}); err != nil { }); err != nil {
errs = append(errs, fmt.Sprintf("%q: unable to import file %q: %s", path.Base(exercice.Path), fname, err)) errs = append(errs, fmt.Sprintf("%q: unable to import file %q: %s", path.Base(exercice.Path), fname, err))
continue continue
} else if f.(fic.EFile).Size == 0 { } else if f.(*fic.EFile).Size == 0 {
errs = append(errs, fmt.Sprintf("%q: WARNING imported file %q is empty!", path.Base(exercice.Path), fname)) errs = append(errs, fmt.Sprintf("%q: WARNING imported file %q is empty!", path.Base(exercice.Path), fname))
} }
} }
@ -149,15 +149,15 @@ func SyncExerciceFiles(i Importer, exercice fic.Exercice) (errs []string) {
func ApiGetRemoteExerciceFiles(ps httprouter.Params, _ []byte) (interface{}, error) { func ApiGetRemoteExerciceFiles(ps httprouter.Params, _ []byte) (interface{}, error) {
theme, errs := BuildTheme(GlobalImporter, ps.ByName("thid")) theme, errs := BuildTheme(GlobalImporter, ps.ByName("thid"))
if theme != nil { if theme != nil {
exercice, _, _, _, errs := BuildExercice(GlobalImporter, *theme, path.Join(theme.Path, ps.ByName("exid")), nil) exercice, _, _, _, errs := BuildExercice(GlobalImporter, theme, path.Join(theme.Path, ps.ByName("exid")), nil)
if exercice != nil { if exercice != nil {
files, digests, errs := BuildFilesListInto(GlobalImporter, *exercice, "files") files, digests, errs := BuildFilesListInto(GlobalImporter, exercice, "files")
if files != nil { if files != nil {
var ret []fic.EFile var ret []*fic.EFile
for _, fname := range files { for _, fname := range files {
fPath := path.Join(exercice.Path, "files", fname) fPath := path.Join(exercice.Path, "files", fname)
fSize, _ := getFileSize(GlobalImporter, fPath) fSize, _ := getFileSize(GlobalImporter, fPath)
ret = append(ret, fic.EFile{ ret = append(ret, &fic.EFile{
Path: fPath, Path: fPath,
Name: fname, Name: fname,
Checksum: digests[fname], Checksum: digests[fname],

View file

@ -22,7 +22,7 @@ type importHint struct {
FlagsDeps []int64 FlagsDeps []int64
} }
func buildExerciceHints(i Importer, exercice fic.Exercice) (hints []importHint, errs []string) { func buildExerciceHints(i Importer, exercice *fic.Exercice) (hints []importHint, errs []string) {
params, _, err := parseExerciceParams(i, exercice.Path) params, _, err := parseExerciceParams(i, exercice.Path)
if err != nil { if err != nil {
errs = append(errs, fmt.Sprintf("%q: challenge.txt: %s", path.Base(exercice.Path), err)) errs = append(errs, fmt.Sprintf("%q: challenge.txt: %s", path.Base(exercice.Path), err))
@ -102,19 +102,19 @@ func buildExerciceHints(i Importer, exercice fic.Exercice) (hints []importHint,
} }
// CheckExerciceHints checks if all hints are corrects.. // CheckExerciceHints checks if all hints are corrects..
func CheckExerciceHints(i Importer, exercice fic.Exercice) ([]importHint, []string) { func CheckExerciceHints(i Importer, exercice *fic.Exercice) ([]importHint, []string) {
return buildExerciceHints(i, exercice) return buildExerciceHints(i, exercice)
} }
// SyncExerciceHints reads the content of hints/ directories and import it as EHint for the given challenge. // SyncExerciceHints reads the content of hints/ directories and import it as EHint for the given challenge.
func SyncExerciceHints(i Importer, exercice fic.Exercice, flagsBindings map[int64]fic.Flag) (hintsBindings map[int]fic.EHint, errs []string) { func SyncExerciceHints(i Importer, exercice *fic.Exercice, flagsBindings map[int64]fic.Flag) (hintsBindings map[int]*fic.EHint, errs []string) {
if _, err := exercice.WipeHints(); err != nil { if _, err := exercice.WipeHints(); err != nil {
errs = append(errs, err.Error()) errs = append(errs, err.Error())
} else { } else {
hints, berrs := buildExerciceHints(i, exercice) hints, berrs := buildExerciceHints(i, exercice)
errs = append(errs, berrs...) errs = append(errs, berrs...)
hintsBindings = map[int]fic.EHint{} hintsBindings = map[int]*fic.EHint{}
for _, hint := range hints { for _, hint := range hints {
// Import hint // Import hint
@ -143,9 +143,9 @@ func SyncExerciceHints(i Importer, exercice fic.Exercice, flagsBindings map[int6
func ApiGetRemoteExerciceHints(ps httprouter.Params, _ []byte) (interface{}, error) { func ApiGetRemoteExerciceHints(ps httprouter.Params, _ []byte) (interface{}, error) {
theme, errs := BuildTheme(GlobalImporter, ps.ByName("thid")) theme, errs := BuildTheme(GlobalImporter, ps.ByName("thid"))
if theme != nil { if theme != nil {
exercice, _, _, _, errs := BuildExercice(GlobalImporter, *theme, path.Join(theme.Path, ps.ByName("exid")), nil) exercice, _, _, _, errs := BuildExercice(GlobalImporter, theme, path.Join(theme.Path, ps.ByName("exid")), nil)
if exercice != nil { if exercice != nil {
hints, errs := CheckExerciceHints(GlobalImporter, *exercice) hints, errs := CheckExerciceHints(GlobalImporter, exercice)
if hints != nil { if hints != nil {
return hints, nil return hints, nil
} else { } else {

View file

@ -95,7 +95,7 @@ func getRawKey(input interface{}, validatorRe string, ordered bool, showLines bo
return return
} }
func buildKeyFlag(exercice fic.Exercice, flag ExerciceFlag, flagline int, defaultLabel string) (f *fic.Flag, choices []fic.FlagChoice, errs []string) { func buildKeyFlag(exercice *fic.Exercice, flag ExerciceFlag, flagline int, defaultLabel string) (f *fic.Flag, choices []*fic.FlagChoice, errs []string) {
if len(flag.Label) == 0 { if len(flag.Label) == 0 {
flag.Label = defaultLabel flag.Label = defaultLabel
} }
@ -129,7 +129,7 @@ func buildKeyFlag(exercice fic.Exercice, flag ExerciceFlag, flagline int, defaul
errs = append(errs, fmt.Sprintf("%q: flag #%d: %s", path.Base(exercice.Path), flagline, err.Error())) errs = append(errs, fmt.Sprintf("%q: flag #%d: %s", path.Base(exercice.Path), flagline, err.Error()))
return return
} }
fl := fic.Flag(fic.FlagKey{ fl := fic.Flag(&fic.FlagKey{
Type: flag.Type, Type: flag.Type,
IdExercice: exercice.Id, IdExercice: exercice.Id,
Order: int8(flagline), Order: int8(flagline),
@ -173,7 +173,7 @@ func buildKeyFlag(exercice fic.Exercice, flag ExerciceFlag, flagline int, defaul
val = strings.ToLower(val) val = strings.ToLower(val)
} }
choices = append(choices, fic.FlagChoice{ choices = append(choices, &fic.FlagChoice{
Label: choice.Label, Label: choice.Label,
Value: val, Value: val,
}) })
@ -196,7 +196,7 @@ func buildKeyFlag(exercice fic.Exercice, flag ExerciceFlag, flagline int, defaul
type importFlag struct { type importFlag struct {
Line int Line int
Flag fic.Flag Flag fic.Flag
Choices []fic.FlagChoice Choices []*fic.FlagChoice
FilesDeps []string FilesDeps []string
FlagsDeps []int64 FlagsDeps []int64
} }
@ -216,7 +216,7 @@ func iface2Number(input interface{}, output *string) error {
} }
// buildExerciceFlags read challenge.txt and extract all flags. // buildExerciceFlags read challenge.txt and extract all flags.
func buildExerciceFlag(i Importer, exercice fic.Exercice, flag ExerciceFlag, nline int) (ret []importFlag, errs []string) { func buildExerciceFlag(i Importer, exercice *fic.Exercice, flag ExerciceFlag, nline int) (ret []importFlag, errs []string) {
switch strings.ToLower(flag.Type) { switch strings.ToLower(flag.Type) {
case "": case "":
flag.Type = "key" flag.Type = "key"
@ -281,7 +281,7 @@ func buildExerciceFlag(i Importer, exercice fic.Exercice, flag ExerciceFlag, nli
IdExercice: exercice.Id, IdExercice: exercice.Id,
Order: int8(nline + 1), Order: int8(nline + 1),
Title: flag.Label, Title: flag.Label,
Entries: []fic.MCQ_entry{}, Entries: []*fic.MCQ_entry{},
} }
hasOne := false hasOne := false
@ -317,7 +317,7 @@ func buildExerciceFlag(i Importer, exercice fic.Exercice, flag ExerciceFlag, nli
continue continue
} }
addedFlag.Entries = append(addedFlag.Entries, fic.MCQ_entry{ addedFlag.Entries = append(addedFlag.Entries, &fic.MCQ_entry{
Label: choice.Label, Label: choice.Label,
Response: val, Response: val,
}) })
@ -339,14 +339,14 @@ func buildExerciceFlag(i Importer, exercice fic.Exercice, flag ExerciceFlag, nli
ret = append(ret, importFlag{ ret = append(ret, importFlag{
Line: nline + 1, Line: nline + 1,
Flag: addedFlag, Flag: &addedFlag,
}) })
} }
return return
} }
// buildExerciceFlags read challenge.txt and extract all flags. // buildExerciceFlags read challenge.txt and extract all flags.
func buildExerciceFlags(i Importer, exercice fic.Exercice) (flags map[int64]importFlag, flagids []int64, errs []string) { func buildExerciceFlags(i Importer, exercice *fic.Exercice) (flags map[int64]importFlag, flagids []int64, errs []string) {
params, gerrs := getExerciceParams(i, exercice) params, gerrs := getExerciceParams(i, exercice)
if len(gerrs) > 0 { if len(gerrs) > 0 {
return flags, flagids, gerrs return flags, flagids, gerrs
@ -397,7 +397,7 @@ func buildExerciceFlags(i Importer, exercice fic.Exercice) (flags map[int64]impo
} }
// 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) (rf []fic.Flag, errs []string) { func CheckExerciceFlags(i Importer, exercice *fic.Exercice, files []string) (rf []fic.Flag, errs []string) {
flags, flagsids, berrs := buildExerciceFlags(i, exercice) flags, flagsids, berrs := buildExerciceFlags(i, exercice)
errs = append(errs, berrs...) errs = append(errs, berrs...)
@ -432,7 +432,7 @@ func CheckExerciceFlags(i Importer, exercice fic.Exercice, files []string) (rf [
} }
// ExerciceFlagsMap builds the flags bindings between challenge.txt and DB. // ExerciceFlagsMap builds the flags bindings between challenge.txt and DB.
func ExerciceFlagsMap(i Importer, exercice fic.Exercice) (kmap map[int64]fic.Flag) { func ExerciceFlagsMap(i Importer, exercice *fic.Exercice) (kmap map[int64]fic.Flag) {
flags, flagids, _ := buildExerciceFlags(i, exercice) flags, flagids, _ := buildExerciceFlags(i, exercice)
kmap = map[int64]fic.Flag{} kmap = map[int64]fic.Flag{}
@ -449,7 +449,7 @@ func ExerciceFlagsMap(i Importer, exercice fic.Exercice) (kmap map[int64]fic.Fla
} }
// SyncExerciceFlags imports all kind of flags for the given challenge. // SyncExerciceFlags imports all kind of flags for the given challenge.
func SyncExerciceFlags(i Importer, exercice fic.Exercice) (kmap map[int64]fic.Flag, errs []string) { func SyncExerciceFlags(i Importer, exercice *fic.Exercice) (kmap map[int64]fic.Flag, errs []string) {
if _, err := exercice.WipeFlags(); err != nil { if _, err := exercice.WipeFlags(); err != nil {
errs = append(errs, err.Error()) errs = append(errs, err.Error())
} else if _, err := exercice.WipeMCQs(); err != nil { } else if _, err := exercice.WipeMCQs(); err != nil {
@ -466,7 +466,7 @@ func SyncExerciceFlags(i Importer, exercice fic.Exercice) (kmap map[int64]fic.Fl
if addedFlag, err := exercice.AddFlag(flag.Flag); err != nil { if addedFlag, err := exercice.AddFlag(flag.Flag); err != nil {
errs = append(errs, fmt.Sprintf("%q: error flag #%d: %s", path.Base(exercice.Path), flag.Line, err)) errs = append(errs, fmt.Sprintf("%q: error flag #%d: %s", path.Base(exercice.Path), flag.Line, err))
} else { } else {
if f, ok := addedFlag.(fic.FlagKey); ok { if f, ok := addedFlag.(*fic.FlagKey); ok {
for _, choice := range flag.Choices { for _, choice := range flag.Choices {
if _, err := f.AddChoice(choice); err != nil { if _, err := f.AddChoice(choice); err != nil {
errs = append(errs, fmt.Sprintf("%q: error in flag #%d choice #FIXME: %s", path.Base(exercice.Path), flag.Line, err)) errs = append(errs, fmt.Sprintf("%q: error in flag #%d choice #FIXME: %s", path.Base(exercice.Path), flag.Line, err))
@ -505,9 +505,9 @@ func SyncExerciceFlags(i Importer, exercice fic.Exercice) (kmap map[int64]fic.Fl
func ApiGetRemoteExerciceFlags(ps httprouter.Params, _ []byte) (interface{}, error) { func ApiGetRemoteExerciceFlags(ps httprouter.Params, _ []byte) (interface{}, error) {
theme, errs := BuildTheme(GlobalImporter, ps.ByName("thid")) theme, errs := BuildTheme(GlobalImporter, ps.ByName("thid"))
if theme != nil { if theme != nil {
exercice, _, _, _, errs := BuildExercice(GlobalImporter, *theme, path.Join(theme.Path, ps.ByName("exid")), nil) exercice, _, _, _, errs := BuildExercice(GlobalImporter, theme, path.Join(theme.Path, ps.ByName("exid")), nil)
if exercice != nil { if exercice != nil {
flags, errs := CheckExerciceFlags(GlobalImporter, *exercice, []string{}) flags, errs := CheckExerciceFlags(GlobalImporter, exercice, []string{})
if flags != nil { if flags != nil {
return flags, nil return flags, nil
} else { } else {

View file

@ -22,7 +22,7 @@ func fixnbsp(s string) string {
} }
// GetExercices returns all exercice directories existing in a given theme, considering the given Importer. // GetExercices returns all exercice directories existing in a given theme, considering the given Importer.
func GetExercices(i Importer, theme fic.Theme) ([]string, error) { func GetExercices(i Importer, theme *fic.Theme) ([]string, error) {
var exercices []string var exercices []string
if len(theme.Path) == 0 { if len(theme.Path) == 0 {
@ -42,12 +42,12 @@ func GetExercices(i Importer, theme fic.Theme) ([]string, error) {
return exercices, nil return exercices, nil
} }
func buildDependancyMap(i Importer, theme fic.Theme) (dmap map[int64]fic.Exercice, err error) { func buildDependancyMap(i Importer, theme *fic.Theme) (dmap map[int64]*fic.Exercice, err error) {
var exercices []string var exercices []string
if exercices, err = GetExercices(i, theme); err != nil { if exercices, err = GetExercices(i, theme); err != nil {
return return
} else { } else {
dmap = map[int64]fic.Exercice{} dmap = map[int64]*fic.Exercice{}
for _, edir := range exercices { for _, edir := range exercices {
var eid int var eid int
@ -58,7 +58,7 @@ func buildDependancyMap(i Importer, theme fic.Theme) (dmap map[int64]fic.Exercic
continue continue
} }
var e fic.Exercice var e *fic.Exercice
e, err = theme.GetExerciceByTitle(ename) e, err = theme.GetExerciceByTitle(ename)
if err != nil { if err != nil {
return return
@ -90,7 +90,7 @@ func parseExerciceDirname(edir string) (eid int, ename string, err error) {
} }
// BuildExercice creates an Exercice from a given importer. // BuildExercice creates an Exercice from a given importer.
func BuildExercice(i Importer, theme fic.Theme, epath string, dmap *map[int64]fic.Exercice) (e *fic.Exercice, p ExerciceParams, eid int, edir string, errs []string) { func BuildExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*fic.Exercice) (e *fic.Exercice, p ExerciceParams, eid int, edir string, errs []string) {
e = &fic.Exercice{} e = &fic.Exercice{}
e.Path = epath e.Path = epath
@ -211,7 +211,7 @@ func BuildExercice(i Importer, theme fic.Theme, epath string, dmap *map[int64]fi
} }
// SyncExercice imports new or updates existing given exercice. // SyncExercice imports new or updates existing given exercice.
func SyncExercice(i Importer, theme fic.Theme, epath string, dmap *map[int64]fic.Exercice) (e *fic.Exercice, eid int, errs []string) { func SyncExercice(i Importer, theme *fic.Theme, epath string, dmap *map[int64]*fic.Exercice) (e *fic.Exercice, eid int, errs []string) {
var err error var err error
var edir string var edir string
var p ExerciceParams var p ExerciceParams
@ -242,7 +242,7 @@ func SyncExercice(i Importer, theme fic.Theme, epath string, dmap *map[int64]fic
} }
// SyncExercices imports new or updates existing exercices, in a given theme. // SyncExercices imports new or updates existing exercices, in a given theme.
func SyncExercices(i Importer, theme fic.Theme) (errs []string) { func SyncExercices(i Importer, theme *fic.Theme) (errs []string) {
if !avoidImporterSync() { if !avoidImporterSync() {
if err := i.Sync(); err != nil { if err := i.Sync(); err != nil {
errs = append(errs, err.Error()) errs = append(errs, err.Error())
@ -260,7 +260,7 @@ func SyncExercices(i Importer, theme fic.Theme) (errs []string) {
e, eid, cur_errs := SyncExercice(i, theme, path.Join(theme.Path, edir), &dmap) e, eid, cur_errs := SyncExercice(i, theme, path.Join(theme.Path, edir), &dmap)
if e != nil { if e != nil {
emap[e.Title] = eid emap[e.Title] = eid
dmap[int64(eid)] = *e dmap[int64(eid)] = e
errs = append(errs, cur_errs...) errs = append(errs, cur_errs...)
} }
} }
@ -281,7 +281,7 @@ func SyncExercices(i Importer, theme fic.Theme) (errs []string) {
func ApiListRemoteExercices(ps httprouter.Params, _ []byte) (interface{}, error) { func ApiListRemoteExercices(ps httprouter.Params, _ []byte) (interface{}, error) {
theme, errs := BuildTheme(GlobalImporter, ps.ByName("thid")) theme, errs := BuildTheme(GlobalImporter, ps.ByName("thid"))
if theme != nil { if theme != nil {
return GetExercices(GlobalImporter, *theme) return GetExercices(GlobalImporter, theme)
} else { } else {
return nil, fmt.Errorf("%q", errs) return nil, fmt.Errorf("%q", errs)
} }
@ -291,7 +291,7 @@ func ApiListRemoteExercices(ps httprouter.Params, _ []byte) (interface{}, error)
func ApiGetRemoteExercice(ps httprouter.Params, _ []byte) (interface{}, error) { func ApiGetRemoteExercice(ps httprouter.Params, _ []byte) (interface{}, error) {
theme, errs := BuildTheme(GlobalImporter, ps.ByName("thid")) theme, errs := BuildTheme(GlobalImporter, ps.ByName("thid"))
if theme != nil { if theme != nil {
exercice, _, _, _, errs := BuildExercice(GlobalImporter, *theme, path.Join(theme.Path, ps.ByName("exid")), nil) exercice, _, _, _, errs := BuildExercice(GlobalImporter, theme, path.Join(theme.Path, ps.ByName("exid")), nil)
if exercice != nil { if exercice != nil {
return exercice, nil return exercice, nil
} else { } else {

View file

@ -129,6 +129,10 @@ func getFileContent(i Importer, URI string) (string, error) {
buf = append(buf, b) buf = append(buf, b)
} }
if len(buf) == 0 {
return "", fmt.Errorf("File is empty")
}
return strings.TrimSpace(string(buf)), nil return strings.TrimSpace(string(buf)), nil
} }
} }

View file

@ -182,7 +182,7 @@ func EditDeepReport(errs map[string][]string, erase bool) {
} }
// SyncThemeDeep performs a recursive synchronisation: from challenges to challenge items. // SyncThemeDeep performs a recursive synchronisation: from challenges to challenge items.
func SyncThemeDeep(i Importer, theme fic.Theme, tid int, themeStep uint8) (errs []string) { func SyncThemeDeep(i Importer, theme *fic.Theme, tid int, themeStep uint8) (errs []string) {
oneThemeDeepSync.Lock() oneThemeDeepSync.Lock()
defer oneThemeDeepSync.Unlock() defer oneThemeDeepSync.Unlock()

View file

@ -213,15 +213,15 @@ func SyncThemes(i Importer) (errs []string) {
} }
} }
var theme fic.Theme var theme *fic.Theme
if theme, err = fic.GetThemeByPath(btheme.Path); err != nil { if theme, err = fic.GetThemeByPath(btheme.Path); err != nil {
if _, err := fic.CreateTheme(*btheme); err != nil { if _, err := fic.CreateTheme(btheme); err != nil {
errs = append(errs, fmt.Sprintf("%q: an error occurs during add: %s", tdir, err)) errs = append(errs, fmt.Sprintf("%q: an error occurs during add: %s", tdir, err))
continue continue
} }
} }
if !fic.CmpTheme(theme, *btheme) { if !fic.CmpTheme(theme, btheme) {
btheme.Id = theme.Id btheme.Id = theme.Id
if _, err := btheme.Update(); err != nil { if _, err := btheme.Update(); err != nil {
errs = append(errs, fmt.Sprintf("%q: an error occurs during update: %s", tdir, err)) errs = append(errs, fmt.Sprintf("%q: an error occurs during update: %s", tdir, err))

View file

@ -16,7 +16,7 @@ type wantChoices struct {
FlagId int `json:"id"` FlagId int `json:"id"`
} }
func treatWantChoices(pathname string, team fic.Team) { func treatWantChoices(pathname string, team *fic.Team) {
// Generate a unique identifier to follow the request in logs // Generate a unique identifier to follow the request in logs
bid := make([]byte, 5) bid := make([]byte, 5)
binary.LittleEndian.PutUint32(bid, rand.Uint32()) binary.LittleEndian.PutUint32(bid, rand.Uint32())
@ -43,7 +43,7 @@ func treatWantChoices(pathname string, team fic.Team) {
} else if err = team.DisplayChoices(flag); err != nil { } else if err = team.DisplayChoices(flag); err != nil {
log.Printf("%s [ERR] %s\n", id, err) log.Printf("%s [ERR] %s\n", id, err)
} else { } else {
genTeamQueue <- &team genTeamQueue <- team
if err = os.Remove(pathname); err != nil { if err = os.Remove(pathname); err != nil {
log.Printf("%s [ERR] %s\n", id, err) log.Printf("%s [ERR] %s\n", id, err)
} }

View file

@ -96,7 +96,7 @@ func consumer() {
} }
// Generate issues.json for a given team // Generate issues.json for a given team
func genTeamIssuesFile(team fic.Team) error { func genTeamIssuesFile(team *fic.Team) error {
dirPath := path.Join(TeamsDir, fmt.Sprintf("%d", team.Id)) dirPath := path.Join(TeamsDir, fmt.Sprintf("%d", team.Id))
if s, err := os.Stat(dirPath); os.IsNotExist(err) { if s, err := os.Stat(dirPath); os.IsNotExist(err) {
@ -237,7 +237,7 @@ func genAll() {
} else { } else {
for _, team := range teams { for _, team := range teams {
myteam := team // team is reused, we need to create a new variable here to store the value myteam := team // team is reused, we need to create a new variable here to store the value
genTeamQueue <- &myteam genTeamQueue <- myteam
} }
} }
} }

View file

@ -18,7 +18,7 @@ type askOpenHint struct {
HintId int64 `json:"id"` HintId int64 `json:"id"`
} }
func treatOpeningHint(pathname string, team fic.Team) { func treatOpeningHint(pathname string, team *fic.Team) {
// Generate a unique identifier to follow the request in logs // Generate a unique identifier to follow the request in logs
bid := make([]byte, 5) bid := make([]byte, 5)
binary.LittleEndian.PutUint32(bid, rand.Uint32()) binary.LittleEndian.PutUint32(bid, rand.Uint32())
@ -54,7 +54,7 @@ func treatOpeningHint(pathname string, team fic.Team) {
log.Printf("%s [WRN] Unable to create event: %s\n", id, err) log.Printf("%s [WRN] Unable to create event: %s\n", id, err)
} }
genTeamQueue <- &team genTeamQueue <- team
appendGenQueue(genStruct{Type: GenEvents}) appendGenQueue(genStruct{Type: GenEvents})
if err = os.Remove(pathname); err != nil { if err = os.Remove(pathname); err != nil {
log.Printf("%s [ERR] %s\n", id, err) log.Printf("%s [ERR] %s\n", id, err)

View file

@ -19,7 +19,7 @@ type IssueUpload struct {
Description string `json:"description"` Description string `json:"description"`
} }
func treatIssue(pathname string, team fic.Team) { func treatIssue(pathname string, team *fic.Team) {
// Generate a unique identifier to follow the request in logs // Generate a unique identifier to follow the request in logs
bid := make([]byte, 5) bid := make([]byte, 5)
binary.LittleEndian.PutUint32(bid, rand.Uint32()) binary.LittleEndian.PutUint32(bid, rand.Uint32())
@ -50,7 +50,7 @@ func treatIssue(pathname string, team fic.Team) {
log.Printf("%s [ERR] %s\n", id, err) log.Printf("%s [ERR] %s\n", id, err)
} }
log.Printf("%s Empty issue: not treated.\n", id) log.Printf("%s Empty issue: not treated.\n", id)
} else if desc, err := claim.AddDescription(issue.Description, fic.ClaimAssignee{Id: 0}, true); err != nil { } else if desc, err := claim.AddDescription(issue.Description, &fic.ClaimAssignee{Id: 0}, true); err != nil {
log.Printf("%s [WRN] Unable to add description to issue: %s\n", id, err) log.Printf("%s [WRN] Unable to add description to issue: %s\n", id, err)
} else { } else {
claim.State = "new" claim.State = "new"
@ -65,13 +65,13 @@ func treatIssue(pathname string, team fic.Team) {
} else { } else {
var exercice *fic.Exercice = nil var exercice *fic.Exercice = nil
if e, err := fic.GetExercice(issue.IdExercice); err == nil { if e, err := fic.GetExercice(issue.IdExercice); err == nil {
exercice = &e exercice = e
} }
if claim, err := fic.NewClaim(issue.Subject, &team, exercice, nil, "medium"); err != nil { if claim, err := fic.NewClaim(issue.Subject, team, exercice, nil, "medium"); err != nil {
log.Printf("%s [ERR] Unable to create new issue: %s\n", id, err) log.Printf("%s [ERR] Unable to create new issue: %s\n", id, err)
} else if len(issue.Description) > 0 { } else if len(issue.Description) > 0 {
if _, err := claim.AddDescription(issue.Description, fic.ClaimAssignee{Id: 0}, true); err != nil { if _, err := claim.AddDescription(issue.Description, &fic.ClaimAssignee{Id: 0}, true); err != nil {
log.Printf("%s [WRN] Unable to add description to issue: %s\n", id, err) log.Printf("%s [WRN] Unable to add description to issue: %s\n", id, err)
} else { } else {
log.Printf("%s [OOK] New issue created: id=%d\n", id, claim.Id) log.Printf("%s [OOK] New issue created: id=%d\n", id, claim.Id)

View file

@ -220,7 +220,7 @@ func treat(raw_path string) {
} }
} }
var team fic.Team var team *fic.Team
if team, err = fic.GetTeam(teamid); err != nil { if team, err = fic.GetTeam(teamid); err != nil {
log.Printf("[ERR] Unable to retrieve team %d: %s\n", teamid, err) log.Printf("[ERR] Unable to retrieve team %d: %s\n", teamid, err)
return return

View file

@ -27,11 +27,11 @@ type uTeamRegistration struct {
Members []fic.Member Members []fic.Member
} }
func registrationProcess(id string, team fic.Team, members []fic.Member, team_id string) { func registrationProcess(id string, team *fic.Team, members []fic.Member, team_id string) {
for _, m := range members { for _, m := range members {
// Force Id to 0, as it shouldn't have been defined yet // Force Id to 0, as it shouldn't have been defined yet
m.Id = 0 m.Id = 0
if err := team.GainMember(m); err != nil { if err := team.GainMember(&m); err != nil {
log.Println("[WRN] Unable to add member (", m, ") to team (", team, "):", err) log.Println("[WRN] Unable to add member (", m, ") to team (", team, "):", err)
} }
} }
@ -46,7 +46,7 @@ func registrationProcess(id string, team fic.Team, members []fic.Member, team_id
log.Println(id, "[ERR]", err) log.Println(id, "[ERR]", err)
} }
genTeamQueue <- &team genTeamQueue <- team
appendGenQueue(genStruct{Type: GenTeams}) appendGenQueue(genStruct{Type: GenTeams})
} }

View file

@ -20,7 +20,7 @@ func validTeamName(name string) bool {
return err == nil && match return err == nil && match
} }
func treatRename(pathname string, team fic.Team) { func treatRename(pathname string, team *fic.Team) {
// Generate a unique identifier to follow the request in logs // Generate a unique identifier to follow the request in logs
bid := make([]byte, 5) bid := make([]byte, 5)
binary.LittleEndian.PutUint32(bid, rand.Uint32()) binary.LittleEndian.PutUint32(bid, rand.Uint32())
@ -38,7 +38,7 @@ func treatRename(pathname string, team fic.Team) {
if _, err := team.Update(); err != nil { if _, err := team.Update(); err != nil {
log.Printf("%s [WRN] Unable to change team name: %s\n", id, err) log.Printf("%s [WRN] Unable to change team name: %s\n", id, err)
} }
genTeamQueue <- &team genTeamQueue <- team
if _, err := fic.NewEvent(fmt.Sprintf("Souhaitons bonne chance à l'équipe <strong>%s</strong> qui vient de nous rejoindre&#160;!", html.EscapeString(team.Name)), "info"); err != nil { if _, err := fic.NewEvent(fmt.Sprintf("Souhaitons bonne chance à l'équipe <strong>%s</strong> qui vient de nous rejoindre&#160;!", html.EscapeString(team.Name)), "info"); err != nil {
log.Printf("%s [WRN] Unable to create event: %s\n", id, err) log.Printf("%s [WRN] Unable to create event: %s\n", id, err)
} }

View file

@ -23,7 +23,7 @@ type ResponsesUpload struct {
MCQJ map[int]string `json:"justifications"` MCQJ map[int]string `json:"justifications"`
} }
func treatSubmission(pathname string, team fic.Team, exercice_id string) { func treatSubmission(pathname string, team *fic.Team, exercice_id string) {
// Generate a unique identifier to follow the request in logs // Generate a unique identifier to follow the request in logs
bid := make([]byte, 5) bid := make([]byte, 5)
binary.LittleEndian.PutUint32(bid, rand.Uint32()) binary.LittleEndian.PutUint32(bid, rand.Uint32())
@ -80,8 +80,8 @@ 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
s, tm := team.HasSolved(exercice) tm := team.HasSolved(exercice)
if s { if tm != nil {
log.Printf("%s [WRN] Team %d ALREADY solved exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title) log.Printf("%s [WRN] Team %d ALREADY solved exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
return return
} }
@ -110,7 +110,7 @@ func treatSubmission(pathname string, team fic.Team, exercice_id string) {
solved, err := exercice.CheckResponse(cksum[:], responses.Keys, responses.MCQs, team) solved, err := exercice.CheckResponse(cksum[:], responses.Keys, responses.MCQs, team)
if err != nil { if err != nil {
log.Println(id, "[ERR] Unable to CheckResponse:", err) log.Println(id, "[ERR] Unable to CheckResponse:", err)
genTeamQueue <- &team genTeamQueue <- team
return return
} }
@ -131,21 +131,21 @@ func treatSubmission(pathname string, team fic.Team, exercice_id string) {
} else if _, err := fic.NewEvent(fmt.Sprintf("L'équipe %s a résolu le <strong>%d<sup>e</sup></strong> défi %s&#160;!", html.EscapeString(team.Name), lvl, theme.Name), "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&#160;!", 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)
} }
genTeamQueue <- &team genTeamQueue <- team
appendGenQueue(genStruct{id, GenThemes}) appendGenQueue(genStruct{id, GenThemes})
appendGenQueue(genStruct{id, GenTeams}) appendGenQueue(genStruct{id, 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) log.Printf("%s Team %d submit an invalid solution for exercice %d (%s : %s)\n", id, team.Id, exercice.Id, theme.Name, exercice.Title)
// Write event (only on first try) // Write event (only on first try)
if tm.Unix() == 0 { if tm == nil {
if lvl, err := exercice.GetLevel(); err != nil { if lvl, err := exercice.GetLevel(); err != nil {
log.Println(id, "[ERR] Unable to get exercice level:", err) 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&#160;!", html.EscapeString(team.Name), lvl, theme.Name), "warning"); err != nil { } else if _, err := fic.NewEvent(fmt.Sprintf("L'équipe %s tente le <strong>%d<sup>e</sup></strong> défi %s&#160;!", 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)
} }
} }
genTeamQueue <- &team genTeamQueue <- team
} }
appendGenQueue(genStruct{id, GenEvents}) appendGenQueue(genStruct{id, GenEvents})

View file

@ -7,7 +7,7 @@ import (
) )
func WantChoicesHandler(w http.ResponseWriter, r *http.Request, team string, sURL []string) { func WantChoicesHandler(w http.ResponseWriter, r *http.Request, team string, sURL []string) {
if time.Now().Sub(challengeEnd) > 0 { if time.Now().After(challengeEnd) {
http.Error(w, "{\"errmsg\":\"Le challenge est terminé, trop tard !\"}", http.StatusGone) http.Error(w, "{\"errmsg\":\"Le challenge est terminé, trop tard !\"}", http.StatusGone)
return return
} }

View file

@ -7,7 +7,7 @@ import (
) )
func HintHandler(w http.ResponseWriter, r *http.Request, team string, sURL []string) { func HintHandler(w http.ResponseWriter, r *http.Request, team string, sURL []string) {
if time.Now().Sub(challengeEnd) > 0 { if time.Now().After(challengeEnd) {
http.Error(w, "{\"errmsg\":\"Le challenge est terminé, trop tard pour un indice !\"}", http.StatusGone) http.Error(w, "{\"errmsg\":\"Le challenge est terminé, trop tard pour un indice !\"}", http.StatusGone)
return return
} }

View file

@ -31,9 +31,9 @@ func reloadSettings(config settings.FICSettings) {
// Copy the new settings file for distribution // Copy the new settings file for distribution
if data, err := ioutil.ReadFile(path.Join(settings.SettingsDir, settings.SettingsFile)); err != nil { if data, err := ioutil.ReadFile(path.Join(settings.SettingsDir, settings.SettingsFile)); err != nil {
log.Println("Unable to read settings file:", err) log.Println("Unable to read settings file:", err)
} else if err = ioutil.WriteFile(path.Join(SettingsDistDir, settings.SettingsFile + ".tmp"), data, 0644); err != nil { } else if err = ioutil.WriteFile(path.Join(SettingsDistDir, settings.SettingsFile+".tmp"), data, 0644); err != nil {
log.Println("Unable to write tmp settings file:", err) log.Println("Unable to write tmp settings file:", err)
} else if err := os.Rename(path.Join(SettingsDistDir, settings.SettingsFile + ".tmp"), path.Join(SettingsDistDir, settings.SettingsFile)); err != nil { } else if err := os.Rename(path.Join(SettingsDistDir, settings.SettingsFile+".tmp"), path.Join(SettingsDistDir, settings.SettingsFile)); err != nil {
log.Println("Unable to move new settings file:", err) log.Println("Unable to move new settings file:", err)
} }
@ -52,7 +52,7 @@ func reloadSettings(config settings.FICSettings) {
return return
} }
startSub := config.Start.Sub(time.Now()) startSub := time.Until(config.Start)
if startSub > 0 { if startSub > 0 {
log.Println("Challenge will starts at", config.Start, "in", startSub) log.Println("Challenge will starts at", config.Start, "in", startSub)
@ -60,7 +60,7 @@ func reloadSettings(config settings.FICSettings) {
os.Remove(startedFile) os.Remove(startedFile)
} }
touchTimer = time.AfterFunc(config.Start.Sub(time.Now().Add(time.Duration(1 * time.Second))), touchStartedFile) touchTimer = time.AfterFunc(config.Start.Sub(time.Now().Add(time.Duration(1*time.Second))), touchStartedFile)
} else { } else {
log.Println("Challenge started at", config.Start, "since", -startSub) log.Println("Challenge started at", config.Start, "since", -startSub)
touchStartedFile() touchStartedFile()

View file

@ -9,7 +9,7 @@ import (
) )
func SubmissionHandler(w http.ResponseWriter, r *http.Request, team string, sURL []string) { func SubmissionHandler(w http.ResponseWriter, r *http.Request, team string, sURL []string) {
if time.Now().Sub(challengeEnd) > 0 { if time.Now().After(challengeEnd) {
http.Error(w, "{\"errmsg\":\"Vous ne pouvez plus soumettre, le challenge est terminé.\"}", http.StatusGone) http.Error(w, "{\"errmsg\":\"Vous ne pouvez plus soumettre, le challenge est terminé.\"}", http.StatusGone)
return return
} }

View file

@ -16,7 +16,7 @@
<Icon name="people-fill" /> <Icon name="people-fill" />
Membres de l'équipe Membres de l'équipe
</CardHeader> </CardHeader>
{#if members.length} {#if members && members.length}
<ListGroup> <ListGroup>
{#each members as member (member.id)} {#each members as member (member.id)}
<ListGroupItem class="list-group-item-action"> <ListGroupItem class="list-group-item-action">

View file

@ -37,7 +37,7 @@
</Alert> </Alert>
{:else if $teams[$my.team_id]} {:else if $teams[$my.team_id]}
<Alert color="info" class="text-justify" fade={false}> <Alert color="info" class="text-justify" fade={false}>
<strong>Félicitations {#each $my.members as member, index (member.id)}{#if member.id !== $my.members[0].id}{#if member.id === $my.members[$my.members.length - 1].id}&nbsp;et {:else}, {/if}{/if}{member.firstname} {member.lastname}{/each}&nbsp;!</strong> vous êtes maintenant connecté à l'espace de votre équipe <em>{$teams[$my.team_id].name}</em>. <strong>Félicitations{#if $my.members} {#each $my.members as member, index (member.id)}{#if member.id !== $my.members[0].id}{#if member.id === $my.members[$my.members.length - 1].id}&nbsp;et {:else}, {/if}{/if}{member.firstname} {member.lastname}{/each}{/if}&nbsp;!</strong> vous êtes maintenant connecté à l'espace de votre équipe <em>{$teams[$my.team_id].name}</em>.
{#if !$settings.denyNameChange}Vous pouvez changer ce nom dès maintenant en vous rendant sur la page de <a href="edit">votre équipe</a>.{/if} {#if !$settings.denyNameChange}Vous pouvez changer ce nom dès maintenant en vous rendant sur la page de <a href="edit">votre équipe</a>.{/if}
</Alert> </Alert>

View file

@ -24,14 +24,14 @@ type Certificate struct {
} }
// GetCertificates returns the list of all generated certificates. // GetCertificates returns the list of all generated certificates.
func GetCertificates() (certificates []Certificate, err error) { func GetCertificates() (certificates []*Certificate, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_cert, creation, password, revoked FROM certificates ORDER BY creation"); err == nil { if rows, err = DBQuery("SELECT id_cert, creation, password, revoked FROM certificates ORDER BY creation"); err == nil {
defer rows.Close() defer rows.Close()
certificates = make([]Certificate, 0) certificates = []*Certificate{}
for rows.Next() { for rows.Next() {
var c Certificate c := &Certificate{}
if err = rows.Scan(&c.Id, &c.Creation, &c.Password, &c.Revoked); err != nil { if err = rows.Scan(&c.Id, &c.Creation, &c.Password, &c.Revoked); err != nil {
return return
} }
@ -42,9 +42,9 @@ func GetCertificates() (certificates []Certificate, err error) {
return return
} }
// GetCertificate retrieves a certificate from its serial number. // GetCertificate retrieves a certificate from its serial number.
func GetCertificate(serial uint64) (c Certificate, err error) { func GetCertificate(serial uint64) (c *Certificate, err error) {
c = &Certificate{}
err = DBQueryRow("SELECT id_cert, creation, password, revoked FROM certificates WHERE id_cert = ?", serial).Scan(&c.Id, &c.Creation, &c.Password, &c.Revoked) err = DBQueryRow("SELECT id_cert, creation, password, revoked FROM certificates WHERE id_cert = ?", serial).Scan(&c.Id, &c.Creation, &c.Password, &c.Revoked)
return return
} }
@ -72,7 +72,7 @@ func RegisterCertificate(serial uint64, password string) (Certificate, error) {
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (c Certificate) Update() (int64, error) { func (c *Certificate) Update() (int64, error) {
if res, err := DBExec("UPDATE certificates SET creation = ?, password = ?, revoked = ? WHERE id_cert = ?", c.Creation, c.Password, c.Revoked, c.Id); err != nil { if res, err := DBExec("UPDATE certificates SET creation = ?, password = ?, revoked = ? WHERE id_cert = ?", c.Creation, c.Password, c.Revoked, c.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -100,7 +100,6 @@ func (c Certificate) Delete() (int64, error) {
} }
} }
// ClearCertificates removes all certificates from database. // ClearCertificates removes all certificates from database.
func ClearCertificates() (int64, error) { func ClearCertificates() (int64, error) {
if res, err := DBExec("DELETE FROM certificates"); err != nil { if res, err := DBExec("DELETE FROM certificates"); err != nil {

View file

@ -36,15 +36,15 @@ func GetLastEvents() ([]Event, error) {
} }
// GetEvents returns the list of all events, sorted by date, last first // GetEvents returns the list of all events, sorted by date, last first
func GetEvents() ([]Event, error) { func GetEvents() ([]*Event, error) {
if rows, err := DBQuery("SELECT id_event, txt, kind, time FROM events ORDER BY time DESC"); err != nil { if rows, err := DBQuery("SELECT id_event, txt, kind, time FROM events ORDER BY time DESC"); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var events = make([]Event, 0) var events []*Event
for rows.Next() { for rows.Next() {
var e Event e := &Event{}
if err := rows.Scan(&e.Id, &e.Text, &e.Kind, &e.Time); err != nil { if err := rows.Scan(&e.Id, &e.Text, &e.Kind, &e.Time); err != nil {
return nil, err return nil, err
} }
@ -59,24 +59,25 @@ func GetEvents() ([]Event, error) {
} }
// GetEvent retrieves the event with the given id // GetEvent retrieves the event with the given id
func GetEvent(id int64) (e Event, err error) { func GetEvent(id int64) (e *Event, err error) {
e = &Event{}
err = DBQueryRow("SELECT id_event, txt, kind, time FROM events WHERE id_event=?", id).Scan(&e.Id, &e.Text, &e.Kind, &e.Time) err = DBQueryRow("SELECT id_event, txt, kind, time FROM events WHERE id_event=?", id).Scan(&e.Id, &e.Text, &e.Kind, &e.Time)
return return
} }
// NewEvent creates a new event in the database and returns the corresponding structure // NewEvent creates a new event in the database and returns the corresponding structure
func NewEvent(txt string, kind string) (Event, error) { func NewEvent(txt string, kind string) (*Event, error) {
if res, err := DBExec("INSERT INTO events (txt, kind, time) VALUES (?, ?, ?)", txt, kind, time.Now()); err != nil { if res, err := DBExec("INSERT INTO events (txt, kind, time) VALUES (?, ?, ?)", txt, kind, time.Now()); err != nil {
return Event{}, err return nil, err
} else if eid, err := res.LastInsertId(); err != nil { } else if eid, err := res.LastInsertId(); err != nil {
return Event{}, err return nil, err
} else { } else {
return Event{eid, txt, kind, time.Now()}, nil return &Event{eid, txt, kind, time.Now()}, nil
} }
} }
// Update applies modifications back to the database // Update applies modifications back to the database
func (e Event) Update() (int64, error) { func (e *Event) Update() (int64, error) {
if res, err := DBExec("UPDATE events SET txt = ?, kind = ?, time = ? WHERE id_event = ?", e.Text, e.Kind, e.Time, e.Id); err != nil { if res, err := DBExec("UPDATE events SET txt = ?, kind = ?, time = ? WHERE id_event = ?", e.Text, e.Kind, e.Time, e.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -87,7 +88,7 @@ func (e Event) Update() (int64, error) {
} }
// Delete the event from the database // Delete the event from the database
func (e Event) Delete() (int64, error) { func (e *Event) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM events WHERE id_event = ?", e.Id); err != nil { if res, err := DBExec("DELETE FROM events WHERE id_event = ?", e.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {

View file

@ -52,45 +52,45 @@ type Exercice struct {
} }
// GetExercice retrieves the challenge with the given id. // GetExercice retrieves the challenge with the given id.
func GetExercice(id int64) (Exercice, error) { func GetExercice(id int64) (*Exercice, error) {
var e Exercice var e Exercice
if err := DBQueryRow("SELECT id_exercice, id_theme, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, finished FROM exercices WHERE id_exercice = ?", id).Scan(&e.Id, &e.IdTheme, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Finished); err != nil { if err := DBQueryRow("SELECT id_exercice, id_theme, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, finished FROM exercices WHERE id_exercice = ?", id).Scan(&e.Id, &e.IdTheme, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Finished); err != nil {
return Exercice{}, err return nil, err
} }
return e, nil return &e, nil
} }
// GetExercice retrieves the challenge with the given id. // GetExercice retrieves the challenge with the given id.
func (t Theme) GetExercice(id int) (Exercice, error) { func (t *Theme) GetExercice(id int) (*Exercice, error) {
var e Exercice e := &Exercice{}
if err := DBQueryRow("SELECT id_exercice, id_theme, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, finished FROM exercices WHERE id_theme = ? AND id_exercice = ?", t.Id, id).Scan(&e.Id, &e.IdTheme, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Finished); err != nil { if err := DBQueryRow("SELECT id_exercice, id_theme, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, finished FROM exercices WHERE id_theme = ? AND id_exercice = ?", t.Id, id).Scan(&e.Id, &e.IdTheme, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Finished); err != nil {
return Exercice{}, err return nil, err
} }
return e, nil return e, nil
} }
// GetExerciceByTitle retrieves the challenge with the given title. // GetExerciceByTitle retrieves the challenge with the given title.
func (t Theme) GetExerciceByTitle(title string) (Exercice, error) { func (t *Theme) GetExerciceByTitle(title string) (*Exercice, error) {
var e Exercice e := &Exercice{}
if err := DBQueryRow("SELECT id_exercice, id_theme, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, finished FROM exercices WHERE id_theme = ? AND title = ?", t.Id, title).Scan(&e.Id, &e.IdTheme, &e.Title, &t.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Finished); err != nil { if err := DBQueryRow("SELECT id_exercice, id_theme, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, finished FROM exercices WHERE id_theme = ? AND title = ?", t.Id, title).Scan(&e.Id, &e.IdTheme, &e.Title, &t.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Finished); err != nil {
return Exercice{}, err return nil, err
} }
return e, nil return e, nil
} }
// GetExercices returns the list of all challenges present in the database. // GetExercices returns the list of all challenges present in the database.
func GetExercices() ([]Exercice, error) { func GetExercices() ([]*Exercice, error) {
if rows, err := DBQuery("SELECT id_exercice, id_theme, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, finished FROM exercices"); err != nil { if rows, err := DBQuery("SELECT id_exercice, id_theme, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, finished FROM exercices"); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var exos = make([]Exercice, 0) exos := []*Exercice{}
for rows.Next() { for rows.Next() {
var e Exercice e := &Exercice{}
if err := rows.Scan(&e.Id, &e.IdTheme, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Finished); err != nil { if err := rows.Scan(&e.Id, &e.IdTheme, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Finished); err != nil {
return nil, err return nil, err
} }
@ -105,15 +105,15 @@ func GetExercices() ([]Exercice, error) {
} }
// GetExercices returns the list of all challenges in the Theme. // GetExercices returns the list of all challenges in the Theme.
func (t Theme) GetExercices() ([]Exercice, error) { func (t *Theme) GetExercices() ([]*Exercice, error) {
if rows, err := DBQuery("SELECT id_exercice, id_theme, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, finished FROM exercices WHERE id_theme = ?", t.Id); err != nil { if rows, err := DBQuery("SELECT id_exercice, id_theme, title, url_id, path, statement, overview, headline, issue, issue_kind, depend, gain, coefficient_cur, video_uri, finished FROM exercices WHERE id_theme = ?", t.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var exos = make([]Exercice, 0) exos := []*Exercice{}
for rows.Next() { for rows.Next() {
var e Exercice e := &Exercice{}
if err := rows.Scan(&e.Id, &e.IdTheme, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Finished); err != nil { if err := rows.Scan(&e.Id, &e.IdTheme, &e.Title, &e.URLId, &e.Path, &e.Statement, &e.Overview, &e.Headline, &e.Issue, &e.IssueKind, &e.Depend, &e.Gain, &e.Coefficient, &e.VideoURI, &e.Finished); err != nil {
return nil, err return nil, err
} }
@ -128,8 +128,8 @@ func (t Theme) GetExercices() ([]Exercice, error) {
} }
// SaveNamedExercice looks for an exercice with the same title to update it, or create it if it doesn't exists yet. // SaveNamedExercice looks for an exercice with the same title to update it, or create it if it doesn't exists yet.
func (t Theme) SaveNamedExercice(e *Exercice) (err error) { func (t *Theme) SaveNamedExercice(e *Exercice) (err error) {
var search Exercice var search *Exercice
if search, err = t.GetExerciceByTitle(e.Title); err == nil { if search, err = t.GetExerciceByTitle(e.Title); err == nil {
// Force ID // Force ID
e.Id = search.Id e.Id = search.Id
@ -152,7 +152,7 @@ func (t Theme) SaveNamedExercice(e *Exercice) (err error) {
return return
} }
func (t Theme) addExercice(e *Exercice) (err error) { func (t *Theme) addExercice(e *Exercice) (err error) {
var ik = "DEFAULT" var ik = "DEFAULT"
if len(e.IssueKind) > 0 { if len(e.IssueKind) > 0 {
ik = fmt.Sprintf("%q", e.IssueKind) ik = fmt.Sprintf("%q", e.IssueKind)
@ -175,13 +175,13 @@ func (t Theme) addExercice(e *Exercice) (err error) {
} }
// AddExercice creates and fills a new struct Exercice and registers it into the database. // AddExercice creates and fills a new struct Exercice and registers it into the database.
func (t Theme) AddExercice(title string, urlId string, path string, statement string, overview string, headline string, depend *Exercice, gain int64, videoURI string, finished string) (e Exercice, err error) { func (t *Theme) AddExercice(title string, urlId string, path string, statement string, overview string, headline string, depend *Exercice, gain int64, videoURI string, finished string) (e *Exercice, err error) {
var dpd *int64 = nil var dpd *int64 = nil
if depend != nil { if depend != nil {
dpd = &depend.Id dpd = &depend.Id
} }
e = Exercice{ e = &Exercice{
Title: title, Title: title,
URLId: urlId, URLId: urlId,
Path: path, Path: path,
@ -194,13 +194,13 @@ func (t Theme) AddExercice(title string, urlId string, path string, statement st
VideoURI: videoURI, VideoURI: videoURI,
} }
err = t.addExercice(&e) err = t.addExercice(e)
return return
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (e Exercice) Update() (int64, error) { func (e *Exercice) Update() (int64, error) {
if res, err := DBExec("UPDATE exercices SET title = ?, url_id = ?, path = ?, statement = ?, overview = ?, headline = ?, issue = ?, issue_kind = ?, depend = ?, gain = ?, coefficient_cur = ?, video_uri = ?, finished = ? WHERE id_exercice = ?", e.Title, e.URLId, e.Path, e.Statement, e.Overview, e.Headline, e.Issue, e.IssueKind, e.Depend, e.Gain, e.Coefficient, e.VideoURI, e.Finished, e.Id); err != nil { if res, err := DBExec("UPDATE exercices SET title = ?, url_id = ?, path = ?, statement = ?, overview = ?, headline = ?, issue = ?, issue_kind = ?, depend = ?, gain = ?, coefficient_cur = ?, video_uri = ?, finished = ? WHERE id_exercice = ?", e.Title, e.URLId, e.Path, e.Statement, e.Overview, e.Headline, e.Issue, e.IssueKind, e.Depend, e.Gain, e.Coefficient, e.VideoURI, e.Finished, e.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -221,7 +221,7 @@ func (e *Exercice) FixURLId() bool {
} }
// Delete the challenge from the database. // Delete the challenge from the database.
func (e Exercice) Delete() (int64, error) { func (e *Exercice) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM exercices WHERE id_exercice = ?", e.Id); err != nil { if res, err := DBExec("DELETE FROM exercices WHERE id_exercice = ?", e.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -232,7 +232,7 @@ func (e Exercice) Delete() (int64, error) {
} }
// DeleteCascade the challenge from the database, including inner content but not player content. // DeleteCascade the challenge from the database, including inner content but not player content.
func (e Exercice) DeleteCascade() (int64, error) { func (e *Exercice) DeleteCascade() (int64, error) {
if _, err := DBExec("UPDATE exercices SET depend = NULL WHERE depend = ?", e.Id); err != nil { if _, err := DBExec("UPDATE exercices SET depend = NULL WHERE depend = ?", e.Id); err != nil {
return 0, err return 0, err
} else if _, err := DBExec("DELETE FROM exercice_files_okey_deps WHERE id_file IN (SELECT id_file FROM exercice_files WHERE id_exercice = ?)", e.Id); err != nil { } else if _, err := DBExec("DELETE FROM exercice_files_okey_deps WHERE id_file IN (SELECT id_file FROM exercice_files WHERE id_exercice = ?)", e.Id); err != nil {
@ -269,7 +269,7 @@ func (e Exercice) DeleteCascade() (int64, error) {
} }
// DeleteCascadePlayer delete player content related to this challenge. // DeleteCascadePlayer delete player content related to this challenge.
func (e Exercice) DeleteCascadePlayer() (int64, error) { func (e *Exercice) DeleteCascadePlayer() (int64, error) {
if _, err := DBExec("DELETE FROM mcq_found WHERE id_mcq IN (SELECT id_mcq FROM exercice_mcq WHERE id_exercice = ?)", e.Id); err != nil { if _, err := DBExec("DELETE FROM mcq_found WHERE id_mcq IN (SELECT id_mcq FROM exercice_mcq WHERE id_exercice = ?)", e.Id); err != nil {
return 0, err return 0, err
} else if _, err := DBExec("DELETE FROM flag_found WHERE id_flag IN (SELECT id_flag FROM exercice_flags WHERE id_exercice = ?)", e.Id); err != nil { } else if _, err := DBExec("DELETE FROM flag_found WHERE id_flag IN (SELECT id_flag FROM exercice_flags WHERE id_exercice = ?)", e.Id); err != nil {
@ -288,7 +288,7 @@ func (e Exercice) DeleteCascadePlayer() (int64, error) {
} }
// DeleteDeep the challenge from the database, including player content. // DeleteDeep the challenge from the database, including player content.
func (e Exercice) DeleteDeep() (int64, error) { func (e *Exercice) DeleteDeep() (int64, error) {
if _, err := e.DeleteCascadePlayer(); err != nil { if _, err := e.DeleteCascadePlayer(); err != nil {
return 0, err return 0, err
} else { } else {
@ -297,13 +297,13 @@ func (e Exercice) DeleteDeep() (int64, error) {
} }
// GetLevel returns the number of dependancy challenges. // GetLevel returns the number of dependancy challenges.
func (e Exercice) GetLevel() (int, error) { func (e *Exercice) GetLevel() (int, error) {
dep := e.Depend dep := e.Depend
nb := 1 nb := 1
for dep != nil { for dep != nil {
nb += 1 nb += 1
if nb > 10 || *dep == e.Id { if nb > 10 || *dep == e.Id {
return nb, errors.New("Exceed number of levels") return nb, errors.New("exceed number of levels")
} else if edep, err := GetExercice(*dep); err != nil { } else if edep, err := GetExercice(*dep); err != nil {
return nb, err return nb, err
} else { } else {
@ -314,7 +314,7 @@ func (e Exercice) GetLevel() (int, error) {
} }
// NewTry registers a solving attempt for the given Team. // NewTry registers a solving attempt for the given Team.
func (e Exercice) NewTry(t Team, cksum []byte) error { func (e *Exercice) NewTry(t *Team, cksum []byte) error {
if _, err := DBExec("INSERT INTO exercice_tries (id_exercice, id_team, time, cksum) VALUES (?, ?, ?, ?)", e.Id, t.Id, time.Now(), cksum); err != nil { if _, err := DBExec("INSERT INTO exercice_tries (id_exercice, id_team, time, cksum) VALUES (?, ?, ?, ?)", e.Id, t.Id, time.Now(), cksum); err != nil {
return err return err
} else { } else {
@ -324,7 +324,7 @@ func (e Exercice) NewTry(t Team, cksum []byte) error {
// UpdateTry applies modifications to the latest try registered for the given Team. // UpdateTry applies modifications to the latest try registered for the given Team.
// Updated values are time and the given nbdiff. // Updated values are time and the given nbdiff.
func (e Exercice) UpdateTry(t Team, nbdiff int, oneGood bool) error { func (e *Exercice) UpdateTry(t *Team, nbdiff int, oneGood bool) error {
if _, err := DBExec("UPDATE exercice_tries SET nbdiff = ?, onegood = ?, time = ? WHERE id_exercice = ? AND id_team = ? ORDER BY time DESC LIMIT 1", nbdiff, oneGood, time.Now(), e.Id, t.Id); err != nil { if _, err := DBExec("UPDATE exercice_tries SET nbdiff = ?, onegood = ?, time = ? WHERE id_exercice = ? AND id_team = ? ORDER BY time DESC LIMIT 1", nbdiff, oneGood, time.Now(), e.Id, t.Id); err != nil {
return err return err
} else { } else {
@ -333,7 +333,7 @@ func (e Exercice) UpdateTry(t Team, nbdiff int, oneGood bool) error {
} }
// Solved registers that the given Team solves the challenge. // Solved registers that the given Team solves the challenge.
func (e Exercice) Solved(t Team) error { func (e *Exercice) Solved(t *Team) error {
if _, err := DBExec("INSERT INTO exercice_solved (id_exercice, id_team, time, coefficient) VALUES (?, ?, ?, ?)", e.Id, t.Id, time.Now(), e.Coefficient*ExerciceCurrentCoefficient); err != nil { if _, err := DBExec("INSERT INTO exercice_solved (id_exercice, id_team, time, coefficient) VALUES (?, ?, ?, ?)", e.Id, t.Id, time.Now(), e.Coefficient*ExerciceCurrentCoefficient); err != nil {
return err return err
} else { } else {
@ -342,7 +342,7 @@ func (e Exercice) Solved(t Team) error {
} }
// SolvedCount returns the number of Team that already have solved the challenge. // SolvedCount returns the number of Team that already have solved the challenge.
func (e Exercice) SolvedCount() int64 { func (e *Exercice) SolvedCount() int64 {
var nb int64 var nb int64
if err := DBQueryRow("SELECT COUNT(id_exercice) FROM exercice_solved WHERE id_exercice = ?", e.Id).Scan(&nb); err != nil { if err := DBQueryRow("SELECT COUNT(id_exercice) FROM exercice_solved WHERE id_exercice = ?", e.Id).Scan(&nb); err != nil {
return 0 return 0
@ -352,7 +352,7 @@ func (e Exercice) SolvedCount() int64 {
} }
// TriedTeamCount returns the number of Team that attempted to solve the exercice. // TriedTeamCount returns the number of Team that attempted to solve the exercice.
func (e Exercice) TriedTeamCount() int64 { func (e *Exercice) TriedTeamCount() int64 {
tries_table := "exercice_tries" tries_table := "exercice_tries"
if SubmissionUniqueness { if SubmissionUniqueness {
tries_table = "exercice_distinct_tries" tries_table = "exercice_distinct_tries"
@ -367,7 +367,7 @@ func (e Exercice) TriedTeamCount() int64 {
} }
// TriedCount returns the number of cumulative attempts, all Team combined, for the exercice. // TriedCount returns the number of cumulative attempts, all Team combined, for the exercice.
func (e Exercice) TriedCount() int64 { func (e *Exercice) TriedCount() int64 {
tries_table := "exercice_tries" tries_table := "exercice_tries"
if SubmissionUniqueness { if SubmissionUniqueness {
tries_table = "exercice_distinct_tries" tries_table = "exercice_distinct_tries"
@ -382,7 +382,7 @@ func (e Exercice) TriedCount() int64 {
} }
// FlagSolved returns the list of flags solved. // FlagSolved returns the list of flags solved.
func (e Exercice) FlagSolved() (res []int64) { func (e *Exercice) FlagSolved() (res []int64) {
if rows, err := DBQuery("SELECT F.id_flag FROM flag_found F INNER JOIN exercice_flags E ON E.id_flag = F.id_flag WHERE E.id_exercice = ? GROUP BY id_flag", e.Id); err != nil { if rows, err := DBQuery("SELECT F.id_flag FROM flag_found F INNER JOIN exercice_flags E ON E.id_flag = F.id_flag WHERE E.id_exercice = ? GROUP BY id_flag", e.Id); err != nil {
return return
} else { } else {
@ -400,7 +400,7 @@ func (e Exercice) FlagSolved() (res []int64) {
} }
// MCQSolved returns the list of mcqs solved. // MCQSolved returns the list of mcqs solved.
func (e Exercice) MCQSolved() (res []int64) { func (e *Exercice) MCQSolved() (res []int64) {
if rows, err := DBQuery("SELECT F.id_mcq FROM mcq_found F INNER JOIN exercice_mcq E ON E.id_mcq = F.id_mcq WHERE E.id_exercice = ? GROUP BY id_mcq", e.Id); err != nil { if rows, err := DBQuery("SELECT F.id_mcq FROM mcq_found F INNER JOIN exercice_mcq E ON E.id_mcq = F.id_mcq WHERE E.id_exercice = ? GROUP BY id_mcq", e.Id); err != nil {
return return
} else { } else {
@ -419,7 +419,7 @@ func (e Exercice) MCQSolved() (res []int64) {
// CheckResponse, given both flags and MCQ responses, figures out if thoses are correct (or if they are previously solved). // CheckResponse, given both flags and MCQ responses, figures out if thoses are correct (or if they are previously solved).
// In the meanwhile, CheckResponse registers good answers given (but it does not mark the challenge as solved at the end). // In the meanwhile, CheckResponse registers good answers given (but it does not mark the challenge as solved at the end).
func (e Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq map[int]bool, t Team) (bool, error) { func (e *Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq map[int]bool, t *Team) (bool, error) {
if err := e.NewTry(t, cksum); err != nil { if err := e.NewTry(t, cksum); err != nil {
return false, err return false, err
} else if flags, err := e.GetFlagKeys(); err != nil { } else if flags, err := e.GetFlagKeys(); err != nil {
@ -477,12 +477,12 @@ func (e Exercice) CheckResponse(cksum []byte, respflags map[int]string, respmcq
} }
// IsSolved returns the number of time this challenge has been solved and the time of the first solve occurence. // IsSolved returns the number of time this challenge has been solved and the time of the first solve occurence.
func (e Exercice) IsSolved() (int, time.Time) { func (e *Exercice) IsSolved() (int, *time.Time) {
var nb *int var nb *int
var tm *time.Time var tm *time.Time
if DBQueryRow("SELECT COUNT(id_exercice), MIN(time) FROM exercice_solved WHERE id_exercice = ?", e.Id).Scan(&nb, &tm); nb == nil || tm == nil { if DBQueryRow("SELECT COUNT(id_exercice), MIN(time) FROM exercice_solved WHERE id_exercice = ?", e.Id).Scan(&nb, &tm); nb == nil || tm == nil {
return 0, time.Time{} return 0, nil
} else { } else {
return *nb, *tm return *nb, tm
} }
} }

View file

@ -6,7 +6,7 @@ import (
) )
// GetHistory aggregates all sources of events or actions for an Exercice // GetHistory aggregates all sources of events or actions for an Exercice
func (e Exercice) GetHistory() ([]map[string]interface{}, error) { func (e *Exercice) GetHistory() ([]map[string]interface{}, error) {
hist := make([]map[string]interface{}, 0) hist := make([]map[string]interface{}, 0)
if rows, err := DBQuery(`SELECT id_team, U.name, U.color, "tries" AS kind, time, 0, id_exercice, NULL, NULL FROM exercice_tries NATURAL JOIN teams U WHERE id_exercice = ? UNION if rows, err := DBQuery(`SELECT id_team, U.name, U.color, "tries" AS kind, time, 0, id_exercice, NULL, NULL FROM exercice_tries NATURAL JOIN teams U WHERE id_exercice = ? UNION
@ -57,7 +57,7 @@ func (e Exercice) GetHistory() ([]map[string]interface{}, error) {
} }
// UpdateHistoryItem sets values an entry from the history. // UpdateHistoryItem sets values an entry from the history.
func (e Exercice) UpdateHistoryItem(coeff float32, tId int64, kind string, h time.Time, secondary *int64) (interface{}, error) { func (e *Exercice) UpdateHistoryItem(coeff float32, tId int64, kind string, h time.Time, secondary *int64) (interface{}, error) {
if kind == "hint" && secondary != nil { if kind == "hint" && secondary != nil {
if res, err := DBExec("UPDATE team_hints SET coefficient = ?, time = ? WHERE id_team = ? AND time = ? AND id_hint = ?", coeff, h, tId, h, *secondary); err != nil { if res, err := DBExec("UPDATE team_hints SET coefficient = ?, time = ? WHERE id_team = ? AND time = ? AND id_hint = ?", coeff, h, tId, h, *secondary); err != nil {
return 0, err return 0, err
@ -88,7 +88,7 @@ func (e Exercice) UpdateHistoryItem(coeff float32, tId int64, kind string, h tim
} }
// DelHistoryItem removes from the database an entry from the history. // DelHistoryItem removes from the database an entry from the history.
func (e Exercice) DelHistoryItem(tId int64, kind string, h time.Time, secondary *int64) (interface{}, error) { func (e *Exercice) DelHistoryItem(tId int64, kind string, h time.Time, secondary *int64) (interface{}, error) {
if kind == "tries" { if kind == "tries" {
if res, err := DBExec("DELETE FROM exercice_tries WHERE id_team = ? AND time = ? AND id_exercice = ?", tId, h, e.Id); err != nil { if res, err := DBExec("DELETE FROM exercice_tries WHERE id_team = ? AND time = ? AND id_exercice = ?", tId, h, e.Id); err != nil {
return 0, err return 0, err

View file

@ -5,7 +5,7 @@ import (
) )
// GetTags returns tags associated with this exercice. // GetTags returns tags associated with this exercice.
func (e Exercice) GetTags() (tags []string, err error) { func (e *Exercice) GetTags() (tags []string, err error) {
if rows, errr := DBQuery("SELECT tag FROM exercice_tags WHERE id_exercice = ?", e.Id); errr != nil { if rows, errr := DBQuery("SELECT tag FROM exercice_tags WHERE id_exercice = ?", e.Id); errr != nil {
return nil, errr return nil, errr
} else { } else {
@ -25,7 +25,7 @@ func (e Exercice) GetTags() (tags []string, err error) {
} }
// AddTag assign a new tag to the exercice and registers it into the database. // AddTag assign a new tag to the exercice and registers it into the database.
func (e Exercice) AddTag(tag string) (string, error) { func (e *Exercice) AddTag(tag string) (string, error) {
tag = strings.Title(tag) tag = strings.Title(tag)
if _, err := DBExec("INSERT INTO exercice_tags (id_exercice, tag) VALUES (?, ?)", e.Id, tag); err != nil { if _, err := DBExec("INSERT INTO exercice_tags (id_exercice, tag) VALUES (?, ?)", e.Id, tag); err != nil {
return "", err return "", err
@ -35,7 +35,7 @@ func (e Exercice) AddTag(tag string) (string, error) {
} }
// DeleteTag delete a tag assigned to the current exercice from the database. // DeleteTag delete a tag assigned to the current exercice from the database.
func (e Exercice) DeleteTag(tag string) (int64, error) { func (e *Exercice) DeleteTag(tag string) (int64, error) {
if res, err := DBExec("DELETE FROM exercice_tags WHERE id_exercice = ? AND tag = ?", e.Id, tag); err != nil { if res, err := DBExec("DELETE FROM exercice_tags WHERE id_exercice = ? AND tag = ?", e.Id, tag); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -46,7 +46,7 @@ func (e Exercice) DeleteTag(tag string) (int64, error) {
} }
// WipeTags delete all tag assigned to the current exercice from the database. // WipeTags delete all tag assigned to the current exercice from the database.
func (e Exercice) WipeTags() (int64, error) { func (e *Exercice) WipeTags() (int64, error) {
if res, err := DBExec("DELETE FROM exercice_tags WHERE id_exercice = ?", e.Id); err != nil { if res, err := DBExec("DELETE FROM exercice_tags WHERE id_exercice = ?", e.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {

View file

@ -45,15 +45,15 @@ type EFile struct {
} }
// GetFiles returns a list of all files living in the database. // GetFiles returns a list of all files living in the database.
func GetFiles() ([]EFile, error) { func GetFiles() ([]*EFile, error) {
if rows, err := DBQuery("SELECT id_file, id_exercice, origin, path, name, cksum, size FROM exercice_files"); err != nil { if rows, err := DBQuery("SELECT id_file, id_exercice, origin, path, name, cksum, size FROM exercice_files"); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var files = make([]EFile, 0) files := []*EFile{}
for rows.Next() { for rows.Next() {
var f EFile f := &EFile{}
if err := rows.Scan(&f.Id, &f.IdExercice, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.Size); err != nil { if err := rows.Scan(&f.Id, &f.IdExercice, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.Size); err != nil {
return nil, err return nil, err
} }
@ -68,16 +68,17 @@ func GetFiles() ([]EFile, error) {
} }
// GetFile retrieves the file with the given id. // GetFile retrieves the file with the given id.
func GetFile(id int64) (f EFile, err error) { func GetFile(id int64) (f *EFile, err error) {
f = &EFile{}
err = DBQueryRow("SELECT id_file, origin, path, name, cksum, size FROM exercice_files WHERE id_file = ?", id).Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.Size) err = DBQueryRow("SELECT id_file, origin, path, name, cksum, size FROM exercice_files WHERE id_file = ?", id).Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.Size)
return return
} }
// GetFileByPath retrieves the file that should be found at the given location. // GetFileByPath retrieves the file that should be found at the given location.
func GetFileByPath(path string) (EFile, error) { func GetFileByPath(path string) (*EFile, error) {
path = strings.TrimPrefix(path, FilesDir) path = strings.TrimPrefix(path, FilesDir)
var f EFile f := &EFile{}
if err := DBQueryRow("SELECT id_file, origin, path, id_exercice, name, cksum, size FROM exercice_files WHERE path = ?", path).Scan(&f.Id, &f.origin, &f.Path, &f.IdExercice, &f.Name, &f.Checksum, &f.Size); err != nil { if err := DBQueryRow("SELECT id_file, origin, path, id_exercice, name, cksum, size FROM exercice_files WHERE path = ?", path).Scan(&f.Id, &f.origin, &f.Path, &f.IdExercice, &f.Name, &f.Checksum, &f.Size); err != nil {
return f, err return f, err
} }
@ -86,24 +87,25 @@ func GetFileByPath(path string) (EFile, error) {
} }
// GetFileByFilename retrieves the file that should be called so. // GetFileByFilename retrieves the file that should be called so.
func (e Exercice) GetFileByFilename(filename string) (f EFile, err error) { func (e *Exercice) GetFileByFilename(filename string) (f *EFile, err error) {
filename = path.Base(filename) filename = path.Base(filename)
f = &EFile{}
err = DBQueryRow("SELECT id_file, origin, path, id_exercice, name, cksum, size FROM exercice_files WHERE id_exercice = ? AND origin LIKE ?", e.Id, "%/"+filename).Scan(&f.Id, &f.origin, &f.Path, &f.IdExercice, &f.Name, &f.Checksum, &f.Size) err = DBQueryRow("SELECT id_file, origin, path, id_exercice, name, cksum, size FROM exercice_files WHERE id_exercice = ? AND origin LIKE ?", e.Id, "%/"+filename).Scan(&f.Id, &f.origin, &f.Path, &f.IdExercice, &f.Name, &f.Checksum, &f.Size)
return return
} }
// GetFiles returns a list of files coming with the challenge. // GetFiles returns a list of files coming with the challenge.
func (e Exercice) GetFiles() ([]EFile, error) { func (e *Exercice) GetFiles() ([]*EFile, error) {
if rows, err := DBQuery("SELECT id_file, origin, path, name, cksum, size FROM exercice_files WHERE id_exercice = ?", e.Id); err != nil { if rows, err := DBQuery("SELECT id_file, origin, path, name, cksum, size FROM exercice_files WHERE id_exercice = ?", e.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var files = make([]EFile, 0) files := []*EFile{}
for rows.Next() { for rows.Next() {
var f EFile f := &EFile{}
f.IdExercice = e.Id f.IdExercice = e.Id
if err := rows.Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.Size); err != nil { if err := rows.Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.Size); err != nil {
return nil, err return nil, err
@ -119,12 +121,12 @@ func (e Exercice) GetFiles() ([]EFile, error) {
} }
// GetFileByPath retrieves the file that should be found at the given location, limited to the challenge files. // GetFileByPath retrieves the file that should be found at the given location, limited to the challenge files.
func (e Exercice) GetFileByPath(path string) (EFile, error) { func (e *Exercice) GetFileByPath(path string) (*EFile, error) {
path = strings.TrimPrefix(path, FilesDir) path = strings.TrimPrefix(path, FilesDir)
var f EFile f := &EFile{}
if err := DBQueryRow("SELECT id_file, origin, path, name, cksum, size FROM exercice_files WHERE id_exercice = ? AND path = ?", e.Id, path).Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.Size); err != nil { if err := DBQueryRow("SELECT id_file, origin, path, name, cksum, size FROM exercice_files WHERE id_exercice = ? AND path = ?", e.Id, path).Scan(&f.Id, &f.origin, &f.Path, &f.Name, &f.Checksum, &f.Size); err != nil {
return f, err return nil, err
} }
return f, nil return f, nil
@ -182,7 +184,7 @@ func CheckBufferHash(hash160 *hash.Hash, hash512 *hash.Hash, digest []byte) ([]b
// It also returns the file's size. // It also returns the file's size.
func checkFileHash(filePath string, digest []byte) (dgst []byte, size int64, err error) { func checkFileHash(filePath string, digest []byte) (dgst []byte, size int64, err error) {
if digest == nil { if digest == nil {
return []byte{}, 0, errors.New("No digest given.") return []byte{}, 0, errors.New("no digest given")
} else if fi, errr := os.Stat(filePath); errr != nil { } else if fi, errr := os.Stat(filePath); errr != nil {
return []byte{}, 0, errr return []byte{}, 0, errr
} else if fd, errr := os.Open(filePath); errr != nil { } else if fd, errr := os.Open(filePath); errr != nil {
@ -204,7 +206,7 @@ func checkFileHash(filePath string, digest []byte) (dgst []byte, size int64, err
} }
// ImportFile registers (ou updates if it already exists in database) the file in database. // ImportFile registers (ou updates if it already exists in database) the file in database.
func (e Exercice) ImportFile(filePath string, origin string, digest []byte) (interface{}, error) { func (e *Exercice) ImportFile(filePath string, origin string, digest []byte) (interface{}, error) {
if result512, size, err := checkFileHash(filePath, digest); !OptionalDigest && err != nil { if result512, size, err := checkFileHash(filePath, digest); !OptionalDigest && err != nil {
return EFile{}, err return EFile{}, err
} else { } else {
@ -229,18 +231,18 @@ func (e Exercice) ImportFile(filePath string, origin string, digest []byte) (int
} }
// AddFile creates and fills a new struct File and registers it into the database. // AddFile creates and fills a new struct File and registers it into the database.
func (e Exercice) AddFile(path string, origin string, name string, checksum []byte, size int64) (EFile, error) { func (e *Exercice) AddFile(path string, origin string, name string, checksum []byte, size int64) (*EFile, error) {
if res, err := DBExec("INSERT INTO exercice_files (id_exercice, origin, path, name, cksum, size) VALUES (?, ?, ?, ?, ?, ?)", e.Id, origin, path, name, checksum, size); err != nil { if res, err := DBExec("INSERT INTO exercice_files (id_exercice, origin, path, name, cksum, size) VALUES (?, ?, ?, ?, ?, ?)", e.Id, origin, path, name, checksum, size); err != nil {
return EFile{}, err return nil, err
} else if fid, err := res.LastInsertId(); err != nil { } else if fid, err := res.LastInsertId(); err != nil {
return EFile{}, err return nil, err
} else { } else {
return EFile{fid, origin, path, e.Id, name, checksum, size}, nil return &EFile{fid, origin, path, e.Id, name, checksum, size}, nil
} }
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (f EFile) Update() (int64, error) { func (f *EFile) Update() (int64, error) {
if res, err := DBExec("UPDATE exercice_files SET id_exercice = ?, origin = ?, path = ?, name = ?, cksum = ?, size = ? WHERE id_file = ?", f.IdExercice, f.origin, f.Path, f.Name, f.Checksum, f.Size, f.Id); err != nil { if res, err := DBExec("UPDATE exercice_files SET id_exercice = ?, origin = ?, path = ?, name = ?, cksum = ?, size = ? WHERE id_file = ?", f.IdExercice, f.origin, f.Path, f.Name, f.Checksum, f.Size, f.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -288,36 +290,36 @@ func ClearFiles() (int64, error) {
} }
// GetOrigin access the private field origin of the file. // GetOrigin access the private field origin of the file.
func (f EFile) GetOrigin() string { func (f *EFile) GetOrigin() string {
return f.origin return f.origin
} }
// AddDepend insert a new dependency to a given flag. // AddDepend insert a new dependency to a given flag.
func (f EFile) AddDepend(j Flag) (err error) { func (f *EFile) AddDepend(j Flag) (err error) {
if k, ok := j.(FlagKey); ok { if k, ok := j.(*FlagKey); ok {
_, err = DBExec("INSERT INTO exercice_files_okey_deps (id_file, id_flag) VALUES (?, ?)", f.Id, k.Id) _, err = DBExec("INSERT INTO exercice_files_okey_deps (id_file, id_flag) VALUES (?, ?)", f.Id, k.Id)
} else if m, ok := j.(MCQ); ok { } else if m, ok := j.(*MCQ); ok {
_, err = DBExec("INSERT INTO exercice_files_omcq_deps (id_file, id_mcq) VALUES (?, ?)", f.Id, m.Id) _, err = DBExec("INSERT INTO exercice_files_omcq_deps (id_file, id_mcq) VALUES (?, ?)", f.Id, m.Id)
} else { } else {
err = errors.New("Dependancy type not implemented for this file.") err = errors.New("dependancy type not implemented for this file")
} }
return return
} }
// DeleteDepend insert a new dependency to a given flag. // DeleteDepend insert a new dependency to a given flag.
func (f EFile) DeleteDepend(j Flag) (err error) { func (f *EFile) DeleteDepend(j Flag) (err error) {
if k, ok := j.(FlagKey); ok { if k, ok := j.(*FlagKey); ok {
_, err = DBExec("DELETE FROM exercice_files_okey_deps WHERE id_file = ? AND id_flag = ?", f.Id, k.Id) _, err = DBExec("DELETE FROM exercice_files_okey_deps WHERE id_file = ? AND id_flag = ?", f.Id, k.Id)
} else if m, ok := j.(MCQ); ok { } else if m, ok := j.(*MCQ); ok {
_, err = DBExec("DELETE FROM exercice_files_omcq_deps WHERE id_file = ? AND id_mcq = ?", f.Id, m.Id) _, err = DBExec("DELETE FROM exercice_files_omcq_deps WHERE id_file = ? AND id_mcq = ?", f.Id, m.Id)
} else { } else {
err = errors.New("Dependancy type not implemented for this file.") err = errors.New("dependancy type not implemented for this file")
} }
return return
} }
// GetDepends retrieve the flag's dependency list. // GetDepends retrieve the flag's dependency list.
func (f EFile) GetDepends() ([]Flag, error) { func (f *EFile) GetDepends() ([]Flag, error) {
var deps = make([]Flag, 0) var deps = make([]Flag, 0)
if rows, err := DBQuery("SELECT id_flag FROM exercice_files_okey_deps WHERE id_file = ?", f.Id); err != nil { if rows, err := DBQuery("SELECT id_flag FROM exercice_files_okey_deps WHERE id_file = ?", f.Id); err != nil {
@ -330,7 +332,7 @@ func (f EFile) GetDepends() ([]Flag, error) {
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
deps = append(deps, FlagKey{d, f.IdExercice, 0, "", "", "", "", "", false, false, nil, []byte{}, 0}) deps = append(deps, &FlagKey{d, f.IdExercice, 0, "", "", "", "", "", false, false, nil, []byte{}, 0})
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
return nil, err return nil, err
@ -347,7 +349,7 @@ func (f EFile) GetDepends() ([]Flag, error) {
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
deps = append(deps, MCQ{d, f.IdExercice, 0, "", []MCQ_entry{}}) deps = append(deps, &MCQ{d, f.IdExercice, 0, "", []*MCQ_entry{}})
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
return nil, err return nil, err
@ -358,11 +360,11 @@ func (f EFile) GetDepends() ([]Flag, error) {
} }
// CheckFileOnDisk recalculates the hash of the file on disk. // CheckFileOnDisk recalculates the hash of the file on disk.
func (f EFile) CheckFileOnDisk() error { func (f *EFile) CheckFileOnDisk() error {
if _, size, err := checkFileHash(path.Join(FilesDir, f.Path), f.Checksum); err != nil { if _, size, err := checkFileHash(path.Join(FilesDir, f.Path), f.Checksum); err != nil {
return err return err
} else if size == 0 { } else if size == 0 {
return errors.New("Empty file!") return errors.New("empty file")
} else { } else {
return nil return nil
} }

View file

@ -5,19 +5,19 @@ import ()
type Flag interface { type Flag interface {
GetId() int GetId() int
RecoverId() (Flag, error) RecoverId() (Flag, error)
Create(e Exercice) (Flag, error) Create(e *Exercice) (Flag, error)
Update() (int64, error) Update() (int64, error)
Delete() (int64, error) Delete() (int64, error)
AddDepend(d Flag) error AddDepend(d Flag) error
GetDepends() ([]Flag, error) GetDepends() ([]Flag, error)
GetOrder() int8 GetOrder() int8
Check(val interface{}) int Check(val interface{}) int
FoundBy(t Team) FoundBy(t *Team)
} }
// GetFlag returns a list of flags comming with the challenge. // GetFlag returns a list of flags comming with the challenge.
func (e Exercice) GetFlags() ([]Flag, error) { func (e *Exercice) GetFlags() ([]Flag, error) {
var flags = make([]Flag, 0) var flags []Flag
if ks, err := e.GetFlagKeys(); err != nil { if ks, err := e.GetFlagKeys(); err != nil {
return nil, err return nil, err
@ -39,12 +39,12 @@ func (e Exercice) GetFlags() ([]Flag, error) {
} }
// AddFlag add the given flag and eventually its entries (from MCQ). // AddFlag add the given flag and eventually its entries (from MCQ).
func (e Exercice) AddFlag(flag Flag) (f Flag, err error) { func (e *Exercice) AddFlag(flag Flag) (Flag, error) {
return flag.Create(e) return flag.Create(e)
} }
// WipeFlags deletes flags coming with the challenge. // WipeFlags deletes flags coming with the challenge.
func (e Exercice) WipeFlags() (int64, error) { func (e *Exercice) WipeFlags() (int64, error) {
if _, err := DBExec("DELETE FROM exercice_files_okey_deps WHERE id_flag IN (SELECT id_flag FROM exercice_flags WHERE id_exercice = ?)", e.Id); err != nil { if _, err := DBExec("DELETE FROM exercice_files_okey_deps WHERE id_flag IN (SELECT id_flag FROM exercice_flags WHERE id_exercice = ?)", e.Id); err != nil {
return 0, err return 0, err
} else 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 { } else 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 {

View file

@ -14,15 +14,15 @@ type FlagChoice struct {
} }
// GetChoices returns a list of choices for the given Flag. // GetChoices returns a list of choices for the given Flag.
func (f FlagKey) GetChoices() ([]FlagChoice, error) { func (f *FlagKey) GetChoices() ([]*FlagChoice, error) {
if rows, err := DBQuery("SELECT id_choice, id_flag, label, response FROM flag_choices WHERE id_flag = ?", f.Id); err != nil { if rows, err := DBQuery("SELECT id_choice, id_flag, label, response FROM flag_choices WHERE id_flag = ?", f.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var choices = make([]FlagChoice, 0) var choices []*FlagChoice
for rows.Next() { for rows.Next() {
var c FlagChoice c := &FlagChoice{}
c.IdFlag = f.Id c.IdFlag = f.Id
if err := rows.Scan(&c.Id, &c.IdFlag, &c.Label, &c.Value); err != nil { if err := rows.Scan(&c.Id, &c.IdFlag, &c.Label, &c.Value); err != nil {
@ -40,7 +40,8 @@ func (f FlagKey) GetChoices() ([]FlagChoice, error) {
} }
// GetChoice returns a choice for the given Flag. // GetChoice returns a choice for the given Flag.
func (f FlagKey) GetChoice(id int) (c FlagChoice, err error) { func (f *FlagKey) GetChoice(id int) (c *FlagChoice, err error) {
c = &FlagChoice{}
if errr := DBQueryRow("SELECT id_choice, id_flag, label, response FROM flag_choices WHERE id_choice = ?", id).Scan(&c.Id, &c.IdFlag, &c.Label, &c.Value); errr != nil { if errr := DBQueryRow("SELECT id_choice, id_flag, label, response FROM flag_choices WHERE id_choice = ?", id).Scan(&c.Id, &c.IdFlag, &c.Label, &c.Value); errr != nil {
return c, errr return c, errr
} }
@ -48,7 +49,7 @@ func (f FlagKey) GetChoice(id int) (c FlagChoice, err error) {
} }
// AddChoice creates and fills a new struct FlagChoice, from a label and a value. // AddChoice creates and fills a new struct FlagChoice, from a label and a value.
func (f FlagKey) AddChoice(c FlagChoice) (FlagChoice, error) { func (f *FlagKey) AddChoice(c *FlagChoice) (*FlagChoice, error) {
if res, err := DBExec("INSERT INTO flag_choices (id_flag, label, response) VALUES (?, ?, ?)", f.Id, c.Label, c.Value); err != nil { if res, err := DBExec("INSERT INTO flag_choices (id_flag, label, response) VALUES (?, ?, ?)", f.Id, c.Label, c.Value); err != nil {
return c, err return c, err
} else { } else {
@ -59,7 +60,7 @@ func (f FlagKey) AddChoice(c FlagChoice) (FlagChoice, error) {
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (c FlagChoice) Update() (int64, error) { func (c *FlagChoice) Update() (int64, error) {
if res, err := DBExec("UPDATE flag_choices SET id_flag = ?, label = ?, response = ? WHERE id_choice = ?", c.IdFlag, c.Label, c.Value, c.Id); err != nil { if res, err := DBExec("UPDATE flag_choices SET id_flag = ?, label = ?, response = ? WHERE id_choice = ?", c.IdFlag, c.Label, c.Value, c.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -70,7 +71,7 @@ func (c FlagChoice) Update() (int64, error) {
} }
// Delete the flag from the database. // Delete the flag from the database.
func (c FlagChoice) Delete() (int64, error) { func (c *FlagChoice) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM flag_choices WHERE id_choice = ?", c.Id); err != nil { if res, err := DBExec("DELETE FROM flag_choices WHERE id_choice = ?", c.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -81,7 +82,7 @@ func (c FlagChoice) Delete() (int64, error) {
} }
// WipeFlags deletes flags coming with the challenge. // WipeFlags deletes flags coming with the challenge.
func (f FlagKey) WipeChoices() (int64, error) { func (f *FlagKey) WipeChoices() (int64, error) {
if res, err := DBExec("DELETE FROM flag_choices WHERE id_flag = ?", f.Id); err != nil { if res, err := DBExec("DELETE FROM flag_choices WHERE id_flag = ?", f.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {

View file

@ -40,15 +40,15 @@ type FlagKey struct {
} }
// GetFlagKeys returns a list of key's flags comming with the challenge. // GetFlagKeys returns a list of key's flags comming with the challenge.
func (e Exercice) GetFlagKeys() ([]FlagKey, error) { func (e *Exercice) GetFlagKeys() ([]*FlagKey, error) {
if rows, err := DBQuery("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE id_exercice = ?", e.Id); err != nil { if rows, err := DBQuery("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE id_exercice = ?", e.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var flags = make([]FlagKey, 0) flags := []*FlagKey{}
for rows.Next() { for rows.Next() {
var k FlagKey k := &FlagKey{}
k.IdExercice = e.Id k.IdExercice = e.Id
if err := rows.Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost); err != nil { if err := rows.Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost); err != nil {
@ -66,13 +66,15 @@ func (e Exercice) GetFlagKeys() ([]FlagKey, error) {
} }
// GetFlagKey returns a list of flags comming with the challenge. // GetFlagKey returns a list of flags comming with the challenge.
func GetFlagKey(id int) (k FlagKey, err error) { func GetFlagKey(id int) (k *FlagKey, err error) {
k = &FlagKey{}
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE id_flag = ?", id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost) err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE id_flag = ?", id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost)
return return
} }
// GetFlagKeyByLabel returns a flag matching the given label. // GetFlagKeyByLabel returns a flag matching the given label.
func (e Exercice) GetFlagKeyByLabel(label string) (k FlagKey, err error) { func (e *Exercice) GetFlagKeyByLabel(label string) (k *FlagKey, err error) {
k = &FlagKey{}
err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE type LIKE ? AND id_exercice = ?", label, e.Id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost) err = DBQueryRow("SELECT id_flag, id_exercice, ordre, label, type, placeholder, help, unit, ignorecase, multiline, validator_regexp, cksum, choices_cost FROM exercice_flags WHERE type LIKE ? AND id_exercice = ?", label, e.Id).Scan(&k.Id, &k.IdExercice, &k.Order, &k.Label, &k.Type, &k.Placeholder, &k.Help, &k.Unit, &k.IgnoreCase, &k.Multiline, &k.ValidatorRegexp, &k.Checksum, &k.ChoicesCost)
return return
} }
@ -92,7 +94,7 @@ func ComputeHashedFlag(raw_value []byte, ignorecase bool, validator_regexp *stri
// Check that the value is not empty // Check that the value is not empty
if len(raw_value) == 0 { if len(raw_value) == 0 {
err = errors.New("Empty flag after applying filters") err = errors.New("empty flag after applying filters")
} }
hash = blake2b.Sum512(raw_value) hash = blake2b.Sum512(raw_value)
@ -106,20 +108,20 @@ func ExecValidatorRegexp(vre string, val []byte, ignorecase bool) ([]byte, error
if re, err := regexp.Compile(vre); err != nil { if re, err := regexp.Compile(vre); err != nil {
return val, err return val, err
} else if res := re.FindSubmatch(val); res == nil { } else if res := re.FindSubmatch(val); res == nil {
return val, errors.New("Expected flag doesn't pass through the validator_regexp") return val, errors.New("expected flag doesn't pass through the validator_regexp")
} else { } else {
return bytes.Join(res[1:], []byte("+")), nil return bytes.Join(res[1:], []byte("+")), nil
} }
} }
// AddRawFlagKey creates and fills a new struct FlagKey, from a non-hashed flag, and registers it into the database. // AddRawFlagKey creates and fills a new struct FlagKey, from a non-hashed flag, and registers it into the database.
func (e Exercice) AddRawFlagKey(name string, t string, placeholder string, ignorecase bool, multiline bool, validator_regexp *string, raw_value []byte, choicescost int64) (f FlagKey, err error) { func (e *Exercice) AddRawFlagKey(name string, t string, placeholder string, ignorecase bool, multiline bool, validator_regexp *string, raw_value []byte, choicescost int64) (*FlagKey, error) {
hash, errr := ComputeHashedFlag(raw_value, ignorecase, validator_regexp) hash, err := ComputeHashedFlag(raw_value, ignorecase, validator_regexp)
if errr != nil { if err != nil {
return f, err return nil, err
} }
f = FlagKey{ f := &FlagKey{
Type: t, Type: t,
Label: name, Label: name,
Placeholder: placeholder, Placeholder: placeholder,
@ -131,25 +133,25 @@ func (e Exercice) AddRawFlagKey(name string, t string, placeholder string, ignor
} }
_, err = f.Create(e) _, err = f.Create(e)
return return f, err
} }
// GetId returns the Flag identifier. // GetId returns the Flag identifier.
func (k FlagKey) GetId() int { func (k *FlagKey) GetId() int {
return k.Id return k.Id
} }
// RecoverId returns the Flag identifier as register in DB. // RecoverId returns the Flag identifier as register in DB.
func (k FlagKey) RecoverId() (Flag, error) { func (k *FlagKey) RecoverId() (Flag, error) {
if err := DBQueryRow("SELECT id_flag FROM exercice_flags WHERE label LIKE ? AND id_exercice = ?", k.Label, k.IdExercice).Scan(&k.Id); err != nil { if err := DBQueryRow("SELECT id_flag FROM exercice_flags WHERE label LIKE ? AND id_exercice = ?", k.Label, k.IdExercice).Scan(&k.Id); err != nil {
return FlagKey{}, err return nil, err
} else { } else {
return k, err return k, err
} }
} }
// AddFlagKey creates and fills a new struct Flag, from a hashed flag, and registers it into the database. // AddFlagKey creates and fills a new struct Flag, from a hashed flag, and registers it into the database.
func (k FlagKey) Create(e Exercice) (Flag, error) { func (k *FlagKey) Create(e *Exercice) (Flag, error) {
// Check the regexp compile // Check the regexp compile
if k.ValidatorRegexp != nil { if k.ValidatorRegexp != nil {
if _, err := regexp.Compile(*k.ValidatorRegexp); err != nil { if _, err := regexp.Compile(*k.ValidatorRegexp); err != nil {
@ -169,13 +171,13 @@ func (k FlagKey) Create(e Exercice) (Flag, error) {
} }
// ComputeChecksum calculates the checksum for a given value. // ComputeChecksum calculates the checksum for a given value.
func (k FlagKey) ComputeChecksum(val []byte) ([]byte, error) { func (k *FlagKey) ComputeChecksum(val []byte) ([]byte, error) {
cksum, err := ComputeHashedFlag(val, k.IgnoreCase, k.ValidatorRegexp) cksum, err := ComputeHashedFlag(val, k.IgnoreCase, k.ValidatorRegexp)
return cksum[:], err return cksum[:], err
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (k FlagKey) Update() (int64, error) { func (k *FlagKey) Update() (int64, error) {
if k.ValidatorRegexp != nil { if k.ValidatorRegexp != nil {
if _, err := regexp.Compile(*k.ValidatorRegexp); err != nil { if _, err := regexp.Compile(*k.ValidatorRegexp); err != nil {
return 0, err return 0, err
@ -192,7 +194,7 @@ func (k FlagKey) Update() (int64, error) {
} }
// Delete the flag from the database. // Delete the flag from the database.
func (k FlagKey) Delete() (int64, error) { func (k *FlagKey) Delete() (int64, error) {
if _, err := DBExec("DELETE FROM exercice_files_okey_deps WHERE id_flag = ?", k.Id); err != nil { if _, err := DBExec("DELETE FROM exercice_files_okey_deps WHERE id_flag = ?", k.Id); err != nil {
return 0, err return 0, err
} else if _, err := DBExec("DELETE FROM exercice_mcq_okey_deps WHERE id_flag_dep = ?", k.Id); err != nil { } else if _, err := DBExec("DELETE FROM exercice_mcq_okey_deps WHERE id_flag_dep = ?", k.Id); err != nil {
@ -214,25 +216,25 @@ func (k FlagKey) Delete() (int64, error) {
} }
} }
func (k FlagKey) GetOrder() int8 { func (k *FlagKey) GetOrder() int8 {
return k.Order return k.Order
} }
// AddDepend insert a new dependency to a given flag. // AddDepend insert a new dependency to a given flag.
func (k FlagKey) AddDepend(j Flag) (err error) { func (k *FlagKey) AddDepend(j Flag) (err error) {
if d, ok := j.(FlagKey); ok { if d, ok := j.(*FlagKey); ok {
_, err = DBExec("INSERT INTO exercice_flags_deps (id_flag, id_flag_dep) VALUES (?, ?)", k.Id, d.Id) _, err = DBExec("INSERT INTO exercice_flags_deps (id_flag, id_flag_dep) VALUES (?, ?)", k.Id, d.Id)
} else if d, ok := j.(MCQ); ok { } else if d, ok := j.(*MCQ); ok {
_, err = DBExec("INSERT INTO exercice_flags_omcq_deps (id_flag, id_mcq_dep) VALUES (?, ?)", k.Id, d.Id) _, err = DBExec("INSERT INTO exercice_flags_omcq_deps (id_flag, id_mcq_dep) VALUES (?, ?)", k.Id, d.Id)
} else { } else {
err = fmt.Errorf("Dependancy type for key (%T) not implemented for this flag.", j) err = fmt.Errorf("dependancy type for key (%T) not implemented for this flag", j)
} }
return return
} }
// GetDepends retrieve the flag's dependency list. // GetDepends retrieve the flag's dependency list.
func (k FlagKey) GetDepends() ([]Flag, error) { func (k *FlagKey) GetDepends() ([]Flag, error) {
var deps = make([]Flag, 0) var deps []Flag
if rows, err := DBQuery("SELECT id_flag_dep FROM exercice_flags_deps WHERE id_flag = ?", k.Id); err != nil { if rows, err := DBQuery("SELECT id_flag_dep FROM exercice_flags_deps WHERE id_flag = ?", k.Id); err != nil {
return nil, err return nil, err
@ -244,7 +246,7 @@ func (k FlagKey) GetDepends() ([]Flag, error) {
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
deps = append(deps, FlagKey{Id: d, IdExercice: k.IdExercice}) deps = append(deps, &FlagKey{Id: d, IdExercice: k.IdExercice})
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
return nil, err return nil, err
@ -261,7 +263,7 @@ func (k FlagKey) GetDepends() ([]Flag, error) {
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
deps = append(deps, MCQ{Id: d, IdExercice: k.IdExercice}) deps = append(deps, &MCQ{Id: d, IdExercice: k.IdExercice})
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
return nil, err return nil, err
@ -272,7 +274,7 @@ func (k FlagKey) GetDepends() ([]Flag, error) {
} }
// Check if the given val is the expected one for this flag. // Check if the given val is the expected one for this flag.
func (k FlagKey) Check(v interface{}) int { func (k *FlagKey) Check(v interface{}) int {
var val []byte var val []byte
if va, ok := v.([]byte); !ok { if va, ok := v.([]byte); !ok {
@ -299,15 +301,15 @@ func (k FlagKey) Check(v interface{}) int {
} }
// FoundBy registers in the database that the given Team solved the flag. // FoundBy registers in the database that the given Team solved the flag.
func (k FlagKey) FoundBy(t Team) { func (k *FlagKey) FoundBy(t *Team) {
DBExec("INSERT INTO flag_found (id_flag, id_team, time) VALUES (?, ?, ?)", k.Id, t.Id, time.Now()) DBExec("INSERT INTO flag_found (id_flag, id_team, time) VALUES (?, ?, ?)", k.Id, t.Id, time.Now())
} }
// GetExercice returns the parent Exercice where this flag can be found. // GetExercice returns the parent Exercice where this flag can be found.
func (k FlagKey) GetExercice() (Exercice, error) { func (k *FlagKey) GetExercice() (*Exercice, error) {
var eid int64 var eid int64
if err := DBQueryRow("SELECT id_exercice FROM exercice_flags WHERE id_flag = ?", k.Id).Scan(&eid); err != nil { if err := DBQueryRow("SELECT id_exercice FROM exercice_flags WHERE id_flag = ?", k.Id).Scan(&eid); err != nil {
return Exercice{}, err return nil, err
} }
return GetExercice(eid) return GetExercice(eid)

View file

@ -36,42 +36,42 @@ func treatHintContent(h *EHint) {
} }
// GetHint retrieves the hint with the given id. // GetHint retrieves the hint with the given id.
func GetHint(id int64) (EHint, error) { func GetHint(id int64) (*EHint, error) {
var h EHint h := &EHint{}
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 { 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 {
return h, err return nil, err
} }
treatHintContent(&h) treatHintContent(h)
return h, nil return h, nil
} }
// GetHintByTitle retrieves the hint with the given id. // GetHintByTitle retrieves the hint with the given id.
func (e Exercice) GetHintByTitle(id int64) (EHint, error) { func (e *Exercice) GetHintByTitle(id int64) (*EHint, error) {
var h EHint h := &EHint{}
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 { 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 {
return h, err return nil, err
} }
treatHintContent(&h) treatHintContent(h)
return h, nil return h, nil
} }
// GetHints returns a list of hints comming with the challenge. // GetHints returns a list of hints comming with the challenge.
func (e Exercice) GetHints() ([]EHint, error) { func (e *Exercice) GetHints() ([]*EHint, error) {
if rows, err := DBQuery("SELECT id_hint, title, content, cost FROM exercice_hints WHERE id_exercice = ?", e.Id); err != nil { if rows, err := DBQuery("SELECT id_hint, title, content, cost FROM exercice_hints WHERE id_exercice = ?", e.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var hints = make([]EHint, 0) var hints []*EHint
for rows.Next() { for rows.Next() {
var h EHint h := &EHint{}
h.IdExercice = e.Id h.IdExercice = e.Id
if err := rows.Scan(&h.Id, &h.Title, &h.Content, &h.Cost); err != nil { if err := rows.Scan(&h.Id, &h.Title, &h.Content, &h.Cost); err != nil {
return nil, err return nil, err
} }
treatHintContent(&h) treatHintContent(h)
hints = append(hints, h) hints = append(hints, h)
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
@ -83,18 +83,18 @@ func (e Exercice) GetHints() ([]EHint, error) {
} }
// AddHint creates and fills a new struct EHint and registers it into the database. // AddHint creates and fills a new struct EHint and registers it into the database.
func (e Exercice) AddHint(title string, content string, cost int64) (EHint, error) { func (e *Exercice) AddHint(title string, content string, cost int64) (*EHint, error) {
if res, err := DBExec("INSERT INTO exercice_hints (id_exercice, title, content, cost) VALUES (?, ?, ?, ?)", e.Id, title, content, cost); err != nil { if res, err := DBExec("INSERT INTO exercice_hints (id_exercice, title, content, cost) VALUES (?, ?, ?, ?)", e.Id, title, content, cost); err != nil {
return EHint{}, err return nil, err
} else if hid, err := res.LastInsertId(); err != nil { } else if hid, err := res.LastInsertId(); err != nil {
return EHint{}, err return nil, err
} else { } else {
return EHint{hid, e.Id, title, content, "", cost}, nil return &EHint{hid, e.Id, title, content, "", cost}, nil
} }
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (h EHint) Update() (int64, error) { func (h *EHint) Update() (int64, error) {
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 { 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 return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -105,7 +105,7 @@ func (h EHint) Update() (int64, error) {
} }
// Delete the hint from the database. // Delete the hint from the database.
func (h EHint) Delete() (int64, error) { func (h *EHint) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM exercice_hints WHERE id_hint = ?", h.Id); err != nil { if res, err := DBExec("DELETE FROM exercice_hints WHERE id_hint = ?", h.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -116,7 +116,7 @@ func (h EHint) Delete() (int64, error) {
} }
// WipeHints deletes (only in the database, not on disk) hints coming with the challenge. // WipeHints deletes (only in the database, not on disk) hints coming with the challenge.
func (e Exercice) WipeHints() (int64, error) { func (e *Exercice) WipeHints() (int64, error) {
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 { 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 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 { } 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 {
@ -131,20 +131,20 @@ func (e Exercice) WipeHints() (int64, error) {
} }
// AddDepend insert a new dependency to a given flag. // AddDepend insert a new dependency to a given flag.
func (h EHint) AddDepend(f Flag) (err error) { func (h *EHint) AddDepend(f Flag) (err error) {
if d, ok := f.(FlagKey); ok { if d, ok := f.(*FlagKey); ok {
_, err = DBExec("INSERT INTO exercice_hints_okey_deps (id_hint, id_flag_dep) VALUES (?, ?)", h.Id, d.Id) _, err = DBExec("INSERT INTO exercice_hints_okey_deps (id_hint, id_flag_dep) VALUES (?, ?)", h.Id, d.Id)
} else if d, ok := f.(MCQ); ok { } else if d, ok := f.(*MCQ); ok {
_, err = DBExec("INSERT INTO exercice_hints_omcq_deps (id_hint, id_mcq_dep) VALUES (?, ?)", h.Id, d.Id) _, err = DBExec("INSERT INTO exercice_hints_omcq_deps (id_hint, id_mcq_dep) VALUES (?, ?)", h.Id, d.Id)
} else { } else {
err = fmt.Errorf("Dependancy type for key (%T) not implemented for this flag.", f) err = fmt.Errorf("dependancy type for key (%T) not implemented for this flag", f)
} }
return return
} }
// GetDepends retrieve the flag's dependency list. // GetDepends retrieve the flag's dependency list.
func (h EHint) GetDepends() ([]Flag, error) { func (h *EHint) GetDepends() ([]Flag, error) {
var deps = make([]Flag, 0) var deps []Flag
if rows, err := DBQuery("SELECT id_flag_dep FROM exercice_hints_okey_deps WHERE id_hint = ?", h.Id); err != nil { if rows, err := DBQuery("SELECT id_flag_dep FROM exercice_hints_okey_deps WHERE id_hint = ?", h.Id); err != nil {
return nil, err return nil, err
@ -156,7 +156,7 @@ func (h EHint) GetDepends() ([]Flag, error) {
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
deps = append(deps, FlagKey{Id: d, IdExercice: h.IdExercice}) deps = append(deps, &FlagKey{Id: d, IdExercice: h.IdExercice})
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
return nil, err return nil, err
@ -173,7 +173,7 @@ func (h EHint) GetDepends() ([]Flag, error) {
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
deps = append(deps, MCQ{Id: d, IdExercice: h.IdExercice}) deps = append(deps, &MCQ{Id: d, IdExercice: h.IdExercice})
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
return nil, err return nil, err
@ -184,10 +184,10 @@ func (h EHint) GetDepends() ([]Flag, error) {
} }
// GetExercice returns the parent Exercice where this hint can be found. // GetExercice returns the parent Exercice where this hint can be found.
func (h EHint) GetExercice() (Exercice, error) { func (h *EHint) GetExercice() (*Exercice, error) {
var eid int64 var eid int64
if err := DBQueryRow("SELECT id_exercice FROM exercice_hints WHERE id_hint = ?", h.Id).Scan(&eid); err != nil { if err := DBQueryRow("SELECT id_exercice FROM exercice_hints WHERE id_hint = ?", h.Id).Scan(&eid); err != nil {
return Exercice{}, err return nil, err
} }
return GetExercice(eid) return GetExercice(eid)

View file

@ -16,7 +16,7 @@ type MCQ struct {
// Title is the label of the question // Title is the label of the question
Title string `json:"title"` Title string `json:"title"`
// Entries stores the set of proposed answers // Entries stores the set of proposed answers
Entries []MCQ_entry `json:"entries"` Entries []*MCQ_entry `json:"entries"`
} }
// MCQ_entry represents a proposed response for a given MCQ. // MCQ_entry represents a proposed response for a given MCQ.
@ -29,20 +29,21 @@ type MCQ_entry struct {
} }
// GetMCQ returns a list of flags comming with the challenge. // GetMCQ returns a list of flags comming with the challenge.
func GetMCQ(id int) (m MCQ, err error) { func GetMCQ(id int) (m *MCQ, err error) {
m = &MCQ{}
err = DBQueryRow("SELECT id_mcq, id_exercice, order, title FROM exercice_mcq WHERE id_mcq = ?", id).Scan(&m.Id, &m.IdExercice, &m.Order, &m.Title) err = DBQueryRow("SELECT id_mcq, id_exercice, order, title FROM exercice_mcq WHERE id_mcq = ?", id).Scan(&m.Id, &m.IdExercice, &m.Order, &m.Title)
m.fillEntries() m.fillEntries()
return return
} }
func (m *MCQ) fillEntries() ([]MCQ_entry, error) { func (m *MCQ) fillEntries() ([]*MCQ_entry, error) {
if entries_rows, err := DBQuery("SELECT id_mcq_entry, label, response FROM mcq_entries WHERE id_mcq = ?", m.Id); err != nil { if entries_rows, err := DBQuery("SELECT id_mcq_entry, label, response FROM mcq_entries WHERE id_mcq = ?", m.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer entries_rows.Close() defer entries_rows.Close()
for entries_rows.Next() { for entries_rows.Next() {
var e MCQ_entry e := &MCQ_entry{}
if err := entries_rows.Scan(&e.Id, &e.Label, &e.Response); err != nil { if err := entries_rows.Scan(&e.Id, &e.Label, &e.Response); err != nil {
return nil, err return nil, err
@ -56,15 +57,15 @@ func (m *MCQ) fillEntries() ([]MCQ_entry, error) {
} }
// GetMCQ returns the MCQs coming with the challenge. // GetMCQ returns the MCQs coming with the challenge.
func (e Exercice) GetMCQ() ([]MCQ, error) { func (e *Exercice) GetMCQ() ([]*MCQ, error) {
if rows, err := DBQuery("SELECT id_mcq, id_exercice, ordre, title FROM exercice_mcq WHERE id_exercice = ?", e.Id); err != nil { if rows, err := DBQuery("SELECT id_mcq, id_exercice, ordre, title FROM exercice_mcq WHERE id_exercice = ?", e.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var mcqs = make([]MCQ, 0) var mcqs = []*MCQ{}
for rows.Next() { for rows.Next() {
var m MCQ m := &MCQ{}
m.IdExercice = e.Id m.IdExercice = e.Id
if err := rows.Scan(&m.Id, &m.IdExercice, &m.Order, &m.Title); err != nil { if err := rows.Scan(&m.Id, &m.IdExercice, &m.Order, &m.Title); err != nil {
@ -84,18 +85,19 @@ func (e Exercice) GetMCQ() ([]MCQ, error) {
} }
// GetMCQbyChoice returns the MCQ corresponding to a choice ID. // GetMCQbyChoice returns the MCQ corresponding to a choice ID.
func GetMCQbyChoice(cid int) (m MCQ, c MCQ_entry, err error) { func GetMCQbyChoice(cid int) (m *MCQ, c *MCQ_entry, err error) {
m = &MCQ{}
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 { 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 {
return MCQ{}, MCQ_entry{}, errr return nil, nil, errr
} }
if entries_rows, errr := DBQuery("SELECT id_mcq_entry, label, response FROM mcq_entries WHERE id_mcq = ?", m.Id); errr != nil { if entries_rows, errr := DBQuery("SELECT id_mcq_entry, label, response FROM mcq_entries WHERE id_mcq = ?", m.Id); errr != nil {
return MCQ{}, MCQ_entry{}, errr return nil, nil, errr
} else { } else {
defer entries_rows.Close() defer entries_rows.Close()
for entries_rows.Next() { for entries_rows.Next() {
var e MCQ_entry e := &MCQ_entry{}
if err = entries_rows.Scan(&e.Id, &e.Label, &e.Response); err != nil { if err = entries_rows.Scan(&e.Id, &e.Label, &e.Response); err != nil {
return return
@ -113,21 +115,21 @@ func GetMCQbyChoice(cid int) (m MCQ, c MCQ_entry, err error) {
} }
// GetId returns the MCQ identifier. // GetId returns the MCQ identifier.
func (m MCQ) GetId() int { func (m *MCQ) GetId() int {
return m.Id return m.Id
} }
// RecoverId returns the MCQ identifier as register in DB. // RecoverId returns the MCQ identifier as register in DB.
func (m MCQ) RecoverId() (Flag, error) { func (m *MCQ) RecoverId() (Flag, error) {
if err := DBQueryRow("SELECT id_mcq FROM exercice_mcq WHERE title LIKE ? AND id_exercice = ?", m.Title, m.IdExercice).Scan(&m.Id); err != nil { if err := DBQueryRow("SELECT id_mcq FROM exercice_mcq WHERE title LIKE ? AND id_exercice = ?", m.Title, m.IdExercice).Scan(&m.Id); err != nil {
return MCQ{}, err return nil, err
} else { } else {
return m, err return m, err
} }
} }
// Create registers a MCQ into the database and recursively add its entries. // Create registers a MCQ into the database and recursively add its entries.
func (m MCQ) Create(e Exercice) (Flag, error) { func (m *MCQ) Create(e *Exercice) (Flag, error) {
if res, err := DBExec("INSERT INTO exercice_mcq (id_exercice, ordre, title) VALUES (?, ?, ?)", e.Id, m.Order, m.Title); err != nil { if res, err := DBExec("INSERT INTO exercice_mcq (id_exercice, ordre, title) VALUES (?, ?, ?)", e.Id, m.Order, m.Title); err != nil {
return m, err return m, err
} else if qid, err := res.LastInsertId(); err != nil { } else if qid, err := res.LastInsertId(); err != nil {
@ -150,7 +152,7 @@ func (m MCQ) Create(e Exercice) (Flag, error) {
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (m MCQ) Update() (int64, error) { func (m *MCQ) Update() (int64, error) {
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 { 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 {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -161,7 +163,7 @@ func (m MCQ) Update() (int64, error) {
} }
// Delete the MCQ from the database. // Delete the MCQ from the database.
func (m MCQ) Delete() (int64, error) { func (m *MCQ) Delete() (int64, error) {
if _, err := DBExec("DELETE FROM exercice_files_omcq_deps WHERE id_mcq = ?", m.Id); err != nil { if _, err := DBExec("DELETE FROM exercice_files_omcq_deps WHERE id_mcq = ?", m.Id); err != nil {
return 0, err return 0, err
} else if _, err := DBExec("DELETE FROM exercice_mcq_okey_deps WHERE id_mcq = ?", m.Id); err != nil { } else if _, err := DBExec("DELETE FROM exercice_mcq_okey_deps WHERE id_mcq = ?", m.Id); err != nil {
@ -184,7 +186,7 @@ func (m MCQ) Delete() (int64, error) {
} }
// AddEntry creates and fills a new struct MCQ_entry and registers it into the database. // AddEntry creates and fills a new struct MCQ_entry and registers it into the database.
func (m MCQ) AddEntry(e MCQ_entry) (MCQ_entry, error) { func (m *MCQ) AddEntry(e *MCQ_entry) (*MCQ_entry, error) {
if res, err := DBExec("INSERT INTO mcq_entries (id_mcq, label, response) VALUES (?, ?, ?)", m.Id, e.Label, e.Response); err != nil { if res, err := DBExec("INSERT INTO mcq_entries (id_mcq, label, response) VALUES (?, ?, ?)", m.Id, e.Label, e.Response); err != nil {
return e, err return e, err
} else if nid, err := res.LastInsertId(); err != nil { } else if nid, err := res.LastInsertId(); err != nil {
@ -196,7 +198,7 @@ func (m MCQ) AddEntry(e MCQ_entry) (MCQ_entry, error) {
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (n MCQ_entry) Update() (int64, error) { func (n *MCQ_entry) Update() (int64, error) {
if res, err := DBExec("UPDATE mcq_entries SET label = ?, response = ? WHERE id_mcq = ?", n.Label, n.Response, n.Id); err != nil { if res, err := DBExec("UPDATE mcq_entries SET label = ?, response = ? WHERE id_mcq = ?", n.Label, n.Response, n.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -207,7 +209,7 @@ func (n MCQ_entry) Update() (int64, error) {
} }
// Delete the MCQ entry from the database. // Delete the MCQ entry from the database.
func (n MCQ_entry) Delete() (int64, error) { func (n *MCQ_entry) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM mcq_entries WHERE id_mcq_entry = ?", n.Id); err != nil { if res, err := DBExec("DELETE FROM mcq_entries WHERE id_mcq_entry = ?", n.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -218,7 +220,7 @@ func (n MCQ_entry) Delete() (int64, error) {
} }
// WipeMCQs deletes MCQs coming with the challenge. // WipeMCQs deletes MCQs coming with the challenge.
func (e Exercice) WipeMCQs() (int64, error) { func (e *Exercice) WipeMCQs() (int64, error) {
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 { 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 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 { } 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 {
@ -240,25 +242,25 @@ func (e Exercice) WipeMCQs() (int64, error) {
} }
} }
func (m MCQ) GetOrder() int8 { func (m *MCQ) GetOrder() int8 {
return m.Order return m.Order
} }
// AddDepend insert a new dependency to a given flag. // AddDepend insert a new dependency to a given flag.
func (m MCQ) AddDepend(j Flag) (err error) { func (m *MCQ) AddDepend(j Flag) (err error) {
if d, ok := j.(FlagKey); ok { if d, ok := j.(*FlagKey); ok {
_, err = DBExec("INSERT INTO exercice_mcq_okey_deps (id_mcq, id_flag_dep) VALUES (?, ?)", m.Id, d.Id) _, err = DBExec("INSERT INTO exercice_mcq_okey_deps (id_mcq, id_flag_dep) VALUES (?, ?)", m.Id, d.Id)
} else if d, ok := j.(MCQ); ok { } else if d, ok := j.(*MCQ); ok {
_, err = DBExec("INSERT INTO exercice_mcq_omcq_deps (id_mcq, id_mcq_dep) VALUES (?, ?)", m.Id, d.Id) _, err = DBExec("INSERT INTO exercice_mcq_omcq_deps (id_mcq, id_mcq_dep) VALUES (?, ?)", m.Id, d.Id)
} else { } else {
err = errors.New("Dependancy type not implemented for this flag.") err = errors.New("dependancy type not implemented for this flag")
} }
return return
} }
// GetDepends retrieve the flag's dependency list. // GetDepends retrieve the flag's dependency list.
func (m MCQ) GetDepends() ([]Flag, error) { func (m *MCQ) GetDepends() ([]Flag, error) {
var deps = make([]Flag, 0) deps := []Flag{}
if rows, err := DBQuery("SELECT id_flag_dep FROM exercice_mcq_okey_deps WHERE id_mcq = ?", m.Id); err != nil { if rows, err := DBQuery("SELECT id_flag_dep FROM exercice_mcq_okey_deps WHERE id_mcq = ?", m.Id); err != nil {
return nil, err return nil, err
@ -270,7 +272,7 @@ func (m MCQ) GetDepends() ([]Flag, error) {
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
deps = append(deps, FlagKey{Id: d, IdExercice: m.IdExercice}) deps = append(deps, &FlagKey{Id: d, IdExercice: m.IdExercice})
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
return nil, err return nil, err
@ -288,7 +290,7 @@ func (m MCQ) GetDepends() ([]Flag, error) {
if err := rows.Scan(&d); err != nil { if err := rows.Scan(&d); err != nil {
return nil, err return nil, err
} }
deps = append(deps, MCQ{Id: d, IdExercice: m.IdExercice}) deps = append(deps, &MCQ{Id: d, IdExercice: m.IdExercice})
} }
if err := rows.Err(); err != nil { if err := rows.Err(); err != nil {
return nil, err return nil, err
@ -300,12 +302,12 @@ func (m MCQ) GetDepends() ([]Flag, error) {
} }
// GetJustifiedFlag searchs for a flag in the scope of the given exercice. // GetJustifiedFlag searchs for a flag in the scope of the given exercice.
func (c MCQ_entry) GetJustifiedFlag(e Exercice) (FlagKey, error) { func (c *MCQ_entry) GetJustifiedFlag(e *Exercice) (*FlagKey, error) {
return e.GetFlagKeyByLabel(fmt.Sprintf("\\%%%d\\%%%%", c.Id)) return e.GetFlagKeyByLabel(fmt.Sprintf("\\%%%d\\%%%%", c.Id))
} }
// Check if the given vals are the expected ones to validate this flag. // Check if the given vals are the expected ones to validate this flag.
func (m MCQ) Check(v interface{}) int { func (m *MCQ) Check(v interface{}) int {
var vals map[int]bool var vals map[int]bool
if va, ok := v.(map[int]bool); !ok { if va, ok := v.(map[int]bool); !ok {
return -1 return -1
@ -326,6 +328,6 @@ func (m MCQ) Check(v interface{}) int {
} }
// FoundBy registers in the database that the given Team solved the MCQ. // FoundBy registers in the database that the given Team solved the MCQ.
func (m MCQ) FoundBy(t Team) { func (m *MCQ) FoundBy(t *Team) {
DBExec("INSERT INTO mcq_found (id_mcq, id_team, time) VALUES (?, ?, ?)", m.Id, t.Id, time.Now()) DBExec("INSERT INTO mcq_found (id_mcq, id_team, time) VALUES (?, ?, ?)", m.Id, t.Id, time.Now())
} }

View file

@ -25,7 +25,7 @@ func (k FlagKey) GetMCQJustification() (fl FlagLabel, err error) {
fl.IdChoice = int(idChoice) fl.IdChoice = int(idChoice)
fl.Label = strings.Join(spl[2:], "%") fl.Label = strings.Join(spl[2:], "%")
} else { } else {
err = errors.New("This is not a MCQ justification") err = errors.New("this is not a MCQ justification")
} }
return return
} }

View file

@ -12,15 +12,15 @@ type Member struct {
} }
// GetMembers retrieves the members of the Team // GetMembers retrieves the members of the Team
func (t Team) GetMembers() ([]Member, error) { func (t *Team) GetMembers() ([]*Member, error) {
if rows, err := DBQuery("SELECT id_member, firstname, lastname, nickname, company FROM team_members WHERE id_team = ?", t.Id); err != nil { if rows, err := DBQuery("SELECT id_member, firstname, lastname, nickname, company FROM team_members WHERE id_team = ?", t.Id); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var members = make([]Member, 0) var members []*Member
for rows.Next() { for rows.Next() {
var m Member m := &Member{}
if err := rows.Scan(&m.Id, &m.Firstname, &m.Lastname, &m.Nickname, &m.Company); err != nil { if err := rows.Scan(&m.Id, &m.Firstname, &m.Lastname, &m.Nickname, &m.Company); err != nil {
return nil, err return nil, err
} }
@ -35,18 +35,18 @@ func (t Team) GetMembers() ([]Member, error) {
} }
// AddMember creates and fills a new struct Member and registers it into the database. // AddMember creates and fills a new struct Member and registers it into the database.
func (t Team) AddMember(firstname string, lastname string, nickname string, company string) (Member, error) { func (t *Team) AddMember(firstname string, lastname string, nickname string, company string) (*Member, error) {
if res, err := DBExec("INSERT INTO team_members (id_team, firstname, lastname, nickname, company) VALUES (?, ?, ?, ?, ?)", t.Id, firstname, lastname, nickname, company); err != nil { if res, err := DBExec("INSERT INTO team_members (id_team, firstname, lastname, nickname, company) VALUES (?, ?, ?, ?, ?)", t.Id, firstname, lastname, nickname, company); err != nil {
return Member{}, err return nil, err
} else if mid, err := res.LastInsertId(); err != nil { } else if mid, err := res.LastInsertId(); err != nil {
return Member{}, err return nil, err
} else { } else {
return Member{mid, firstname, lastname, nickname, company}, nil return &Member{mid, firstname, lastname, nickname, company}, nil
} }
} }
// GainMember associates (or registers, it if it doesn't exists yet) a member to the team. // GainMember associates (or registers, it if it doesn't exists yet) a member to the team.
func (t Team) GainMember(m Member) error { func (t *Team) GainMember(m *Member) error {
if m.Id == 0 { if m.Id == 0 {
if res, err := DBExec("INSERT INTO team_members (id_team, firstname, lastname, nickname, company) VALUES (?, ?, ?, ?, ?)", t.Id, m.Firstname, m.Lastname, m.Nickname, m.Company); err != nil { if res, err := DBExec("INSERT INTO team_members (id_team, firstname, lastname, nickname, company) VALUES (?, ?, ?, ?, ?)", t.Id, m.Firstname, m.Lastname, m.Nickname, m.Company); err != nil {
return err return err
@ -65,7 +65,7 @@ func (t Team) GainMember(m Member) error {
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (m Member) Update() (int64, error) { func (m *Member) Update() (int64, error) {
if res, err := DBExec("UPDATE team_members SET firstname = ?, lastname = ?, nickname = ?, company = ? WHERE id_member = ?", m.Firstname, m.Lastname, m.Nickname, m.Company, m.Id); err != nil { if res, err := DBExec("UPDATE team_members SET firstname = ?, lastname = ?, nickname = ?, company = ? WHERE id_member = ?", m.Firstname, m.Lastname, m.Nickname, m.Company, m.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -76,7 +76,7 @@ func (m Member) Update() (int64, error) {
} }
// Delete the member from the database. // Delete the member from the database.
func (m Member) Delete() (int64, error) { func (m *Member) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM team_members WHERE id_member = ?", m.Id); err != nil { if res, err := DBExec("DELETE FROM team_members WHERE id_member = ?", m.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -87,7 +87,7 @@ func (m Member) Delete() (int64, error) {
} }
// ClearMembers deletes members in the team. // ClearMembers deletes members in the team.
func (t Team) ClearMembers() (int64, error) { func (t *Team) ClearMembers() (int64, error) {
if res, err := DBExec("DELETE FROM team_members WHERE id_team = ?", t.Id); err != nil { if res, err := DBExec("DELETE FROM team_members WHERE id_team = ?", t.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {

View file

@ -19,13 +19,14 @@ type QAQuery struct {
} }
// GetQAQuery retrieves the query with the given identifier. // GetQAQuery retrieves the query with the given identifier.
func GetQAQuery(id int64) (q QAQuery, err error) { func GetQAQuery(id int64) (q *QAQuery, err error) {
q = &QAQuery{}
err = DBQueryRow("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa WHERE id_qa = ?", id).Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed) err = DBQueryRow("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa WHERE id_qa = ?", id).Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed)
return return
} }
// GetQAQueries returns a list of all QAQuery registered in the database. // GetQAQueries returns a list of all QAQuery registered in the database.
func GetQAQueries() (res []QAQuery, err error) { func GetQAQueries() (res []*QAQuery, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa"); err != nil { if rows, err = DBQuery("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa"); err != nil {
return return
@ -33,7 +34,7 @@ func GetQAQueries() (res []QAQuery, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var q QAQuery q := &QAQuery{}
if err = rows.Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed); err != nil { if err = rows.Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed); err != nil {
return return
} }
@ -45,7 +46,7 @@ func GetQAQueries() (res []QAQuery, err error) {
} }
// GetQAQueries returns a list of all QAQuery registered for the Exercice. // GetQAQueries returns a list of all QAQuery registered for the Exercice.
func (e Exercice) GetQAQueries() (res []QAQuery, err error) { func (e *Exercice) GetQAQueries() (res []*QAQuery, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa WHERE id_exercice = ?", e.Id); err != nil { if rows, err = DBQuery("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa WHERE id_exercice = ?", e.Id); err != nil {
return nil, err return nil, err
@ -53,7 +54,7 @@ func (e Exercice) GetQAQueries() (res []QAQuery, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var q QAQuery q := &QAQuery{}
if err = rows.Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed); err != nil { if err = rows.Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed); err != nil {
return return
} }
@ -65,7 +66,7 @@ func (e Exercice) GetQAQueries() (res []QAQuery, err error) {
} }
// GetQAQueries returns a list of all QAQuery registered for the Exercice. // GetQAQueries returns a list of all QAQuery registered for the Exercice.
func (t Team) GetQAQueries() (res []QAQuery, err error) { func (t *Team) GetQAQueries() (res []*QAQuery, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa WHERE id_team = ?", t.Id); err != nil { if rows, err = DBQuery("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa WHERE id_team = ?", t.Id); err != nil {
return nil, err return nil, err
@ -73,7 +74,7 @@ func (t Team) GetQAQueries() (res []QAQuery, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var q QAQuery q := &QAQuery{}
if err = rows.Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed); err != nil { if err = rows.Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed); err != nil {
return return
} }
@ -85,24 +86,25 @@ func (t Team) GetQAQueries() (res []QAQuery, err error) {
} }
// GetQAQuery retrieves the query with the given identifier. // GetQAQuery retrieves the query with the given identifier.
func (e Exercice) GetQAQuery(id int64) (q QAQuery, err error) { func (e *Exercice) GetQAQuery(id int64) (q *QAQuery, err error) {
q = &QAQuery{}
err = DBQueryRow("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa WHERE id_qa = ? AND id_exercice = ?", id, e.Id).Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed) err = DBQueryRow("SELECT id_qa, id_exercice, id_team, authuser, creation, state, subject, solved, closed FROM exercices_qa WHERE id_qa = ? AND id_exercice = ?", id, e.Id).Scan(&q.Id, &q.IdExercice, &q.IdTeam, &q.User, &q.Creation, &q.State, &q.Subject, &q.Solved, &q.Closed)
return return
} }
// NewQAQuery creates and fills a new struct QAQuery and registers it into the database. // NewQAQuery creates and fills a new struct QAQuery and registers it into the database.
func (e Exercice) NewQAQuery(subject string, teamId *int64, user string, state string) (QAQuery, error) { func (e *Exercice) NewQAQuery(subject string, teamId *int64, user string, state string) (*QAQuery, error) {
if res, err := DBExec("INSERT INTO exercices_qa (id_exercice, id_team, authuser, creation, state, subject) VALUES (?, ?, ?, ?, ?, ?)", e.Id, teamId, user, time.Now(), state, subject); err != nil { if res, err := DBExec("INSERT INTO exercices_qa (id_exercice, id_team, authuser, creation, state, subject) VALUES (?, ?, ?, ?, ?, ?)", e.Id, teamId, user, time.Now(), state, subject); err != nil {
return QAQuery{}, err return nil, err
} else if qid, err := res.LastInsertId(); err != nil { } else if qid, err := res.LastInsertId(); err != nil {
return QAQuery{}, err return nil, err
} else { } else {
return QAQuery{qid, e.Id, teamId, user, time.Now(), state, subject, nil, nil}, nil return &QAQuery{qid, e.Id, teamId, user, time.Now(), state, subject, nil, nil}, nil
} }
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (q QAQuery) Update() (int64, error) { func (q *QAQuery) Update() (int64, error) {
if res, err := DBExec("UPDATE exercices_qa SET subject = ?, id_team = ?, authuser = ?, id_exercice = ?, creation = ?, state = ?, solved = ?, closed = ? WHERE id_qa = ?", q.Subject, q.IdTeam, q.User, q.IdExercice, q.Creation, q.State, q.Solved, q.Closed, q.Id); err != nil { if res, err := DBExec("UPDATE exercices_qa SET subject = ?, id_team = ?, authuser = ?, id_exercice = ?, creation = ?, state = ?, solved = ?, closed = ? WHERE id_qa = ?", q.Subject, q.IdTeam, q.User, q.IdExercice, q.Creation, q.State, q.Solved, q.Closed, q.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -113,7 +115,7 @@ func (q QAQuery) Update() (int64, error) {
} }
// Delete the query from the database. // Delete the query from the database.
func (q QAQuery) Delete() (int64, error) { func (q *QAQuery) Delete() (int64, error) {
if _, err := DBExec("DELETE FROM qa_comments WHERE id_qa = ?", q.Id); err != nil { if _, err := DBExec("DELETE FROM qa_comments WHERE id_qa = ?", q.Id); err != nil {
return 0, err return 0, err
} else if res, err := DBExec("DELETE FROM exercices_qa WHERE id_qa = ?", q.Id); err != nil { } else if res, err := DBExec("DELETE FROM exercices_qa WHERE id_qa = ?", q.Id); err != nil {
@ -146,7 +148,7 @@ type QAComment struct {
} }
// GetComments returns a list of all descriptions stored in the database for the QAQuery. // GetComments returns a list of all descriptions stored in the database for the QAQuery.
func (q QAQuery) GetComments() (res []QAComment, err error) { func (q *QAQuery) GetComments() (res []*QAComment, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_comment, id_team, authuser, date, content FROM qa_comments WHERE id_qa = ?", q.Id); err != nil { if rows, err = DBQuery("SELECT id_comment, id_team, authuser, date, content FROM qa_comments WHERE id_qa = ?", q.Id); err != nil {
return nil, err return nil, err
@ -154,7 +156,7 @@ func (q QAQuery) GetComments() (res []QAComment, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var c QAComment c := &QAComment{}
if err = rows.Scan(&c.Id, &c.IdTeam, &c.User, &c.Date, &c.Content); err != nil { if err = rows.Scan(&c.Id, &c.IdTeam, &c.User, &c.Date, &c.Content); err != nil {
return return
} }
@ -166,24 +168,25 @@ func (q QAQuery) GetComments() (res []QAComment, err error) {
} }
// GetComment returns the comment stored in the database for the QAQuery. // GetComment returns the comment stored in the database for the QAQuery.
func (q QAQuery) GetComment(id int64) (c QAComment, err error) { func (q *QAQuery) GetComment(id int64) (c *QAComment, err error) {
c = &QAComment{}
err = DBQueryRow("SELECT id_comment, id_team, authuser, date, content FROM qa_comments WHERE id_comment = ? AND id_qa = ?", id, q.Id).Scan(&c.Id, &c.IdTeam, &c.User, &c.Date, &c.Content) err = DBQueryRow("SELECT id_comment, id_team, authuser, date, content FROM qa_comments WHERE id_comment = ? AND id_qa = ?", id, q.Id).Scan(&c.Id, &c.IdTeam, &c.User, &c.Date, &c.Content)
return return
} }
// AddComment append in the database a new description; then returns the corresponding structure. // AddComment append in the database a new description; then returns the corresponding structure.
func (q QAQuery) AddComment(content string, teamId *int64, user string) (QAComment, error) { func (q *QAQuery) AddComment(content string, teamId *int64, user string) (*QAComment, error) {
if res, err := DBExec("INSERT INTO qa_comments (id_qa, id_team, authuser, date, content) VALUES (?, ?, ?, ?, ?)", q.Id, teamId, user, time.Now(), content); err != nil { if res, err := DBExec("INSERT INTO qa_comments (id_qa, id_team, authuser, date, content) VALUES (?, ?, ?, ?, ?)", q.Id, teamId, user, time.Now(), content); err != nil {
return QAComment{}, err return nil, err
} else if cid, err := res.LastInsertId(); err != nil { } else if cid, err := res.LastInsertId(); err != nil {
return QAComment{}, err return nil, err
} else { } else {
return QAComment{cid, teamId, user, time.Now(), content}, nil return &QAComment{cid, teamId, user, time.Now(), content}, nil
} }
} }
// Update applies modifications back to the database // Update applies modifications back to the database
func (c QAComment) Update() (int64, error) { func (c *QAComment) Update() (int64, error) {
if res, err := DBExec("UPDATE qa_comments SET id_team = ?, authuser = ?, date = ?, content = ? WHERE id_comment = ?", c.IdTeam, c.User, c.Date, c.Content, c.Id); err != nil { if res, err := DBExec("UPDATE qa_comments SET id_team = ?, authuser = ?, date = ?, content = ? WHERE id_comment = ?", c.IdTeam, c.User, c.Date, c.Content, c.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -194,7 +197,7 @@ func (c QAComment) Update() (int64, error) {
} }
// Delete the comment in the database. // Delete the comment in the database.
func (c QAComment) Delete() (int64, error) { func (c *QAComment) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM qa_comments WHERE id_comment = ?", c.Id); err != nil { if res, err := DBExec("DELETE FROM qa_comments WHERE id_comment = ?", c.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -210,7 +213,7 @@ type QATodo struct {
IdExercice int64 `json:"id_exercice"` IdExercice int64 `json:"id_exercice"`
} }
func (t Team) GetQATodo() (res []QATodo, err error) { func (t *Team) GetQATodo() (res []*QATodo, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_todo, id_exercice FROM teams_qa_todo WHERE id_team = ?", t.Id); err != nil { if rows, err = DBQuery("SELECT id_todo, id_exercice FROM teams_qa_todo WHERE id_team = ?", t.Id); err != nil {
return nil, err return nil, err
@ -218,7 +221,7 @@ func (t Team) GetQATodo() (res []QATodo, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var t QATodo t := &QATodo{}
if err = rows.Scan(&t.Id, &t.IdExercice); err != nil { if err = rows.Scan(&t.Id, &t.IdExercice); err != nil {
return return
} }
@ -229,19 +232,19 @@ func (t Team) GetQATodo() (res []QATodo, err error) {
return return
} }
func (t Team) NewQATodo(idExercice int64) (QATodo, error) { func (t *Team) NewQATodo(idExercice int64) (*QATodo, error) {
if res, err := DBExec("INSERT INTO teams_qa_todo (id_team, id_exercice) VALUES (?, ?)", t.Id, idExercice); err != nil { if res, err := DBExec("INSERT INTO teams_qa_todo (id_team, id_exercice) VALUES (?, ?)", t.Id, idExercice); err != nil {
return QATodo{}, err return nil, err
} else if tid, err := res.LastInsertId(); err != nil { } else if tid, err := res.LastInsertId(); err != nil {
return QATodo{}, err return nil, err
} else { } else {
return QATodo{tid, t.Id, idExercice}, nil return &QATodo{tid, t.Id, idExercice}, nil
} }
} }
// QAView // QAView
func (t Team) GetQAView() (res []QATodo, err error) { func (t *Team) GetQAView() (res []*QATodo, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_view, id_exercice FROM teams_qa_view WHERE id_team = ?", t.Id); err != nil { if rows, err = DBQuery("SELECT id_view, id_exercice FROM teams_qa_view WHERE id_team = ?", t.Id); err != nil {
return nil, err return nil, err
@ -249,7 +252,7 @@ func (t Team) GetQAView() (res []QATodo, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var t QATodo t := &QATodo{}
if err = rows.Scan(&t.Id, &t.IdExercice); err != nil { if err = rows.Scan(&t.Id, &t.IdExercice); err != nil {
return return
} }
@ -260,12 +263,12 @@ func (t Team) GetQAView() (res []QATodo, err error) {
return return
} }
func (t Team) NewQAView(idExercice int64) (QATodo, error) { func (t *Team) NewQAView(idExercice int64) (*QATodo, error) {
if res, err := DBExec("INSERT INTO teams_qa_view (id_team, id_exercice) VALUES (?, ?)", t.Id, idExercice); err != nil { if res, err := DBExec("INSERT INTO teams_qa_view (id_team, id_exercice) VALUES (?, ?)", t.Id, idExercice); err != nil {
return QATodo{}, err return nil, err
} else if tid, err := res.LastInsertId(); err != nil { } else if tid, err := res.LastInsertId(); err != nil {
return QATodo{}, err return nil, err
} else { } else {
return QATodo{tid, t.Id, idExercice}, nil return &QATodo{tid, t.Id, idExercice}, nil
} }
} }

View file

@ -47,7 +47,7 @@ func rankQuery(whereTeam string) string {
) A ` + whereTeam + ` GROUP BY A.id_team ORDER BY score DESC, time ASC` ) A ` + whereTeam + ` GROUP BY A.id_team ORDER BY score DESC, time ASC`
} }
func (t Team) ScoreGrid() (grid []map[string]interface{}, err error) { func (t *Team) ScoreGrid() (grid []map[string]interface{}, err error) {
q := "SELECT G.reason, G.id_exercice, G.time, G.points, G.coeff FROM (" + teamptsQuery() + ") AS G WHERE G.id_team = ? AND G.points != 0" q := "SELECT G.reason, G.id_exercice, G.time, G.points, G.coeff FROM (" + teamptsQuery() + ") AS G WHERE G.id_team = ? AND G.points != 0"
if rows, err := DBQuery(q, t.Id); err != nil { if rows, err := DBQuery(q, t.Id); err != nil {
return nil, err return nil, err
@ -80,7 +80,7 @@ func (t Team) ScoreGrid() (grid []map[string]interface{}, err error) {
// Points // Points
// EstimateGain calculates the amount of point the Team has (or could have, if not already solved) won. // EstimateGain calculates the amount of point the Team has (or could have, if not already solved) won.
func (e Exercice) EstimateGain(t Team, solved bool) (float64, error) { func (e *Exercice) EstimateGain(t *Team, solved bool) (float64, error) {
var pts float64 var pts float64
err := DBQueryRow("SELECT SUM(A.points * A.coeff) AS score FROM ("+exoptsQuery("WHERE S.id_team = ? AND S.id_exercice = ?")+") A GROUP BY id_team", t.Id, e.Id, t.Id, e.Id).Scan(&pts) err := DBQueryRow("SELECT SUM(A.points * A.coeff) AS score FROM ("+exoptsQuery("WHERE S.id_team = ? AND S.id_exercice = ?")+") A GROUP BY id_team", t.Id, e.Id, t.Id, e.Id).Scan(&pts)
if solved { if solved {
@ -95,7 +95,7 @@ func (e Exercice) EstimateGain(t Team, solved bool) (float64, error) {
} }
// GetPoints returns the score for the Team. // GetPoints returns the score for the Team.
func (t Team) GetPoints() (float64, error) { func (t *Team) GetPoints() (float64, error) {
var tid *int64 var tid *int64
var nb *float64 var nb *float64
var tzzz *time.Time var tzzz *time.Time

View file

@ -24,15 +24,15 @@ type Team struct {
Password *string `json:"password"` Password *string `json:"password"`
} }
func getTeams(filter string) ([]Team, error) { func getTeams(filter string) ([]*Team, error) {
if rows, err := DBQuery("SELECT id_team, name, color, active, external_id, password FROM teams " + filter); err != nil { if rows, err := DBQuery("SELECT id_team, name, color, active, external_id, password FROM teams " + filter); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var teams = make([]Team, 0) var teams []*Team
for rows.Next() { for rows.Next() {
var t Team t := &Team{}
if err := rows.Scan(&t.Id, &t.Name, &t.Color, &t.Active, &t.ExternalId, &t.Password); err != nil { if err := rows.Scan(&t.Id, &t.Name, &t.Color, &t.Active, &t.ExternalId, &t.Password); err != nil {
return nil, err return nil, err
} }
@ -47,18 +47,18 @@ func getTeams(filter string) ([]Team, error) {
} }
// GetTeams returns a list of registered Team from the database. // GetTeams returns a list of registered Team from the database.
func GetTeams() ([]Team, error) { func GetTeams() ([]*Team, error) {
return getTeams("") return getTeams("")
} }
// GetActiveTeams returns a list of registered Team from the database, limited to team to generate. // GetActiveTeams returns a list of registered Team from the database, limited to team to generate.
func GetActiveTeams() ([]Team, error) { func GetActiveTeams() ([]*Team, error) {
return getTeams("WHERE active = 1") return getTeams("WHERE active = 1")
} }
// GetTeam retrieves a Team from its identifier. // GetTeam retrieves a Team from its identifier.
func GetTeam(id int64) (Team, error) { func GetTeam(id int64) (*Team, error) {
var t Team t := &Team{}
if err := DBQueryRow("SELECT id_team, name, color, active, external_id, password FROM teams WHERE id_team = ?", id).Scan(&t.Id, &t.Name, &t.Color, &t.Active, &t.ExternalId, &t.Password); err != nil { if err := DBQueryRow("SELECT id_team, name, color, active, external_id, password FROM teams WHERE id_team = ?", id).Scan(&t.Id, &t.Name, &t.Color, &t.Active, &t.ExternalId, &t.Password); err != nil {
return t, err return t, err
} }
@ -67,8 +67,8 @@ func GetTeam(id int64) (Team, error) {
} }
// GetTeamBySerial retrieves a Team from one of its associated certificates. // GetTeamBySerial retrieves a Team from one of its associated certificates.
func GetTeamBySerial(serial int64) (Team, error) { func GetTeamBySerial(serial int64) (*Team, error) {
var t Team t := &Team{}
if err := DBQueryRow("SELECT T.id_team, T.name, T.color, T.active, T.external_id, T.password FROM certificates C INNER JOIN teams T ON T.id_team = C.id_team WHERE id_cert = ?", serial).Scan(&t.Id, &t.Name, &t.Color, &t.Active, &t.ExternalId, &t.Password); err != nil { if err := DBQueryRow("SELECT T.id_team, T.name, T.color, T.active, T.external_id, T.password FROM certificates C INNER JOIN teams T ON T.id_team = C.id_team WHERE id_cert = ?", serial).Scan(&t.Id, &t.Name, &t.Color, &t.Active, &t.ExternalId, &t.Password); err != nil {
return t, err return t, err
} }
@ -77,18 +77,18 @@ func GetTeamBySerial(serial int64) (Team, error) {
} }
// CreateTeam creates and fills a new struct Team and registers it into the database. // CreateTeam creates and fills a new struct Team and registers it into the database.
func CreateTeam(name string, color uint32, externalId string) (Team, error) { func CreateTeam(name string, color uint32, externalId string) (*Team, error) {
if res, err := DBExec("INSERT INTO teams (name, color, external_id) VALUES (?, ?, ?)", name, color, externalId); err != nil { if res, err := DBExec("INSERT INTO teams (name, color, external_id) VALUES (?, ?, ?)", name, color, externalId); err != nil {
return Team{}, err return nil, err
} else if tid, err := res.LastInsertId(); err != nil { } else if tid, err := res.LastInsertId(); err != nil {
return Team{}, err return nil, err
} else { } else {
return Team{tid, name, color, true, "", nil}, nil return &Team{tid, name, color, true, "", nil}, nil
} }
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (t Team) Update() (int64, error) { func (t *Team) Update() (int64, error) {
if res, err := DBExec("UPDATE teams SET name = ?, color = ?, active = ?, external_id = ?, password = ? WHERE id_team = ?", t.Name, t.Color, t.Active, t.ExternalId, t.Password, t.Id); err != nil { if res, err := DBExec("UPDATE teams SET name = ?, color = ?, active = ?, external_id = ?, password = ? WHERE id_team = ?", t.Name, t.Color, t.Active, t.ExternalId, t.Password, t.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -99,7 +99,7 @@ func (t Team) Update() (int64, error) {
} }
// Delete the challenge from the database // Delete the challenge from the database
func (t Team) Delete() (int64, error) { func (t *Team) Delete() (int64, error) {
if _, err := DBExec("DELETE FROM team_members WHERE id_team = ?", t.Id); err != nil { if _, err := DBExec("DELETE FROM team_members WHERE id_team = ?", t.Id); err != nil {
return 0, err return 0, err
} else if res, err := DBExec("DELETE FROM teams WHERE id_team = ?", t.Id); err != nil { } else if res, err := DBExec("DELETE FROM teams WHERE id_team = ?", t.Id); err != nil {
@ -112,7 +112,7 @@ func (t Team) Delete() (int64, error) {
} }
// HasAccess checks if the Team has access to the given challenge. // HasAccess checks if the Team has access to the given challenge.
func (t Team) HasAccess(e Exercice) bool { func (t *Team) HasAccess(e *Exercice) bool {
if UnlockedChallengeDepth < 0 { if UnlockedChallengeDepth < 0 {
return true return true
} }
@ -123,11 +123,11 @@ func (t Team) HasAccess(e Exercice) bool {
return true return true
} }
ed := Exercice{} ed := &Exercice{}
ed.Id = *e.Depend ed.Id = *e.Depend
s, _ := t.HasSolved(ed) s := t.HasSolved(ed)
if s { if s != nil {
return s return true
} }
// Prepare next iteration // Prepare next iteration
@ -141,7 +141,7 @@ func (t Team) HasAccess(e Exercice) bool {
} }
// CanDownload checks if the Team has access to the given file. // CanDownload checks if the Team has access to the given file.
func (t Team) CanDownload(f EFile) bool { func (t *Team) CanDownload(f *EFile) bool {
if deps, err := f.GetDepends(); err != nil { if deps, err := f.GetDepends(); err != nil {
log.Printf("Unable to retrieve file dependencies: %s\n", err) log.Printf("Unable to retrieve file dependencies: %s\n", err)
return false return false
@ -160,7 +160,7 @@ func (t Team) CanDownload(f EFile) bool {
} }
// CanSeeHint checks if the Team has access to the given hint. // CanSeeHint checks if the Team has access to the given hint.
func (t Team) CanSeeHint(h EHint) bool { func (t *Team) CanSeeHint(h *EHint) bool {
if deps, err := h.GetDepends(); err != nil { if deps, err := h.GetDepends(); err != nil {
log.Printf("Unable to retrieve flag dependencies: %s\n", err) log.Printf("Unable to retrieve flag dependencies: %s\n", err)
return false return false
@ -179,7 +179,7 @@ func (t Team) CanSeeHint(h EHint) bool {
} }
// CanSeeFlag checks if the Team has access to the given flag. // CanSeeFlag checks if the Team has access to the given flag.
func (t Team) CanSeeFlag(k Flag) bool { func (t *Team) CanSeeFlag(k Flag) bool {
if deps, err := k.GetDepends(); err != nil { if deps, err := k.GetDepends(); err != nil {
log.Printf("Unable to retrieve flag dependencies: %s\n", err) log.Printf("Unable to retrieve flag dependencies: %s\n", err)
return false return false
@ -198,7 +198,7 @@ func (t Team) CanSeeFlag(k Flag) bool {
} }
// NbTry retrieves the number of attempts made by the Team to the given challenge. // NbTry retrieves the number of attempts made by the Team to the given challenge.
func NbTry(t *Team, e Exercice) int { func NbTry(t *Team, e *Exercice) int {
tries_table := "exercice_tries" tries_table := "exercice_tries"
if SubmissionUniqueness { if SubmissionUniqueness {
tries_table = "exercice_distinct_tries" tries_table = "exercice_distinct_tries"
@ -220,33 +220,33 @@ func NbTry(t *Team, e Exercice) int {
} }
// HasHint checks if the Team has revealed the given Hint. // HasHint checks if the Team has revealed the given Hint.
func (t Team) HasHint(h EHint) bool { func (t *Team) HasHint(h *EHint) bool {
var tm *time.Time var tm *time.Time
DBQueryRow("SELECT MIN(time) FROM team_hints WHERE id_team = ? AND id_hint = ?", t.Id, h.Id).Scan(&tm) DBQueryRow("SELECT MIN(time) FROM team_hints WHERE id_team = ? AND id_hint = ?", t.Id, h.Id).Scan(&tm)
return tm != nil return tm != nil
} }
// OpenHint registers to the database that the Team has now revealed. // OpenHint registers to the database that the Team has now revealed.
func (t Team) OpenHint(h EHint) error { func (t *Team) OpenHint(h *EHint) error {
_, err := DBExec("INSERT INTO team_hints (id_team, id_hint, time, coefficient) VALUES (?, ?, ?, ?)", t.Id, h.Id, time.Now(), math.Max(HintCoefficient, 0.0)) _, err := DBExec("INSERT INTO team_hints (id_team, id_hint, time, coefficient) VALUES (?, ?, ?, ?)", t.Id, h.Id, time.Now(), math.Max(HintCoefficient, 0.0))
return err return err
} }
// SeeChoices checks if the Team has revealed the given choices. // SeeChoices checks if the Team has revealed the given choices.
func (t Team) SeeChoices(k FlagKey) bool { func (t *Team) SeeChoices(k *FlagKey) bool {
var tm *time.Time var tm *time.Time
DBQueryRow("SELECT MIN(time) FROM team_wchoices WHERE id_team = ? AND id_flag = ?", t.Id, k.Id).Scan(&tm) DBQueryRow("SELECT MIN(time) FROM team_wchoices WHERE id_team = ? AND id_flag = ?", t.Id, k.Id).Scan(&tm)
return tm != nil return tm != nil
} }
// DisplayChoices registers to the database that the Team has now revealed. // DisplayChoices registers to the database that the Team has now revealed.
func (t Team) DisplayChoices(k FlagKey) error { func (t *Team) DisplayChoices(k *FlagKey) error {
_, err := DBExec("INSERT INTO team_wchoices (id_team, id_flag, time, coefficient) VALUES (?, ?, ?, ?)", t.Id, k.Id, time.Now(), math.Max(WChoiceCoefficient, 0.0)) _, err := DBExec("INSERT INTO team_wchoices (id_team, id_flag, time, coefficient) VALUES (?, ?, ?, ?)", t.Id, k.Id, time.Now(), math.Max(WChoiceCoefficient, 0.0))
return err return err
} }
// CountTries gets the amount of attempts made by the Team and retrieves the time of the latest attempt. // CountTries gets the amount of attempts made by the Team and retrieves the time of the latest attempt.
func (t Team) CountTries(e Exercice) (int64, time.Time) { func (t *Team) CountTries(e *Exercice) (int64, *time.Time) {
table := "exercice_tries" table := "exercice_tries"
if CountOnlyNotGoodTries { if CountOnlyNotGoodTries {
table += "_notgood" table += "_notgood"
@ -257,22 +257,22 @@ func (t Team) CountTries(e Exercice) (int64, time.Time) {
if DBQueryRow("SELECT COUNT(id_exercice), MAX(time) FROM "+table+" WHERE id_team = ? AND id_exercice = ?", t.Id, e.Id).Scan(&nb, &tm); tm == nil { if DBQueryRow("SELECT COUNT(id_exercice), MAX(time) FROM "+table+" WHERE id_team = ? AND id_exercice = ?", t.Id, e.Id).Scan(&nb, &tm); tm == nil {
if CountOnlyNotGoodTries { if CountOnlyNotGoodTries {
if DBQueryRow("SELECT COUNT(id_exercice), MAX(time) FROM exercice_tries WHERE id_team = ? AND id_exercice = ?", t.Id, e.Id).Scan(&nb, &tm); tm == nil { if DBQueryRow("SELECT COUNT(id_exercice), MAX(time) FROM exercice_tries WHERE id_team = ? AND id_exercice = ?", t.Id, e.Id).Scan(&nb, &tm); tm == nil {
return 0, time.Unix(0, 0) return 0, nil
} else { } else {
return 0, *tm return 0, tm
} }
} }
return 0, time.Unix(0, 0) return 0, nil
} else if nb == nil { } else if nb == nil {
return 0, *tm return 0, tm
} else { } else {
return *nb, *tm return *nb, tm
} }
} }
// LastTryDist retrieves the distance to the correct answers, for the given challenge. // LastTryDist retrieves the distance to the correct answers, for the given challenge.
// The distance is the number of bad responses given in differents MCQs. // The distance is the number of bad responses given in differents MCQs.
func (t Team) LastTryDist(e Exercice) int64 { func (t *Team) LastTryDist(e *Exercice) int64 {
var nb *int64 var nb *int64
if DBQueryRow("SELECT nbdiff FROM exercice_tries WHERE id_team = ? AND id_exercice = ? ORDER BY time DESC LIMIT 1", t.Id, e.Id).Scan(&nb); nb == nil { if DBQueryRow("SELECT nbdiff FROM exercice_tries WHERE id_team = ? AND id_exercice = ? ORDER BY time DESC LIMIT 1", t.Id, e.Id).Scan(&nb); nb == nil {
return 0 return 0
@ -283,17 +283,13 @@ func (t Team) LastTryDist(e Exercice) int64 {
// HasSolved checks if the Team already has validated the given challenge. // HasSolved checks if the Team already has validated the given challenge.
// Note that the function also returns the effective validation timestamp. // Note that the function also returns the effective validation timestamp.
func (t Team) HasSolved(e Exercice) (bool, time.Time) { func (t *Team) HasSolved(e *Exercice) (tm *time.Time) {
var tm *time.Time DBQueryRow("SELECT MIN(time) FROM exercice_solved WHERE id_team = ? AND id_exercice = ?", t.Id, e.Id).Scan(&tm)
if DBQueryRow("SELECT MIN(time) FROM exercice_solved WHERE id_team = ? AND id_exercice = ?", t.Id, e.Id).Scan(&tm); tm == nil { return
return false, time.Unix(0, 0)
} else {
return true, *tm
}
} }
// GetSolvedRank returns the number of teams that solved the challenge before the Team. // GetSolvedRank returns the number of teams that solved the challenge before the Team.
func (t Team) GetSolvedRank(e Exercice) (nb int64, err error) { func (t *Team) GetSolvedRank(e *Exercice) (nb int64, err error) {
if rows, errr := DBQuery("SELECT id_team FROM exercice_solved WHERE id_exercice = ? ORDER BY time ASC", e.Id); errr != nil { if rows, errr := DBQuery("SELECT id_team FROM exercice_solved WHERE id_exercice = ? ORDER BY time ASC", e.Id); errr != nil {
return nb, errr return nb, errr
} else { } else {
@ -315,10 +311,10 @@ func (t Team) GetSolvedRank(e Exercice) (nb int64, err error) {
} }
// HasPartiallySolved checks if the Team already has unlocked the given flag and returns the validation's timestamp. // HasPartiallySolved checks if the Team already has unlocked the given flag and returns the validation's timestamp.
func (t Team) HasPartiallySolved(f Flag) (tm *time.Time) { func (t *Team) HasPartiallySolved(f Flag) (tm *time.Time) {
if k, ok := f.(FlagKey); ok { if k, ok := f.(*FlagKey); ok {
DBQueryRow("SELECT MIN(time) FROM flag_found WHERE id_team = ? AND id_flag = ?", t.Id, k.Id).Scan(&tm) DBQueryRow("SELECT MIN(time) FROM flag_found WHERE id_team = ? AND id_flag = ?", t.Id, k.Id).Scan(&tm)
} else if m, ok := f.(MCQ); ok { } else if m, ok := f.(*MCQ); ok {
DBQueryRow("SELECT MIN(time) FROM mcq_found WHERE id_team = ? AND id_mcq = ?", t.Id, m.Id).Scan(&tm) DBQueryRow("SELECT MIN(time) FROM mcq_found WHERE id_team = ? AND id_mcq = ?", t.Id, m.Id).Scan(&tm)
} else { } else {
log.Fatal("Unknown flag type") log.Fatal("Unknown flag type")
@ -327,7 +323,7 @@ func (t Team) HasPartiallySolved(f Flag) (tm *time.Time) {
} }
// HashedPassword compute a bcrypt version of the team's password. // HashedPassword compute a bcrypt version of the team's password.
func (t Team) HashedPassword() (string, error) { func (t *Team) HashedPassword() (string, error) {
if t.Password == nil { if t.Password == nil {
if passwd, err := GeneratePassword(); err != nil { if passwd, err := GeneratePassword(); err != nil {
return "", err return "", err

View file

@ -6,17 +6,17 @@ import (
// exportedTeam is a structure representing a Team, as exposed to players. // exportedTeam is a structure representing a Team, as exposed to players.
type ExportedTeam struct { type ExportedTeam struct {
Name string `json:"name"` Name string `json:"name"`
Color string `json:"color"` Color string `json:"color"`
Rank int `json:"rank"` Rank int `json:"rank"`
Points float64 `json:"score"` Points float64 `json:"score"`
Members []Member `json:"members,omitempty"` Members []*Member `json:"members,omitempty"`
ExternalId string `json:"external_id,omitempty"` ExternalId string `json:"external_id,omitempty"`
} }
// Exportedteam creates the structure to respond as teams.json. // Exportedteam creates the structure to respond as teams.json.
func ExportTeams(includeMembers bool) (ret map[string]ExportedTeam, err error) { func ExportTeams(includeMembers bool) (ret map[string]ExportedTeam, err error) {
var teams []Team var teams []*Team
var rank map[int64]int var rank map[int64]int
if teams, err = GetTeams(); err != nil { if teams, err = GetTeams(); err != nil {
@ -27,7 +27,7 @@ func ExportTeams(includeMembers bool) (ret map[string]ExportedTeam, err error) {
ret = map[string]ExportedTeam{} ret = map[string]ExportedTeam{}
for _, team := range teams { for _, team := range teams {
points, _ := team.GetPoints() points, _ := team.GetPoints()
var members []Member var members []*Member
if includeMembers { if includeMembers {
if members, err = team.GetMembers(); err != nil { if members, err = team.GetMembers(); err != nil {
return return

View file

@ -5,7 +5,7 @@ import (
) )
// GetHistory aggregates all sources of events or actions for a Team // GetHistory aggregates all sources of events or actions for a Team
func (t Team) GetHistory() ([]map[string]interface{}, error) { func (t *Team) GetHistory() ([]map[string]interface{}, error) {
hist := make([]map[string]interface{}, 0) hist := make([]map[string]interface{}, 0)
if rows, err := DBQuery(`SELECT id_team, "tries" AS kind, time, 0, E.id_exercice, E.title, NULL, NULL FROM exercice_tries T INNER JOIN exercices E ON E.id_exercice = T.id_exercice WHERE id_team = ? UNION if rows, err := DBQuery(`SELECT id_team, "tries" AS kind, time, 0, E.id_exercice, E.title, NULL, NULL FROM exercice_tries T INNER JOIN exercices E ON E.id_exercice = T.id_exercice WHERE id_team = ? UNION
@ -55,7 +55,7 @@ func (t Team) GetHistory() ([]map[string]interface{}, error) {
} }
// UpdateHistoryCoeff updates the coefficient for a given entry. // UpdateHistoryCoeff updates the coefficient for a given entry.
func (t Team) UpdateHistoryCoeff(kind string, h time.Time, givenId int64, newCoeff float32) (interface{}, error) { func (t *Team) UpdateHistoryCoeff(kind string, h time.Time, givenId int64, newCoeff float32) (interface{}, error) {
if kind == "hint" { if kind == "hint" {
if res, err := DBExec("UPDATE team_hints SET coefficient = ? WHERE id_team = ? AND time = ? AND id_hint = ?", newCoeff, t.Id, h, givenId); err != nil { if res, err := DBExec("UPDATE team_hints SET coefficient = ? WHERE id_team = ? AND time = ? AND id_hint = ?", newCoeff, t.Id, h, givenId); err != nil {
return 0, err return 0, err
@ -86,7 +86,7 @@ func (t Team) UpdateHistoryCoeff(kind string, h time.Time, givenId int64, newCoe
} }
// DelHistoryItem removes from the database an entry from the history. // DelHistoryItem removes from the database an entry from the history.
func (t Team) DelHistoryItem(kind string, h time.Time, primary *int64, secondary *int64) (interface{}, error) { func (t *Team) DelHistoryItem(kind string, h time.Time, primary *int64, secondary *int64) (interface{}, error) {
if kind == "tries" && primary != nil { if kind == "tries" && primary != nil {
if res, err := DBExec("DELETE FROM exercice_tries WHERE id_team = ? AND time = ? AND id_exercice = ?", t.Id, h, *primary); err != nil { if res, err := DBExec("DELETE FROM exercice_tries WHERE id_team = ? AND time = ? AND id_exercice = ?", t.Id, h, *primary); err != nil {
return 0, err return 0, err

View file

@ -79,7 +79,7 @@ type myTeam struct {
Id int64 `json:"team_id"` Id int64 `json:"team_id"`
Name string `json:"name"` Name string `json:"name"`
Points int64 `json:"score"` Points int64 `json:"score"`
Members []Member `json:"members"` Members []*Member `json:"members,omitempty"`
Exercices map[string]myTeamExercice `json:"exercices"` Exercices map[string]myTeamExercice `json:"exercices"`
} }
@ -103,7 +103,6 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
if members, err := t.GetMembers(); err == nil { if members, err := t.GetMembers(); err == nil {
ret.Members = members ret.Members = members
} }
} }
// Fill exercices, only if the challenge is started // Fill exercices, only if the challenge is started
@ -130,16 +129,16 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
exercice.TotalTries = e.TriedCount() exercice.TotalTries = e.TriedCount()
exercice.Gain = int(float64(e.Gain) * e.Coefficient * GlobalScoreCoefficient) exercice.Gain = int(float64(e.Gain) * e.Coefficient * GlobalScoreCoefficient)
} else { } else {
solved, stime := t.HasSolved(e) stime := t.HasSolved(e)
exercice.SolvedTime = &stime exercice.SolvedTime = stime
if solved { if stime != nil {
exercice.SolvedRank, _ = t.GetSolvedRank(e) exercice.SolvedRank, _ = t.GetSolvedRank(e)
exercice.Finished = e.Finished exercice.Finished = e.Finished
exercice.Tries, _ = t.CountTries(e) exercice.Tries, _ = t.CountTries(e)
} else { } else {
exercice.Tries, stime = t.CountTries(e) exercice.Tries, stime = t.CountTries(e)
exercice.SolvedTime = &stime exercice.SolvedTime = stime
if exercice.Tries > 0 { if exercice.Tries > 0 {
exercice.SolveDist = t.LastTryDist(e) exercice.SolveDist = t.LastTryDist(e)
} }
@ -149,7 +148,7 @@ func MyJSONTeam(t *Team, started bool) (interface{}, error) {
exercice.SolvedTime = nil exercice.SolvedTime = nil
} }
if gain, err := e.EstimateGain(*t, solved); err == nil { if gain, err := e.EstimateGain(t, stime != nil); err == nil {
exercice.Gain = int(gain * GlobalScoreCoefficient) exercice.Gain = int(gain * GlobalScoreCoefficient)
} else { } else {
log.Println("ERROR during gain estimation:", err) log.Println("ERROR during gain estimation:", err)

View file

@ -71,7 +71,7 @@ func GetTeamsStats(t *Team) (interface{}, error) {
sLvl.Total += 1 sLvl.Total += 1
if t != nil { if t != nil {
if b, _ := t.HasSolved(exercice); b { if b := t.HasSolved(exercice); b != nil {
solved += 1 solved += 1
sLvl.Solved += 1 sLvl.Solved += 1
} }

View file

@ -18,20 +18,20 @@ type Theme struct {
} }
// CmpTheme returns true if given Themes are identicals. // CmpTheme returns true if given Themes are identicals.
func CmpTheme(t1 Theme, t2 Theme) bool { func CmpTheme(t1 *Theme, t2 *Theme) bool {
return !(t1.Name != t2.Name || t1.URLId != t2.URLId || t1.Path != t2.Path || t1.Authors != t2.Authors || t1.Intro != t2.Intro || t1.Headline != t2.Headline || t1.Image != t2.Image || t1.PartnerImage != t2.PartnerImage || t1.PartnerLink != t2.PartnerLink || t1.PartnerText != t2.PartnerText) return t1 != nil && t2 != nil && !(t1.Name != t2.Name || t1.URLId != t2.URLId || t1.Path != t2.Path || t1.Authors != t2.Authors || t1.Intro != t2.Intro || t1.Headline != t2.Headline || t1.Image != t2.Image || t1.PartnerImage != t2.PartnerImage || t1.PartnerLink != t2.PartnerLink || t1.PartnerText != t2.PartnerText)
} }
// GetThemes returns a list of registered Themes from the database. // GetThemes returns a list of registered Themes from the database.
func GetThemes() ([]Theme, error) { func GetThemes() ([]*Theme, error) {
if rows, err := DBQuery("SELECT id_theme, name, url_id, path, authors, intro, headline, image, partner_img, partner_href, partner_text FROM themes"); err != nil { if rows, err := DBQuery("SELECT id_theme, name, url_id, path, authors, intro, headline, image, partner_img, partner_href, partner_text FROM themes"); err != nil {
return nil, err return nil, err
} else { } else {
defer rows.Close() defer rows.Close()
var themes = make([]Theme, 0) var themes []*Theme
for rows.Next() { for rows.Next() {
var t Theme t := &Theme{}
if err := rows.Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerLink, &t.PartnerText); err != nil { if err := rows.Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerLink, &t.PartnerText); err != nil {
return nil, err return nil, err
} }
@ -46,8 +46,8 @@ func GetThemes() ([]Theme, error) {
} }
// GetTheme retrieves a Theme from its identifier. // GetTheme retrieves a Theme from its identifier.
func GetTheme(id int64) (Theme, error) { func GetTheme(id int64) (*Theme, error) {
var t Theme t := &Theme{}
if err := DBQueryRow("SELECT id_theme, name, url_id, path, authors, intro, headline, image, partner_img, partner_href, partner_text FROM themes WHERE id_theme=?", id).Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerLink, &t.PartnerText); err != nil { if err := DBQueryRow("SELECT id_theme, name, url_id, path, authors, intro, headline, image, partner_img, partner_href, partner_text FROM themes WHERE id_theme=?", id).Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerLink, &t.PartnerText); err != nil {
return t, err return t, err
} }
@ -56,8 +56,8 @@ func GetTheme(id int64) (Theme, error) {
} }
// GetThemeByName retrieves a Theme from its title // GetThemeByName retrieves a Theme from its title
func GetThemeByName(name string) (Theme, error) { func GetThemeByName(name string) (*Theme, error) {
var t Theme t := &Theme{}
if err := DBQueryRow("SELECT id_theme, name, url_id, path, authors, intro, headline, image, partner_img, partner_text FROM themes WHERE name=?", name).Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerText); err != nil { if err := DBQueryRow("SELECT id_theme, name, url_id, path, authors, intro, headline, image, partner_img, partner_text FROM themes WHERE name=?", name).Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerText); err != nil {
return t, err return t, err
} }
@ -66,21 +66,19 @@ func GetThemeByName(name string) (Theme, error) {
} }
// GetThemeByPath retrieves a Theme from its dirname // GetThemeByPath retrieves a Theme from its dirname
func GetThemeByPath(dirname string) (Theme, error) { func GetThemeByPath(dirname string) (*Theme, error) {
var t Theme t := &Theme{}
if err := DBQueryRow("SELECT id_theme, name, url_id, path, authors, intro, headline, image, partner_img, partner_href, partner_text FROM themes WHERE path=?", dirname).Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerLink, &t.PartnerText); err != nil { err := DBQueryRow("SELECT id_theme, name, url_id, path, authors, intro, headline, image, partner_img, partner_href, partner_text FROM themes WHERE path=?", dirname).Scan(&t.Id, &t.Name, &t.URLId, &t.Path, &t.Authors, &t.Intro, &t.Headline, &t.Image, &t.PartnerImage, &t.PartnerLink, &t.PartnerText)
return t, err
}
return t, nil return t, err
} }
// CreateTheme creates and fills a new struct Theme and registers it into the database. // CreateTheme creates and fills a new struct Theme and registers it into the database.
func CreateTheme(theme Theme) (Theme, error) { func CreateTheme(theme *Theme) (*Theme, error) {
if res, err := DBExec("INSERT INTO themes (name, url_id, authors, path, intro, headline, image, partner_img, partner_href, partner_text) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", theme.Name, theme.URLId, theme.Authors, theme.Path, theme.Intro, theme.Headline, theme.Image, theme.PartnerImage, theme.PartnerLink, theme.PartnerText); err != nil { if res, err := DBExec("INSERT INTO themes (name, url_id, authors, path, intro, headline, image, partner_img, partner_href, partner_text) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", theme.Name, theme.URLId, theme.Authors, theme.Path, theme.Intro, theme.Headline, theme.Image, theme.PartnerImage, theme.PartnerLink, theme.PartnerText); err != nil {
return Theme{}, err return nil, err
} else if theme.Id, err = res.LastInsertId(); err != nil { } else if theme.Id, err = res.LastInsertId(); err != nil {
return Theme{}, err return nil, err
} else { } else {
return theme, nil return theme, nil
} }
@ -97,7 +95,7 @@ func (t *Theme) FixURLId() bool {
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (t Theme) Update() (int64, error) { func (t *Theme) Update() (int64, error) {
if res, err := DBExec("UPDATE themes SET name = ?, url_id = ?, authors = ?, path = ?, intro = ?, headline = ?, image = ?, partner_img = ?, partner_href = ?, partner_text = ? WHERE id_theme = ?", t.Name, t.URLId, t.Authors, t.Path, t.Intro, t.Headline, t.Image, t.PartnerImage, t.PartnerLink, t.PartnerText, t.Id); err != nil { if res, err := DBExec("UPDATE themes SET name = ?, url_id = ?, authors = ?, path = ?, intro = ?, headline = ?, image = ?, partner_img = ?, partner_href = ?, partner_text = ? WHERE id_theme = ?", t.Name, t.URLId, t.Authors, t.Path, t.Intro, t.Headline, t.Image, t.PartnerImage, t.PartnerLink, t.PartnerText, t.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -108,7 +106,7 @@ func (t Theme) Update() (int64, error) {
} }
// Delete the theme from the database. // Delete the theme from the database.
func (t Theme) Delete() (int64, error) { func (t *Theme) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM themes WHERE id_theme = ?", t.Id); err != nil { if res, err := DBExec("DELETE FROM themes WHERE id_theme = ?", t.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -118,7 +116,7 @@ func (t Theme) Delete() (int64, error) {
} }
} }
func (t Theme) deleteFunc(f func(Exercice) (int64, error)) (int64, error) { func (t *Theme) deleteFunc(f func(*Exercice) (int64, error)) (int64, error) {
exercices, err := t.GetExercices() exercices, err := t.GetExercices()
if err != nil { if err != nil {
return 0, err return 0, err
@ -135,8 +133,8 @@ func (t Theme) deleteFunc(f func(Exercice) (int64, error)) (int64, error) {
} }
// DeleteCascade the theme from the database, including inner content but not player content. // DeleteCascade the theme from the database, including inner content but not player content.
func (t Theme) DeleteCascade() (int64, error) { func (t *Theme) DeleteCascade() (int64, error) {
_, err := t.deleteFunc(func(e Exercice) (int64, error) { _, err := t.deleteFunc(func(e *Exercice) (int64, error) {
return e.DeleteCascade() return e.DeleteCascade()
}) })
if err != nil { if err != nil {
@ -147,8 +145,8 @@ func (t Theme) DeleteCascade() (int64, error) {
} }
// DeleteCascadePlayer delete player content related to this theme. // DeleteCascadePlayer delete player content related to this theme.
func (t Theme) DeleteCascadePlayer() (int64, error) { func (t *Theme) DeleteCascadePlayer() (int64, error) {
_, err := t.deleteFunc(func(e Exercice) (int64, error) { _, err := t.deleteFunc(func(e *Exercice) (int64, error) {
return e.DeleteCascadePlayer() return e.DeleteCascadePlayer()
}) })
if err != nil { if err != nil {
@ -159,8 +157,8 @@ func (t Theme) DeleteCascadePlayer() (int64, error) {
} }
// DeleteDeep the theme from the database, including player content. // DeleteDeep the theme from the database, including player content.
func (t Theme) DeleteDeep() (int64, error) { func (t *Theme) DeleteDeep() (int64, error) {
_, err := t.deleteFunc(func(e Exercice) (int64, error) { _, err := t.deleteFunc(func(e *Exercice) (int64, error) {
return e.DeleteDeep() return e.DeleteDeep()
}) })
if err != nil { if err != nil {

View file

@ -20,13 +20,14 @@ type Claim struct {
} }
// GetClaim retrieves the claim with the given identifier. // GetClaim retrieves the claim with the given identifier.
func GetClaim(id int64) (c Claim, err error) { func GetClaim(id int64) (c *Claim, err error) {
c = &Claim{}
err = DBQueryRow("SELECT id_claim, subject, id_team, id_exercice, id_assignee, creation, state, priority FROM claims WHERE id_claim = ?", id).Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdExercice, &c.IdAssignee, &c.Creation, &c.State, &c.Priority) err = DBQueryRow("SELECT id_claim, subject, id_team, id_exercice, id_assignee, creation, state, priority FROM claims WHERE id_claim = ?", id).Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdExercice, &c.IdAssignee, &c.Creation, &c.State, &c.Priority)
return return
} }
// GetClaims returns a list of all Claim registered in the database. // GetClaims returns a list of all Claim registered in the database.
func GetClaims() (res []Claim, err error) { func GetClaims() (res []*Claim, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_claim, subject, id_team, id_exercice, id_assignee, creation, state, priority FROM claims"); err != nil { if rows, err = DBQuery("SELECT id_claim, subject, id_team, id_exercice, id_assignee, creation, state, priority FROM claims"); err != nil {
return return
@ -34,7 +35,7 @@ func GetClaims() (res []Claim, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var c Claim c := &Claim{}
if err = rows.Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdExercice, &c.IdAssignee, &c.Creation, &c.State, &c.Priority); err != nil { if err = rows.Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdExercice, &c.IdAssignee, &c.Creation, &c.State, &c.Priority); err != nil {
return return
} }
@ -46,13 +47,14 @@ func GetClaims() (res []Claim, err error) {
} }
// GetClaim retrieves the claim with the given identifier and registered for the given Team. // GetClaim retrieves the claim with the given identifier and registered for the given Team.
func (t Team) GetClaim(id int64) (c Claim, err error) { func (t *Team) GetClaim(id int64) (c *Claim, err error) {
c = &Claim{}
err = DBQueryRow("SELECT id_claim, subject, id_team, id_exercice, id_assignee, creation, state, priority FROM claims WHERE id_claim = ? AND id_team = ?", id, t.Id).Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdExercice, &c.IdAssignee, &c.Creation, &c.State, &c.Priority) err = DBQueryRow("SELECT id_claim, subject, id_team, id_exercice, id_assignee, creation, state, priority FROM claims WHERE id_claim = ? AND id_team = ?", id, t.Id).Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdExercice, &c.IdAssignee, &c.Creation, &c.State, &c.Priority)
return return
} }
// GetClaims returns a list of all Claim registered for the Team. // GetClaims returns a list of all Claim registered for the Team.
func (t Team) GetClaims() (res []Claim, err error) { func (t *Team) GetClaims() (res []*Claim, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_claim, subject, id_team, id_exercice, id_assignee, creation, state, priority FROM claims WHERE id_team = ?", t.Id); err != nil { if rows, err = DBQuery("SELECT id_claim, subject, id_team, id_exercice, id_assignee, creation, state, priority FROM claims WHERE id_team = ?", t.Id); err != nil {
return nil, err return nil, err
@ -60,7 +62,7 @@ func (t Team) GetClaims() (res []Claim, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var c Claim c := &Claim{}
if err = rows.Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdExercice, &c.IdAssignee, &c.Creation, &c.State, &c.Priority); err != nil { if err = rows.Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdExercice, &c.IdAssignee, &c.Creation, &c.State, &c.Priority); err != nil {
return return
} }
@ -72,7 +74,7 @@ func (t Team) GetClaims() (res []Claim, err error) {
} }
// GetExercices returns a list of all Claim registered for the Exercice. // GetExercices returns a list of all Claim registered for the Exercice.
func (e Exercice) GetClaims() (res []Claim, err error) { func (e *Exercice) GetClaims() (res []*Claim, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_claim, subject, id_team, id_exercice, id_assignee, creation, state, priority FROM claims WHERE id_exercice = ?", e.Id); err != nil { if rows, err = DBQuery("SELECT id_claim, subject, id_team, id_exercice, id_assignee, creation, state, priority FROM claims WHERE id_exercice = ?", e.Id); err != nil {
return nil, err return nil, err
@ -80,7 +82,7 @@ func (e Exercice) GetClaims() (res []Claim, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var c Claim c := &Claim{}
if err = rows.Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdExercice, &c.IdAssignee, &c.Creation, &c.State, &c.Priority); err != nil { if err = rows.Scan(&c.Id, &c.Subject, &c.IdTeam, &c.IdExercice, &c.IdAssignee, &c.Creation, &c.State, &c.Priority); err != nil {
return return
} }
@ -92,7 +94,7 @@ func (e Exercice) GetClaims() (res []Claim, err error) {
} }
// NewClaim creates and fills a new struct Claim and registers it into the database. // NewClaim creates and fills a new struct Claim and registers it into the database.
func NewClaim(subject string, team *Team, exercice *Exercice, assignee *ClaimAssignee, priority string) (Claim, error) { func NewClaim(subject string, team *Team, exercice *Exercice, assignee *ClaimAssignee, priority string) (*Claim, error) {
var tid *int64 var tid *int64
if team == nil { if team == nil {
tid = nil tid = nil
@ -115,48 +117,48 @@ func NewClaim(subject string, team *Team, exercice *Exercice, assignee *ClaimAss
} }
if res, err := DBExec("INSERT INTO claims (subject, id_team, id_exercice, id_assignee, creation, state, priority) VALUES (?, ?, ?, ?, ?, ?, ?)", subject, tid, eid, aid, time.Now(), "new", priority); err != nil { if res, err := DBExec("INSERT INTO claims (subject, id_team, id_exercice, id_assignee, creation, state, priority) VALUES (?, ?, ?, ?, ?, ?, ?)", subject, tid, eid, aid, time.Now(), "new", priority); err != nil {
return Claim{}, err return nil, err
} else if cid, err := res.LastInsertId(); err != nil { } else if cid, err := res.LastInsertId(); err != nil {
return Claim{}, err return nil, err
} else { } else {
return Claim{cid, subject, tid, eid, aid, time.Now(), "new", priority}, nil return &Claim{cid, subject, tid, eid, aid, time.Now(), "new", priority}, nil
} }
} }
// GetTeam returns the Team linked to the issue, if any. // GetTeam returns the Team linked to the issue, if any.
func (c Claim) GetTeam() (*Team, error) { func (c *Claim) GetTeam() (*Team, error) {
if c.IdTeam == nil { if c.IdTeam == nil {
return nil, nil return nil, nil
} else if t, err := GetTeam(*c.IdTeam); err != nil { } else if t, err := GetTeam(*c.IdTeam); err != nil {
return nil, err return nil, err
} else { } else {
return &t, nil return t, nil
} }
} }
// SetTeam defines the Team that is linked to this issue. // SetTeam defines the Team that is linked to this issue.
func (c Claim) SetTeam(t Team) { func (c *Claim) SetTeam(t Team) {
c.IdTeam = &t.Id c.IdTeam = &t.Id
} }
// GetExercice returns the Exercice linked to the issue, if any. // GetExercice returns the Exercice linked to the issue, if any.
func (c Claim) GetExercice() (*Exercice, error) { func (c *Claim) GetExercice() (*Exercice, error) {
if c.IdExercice == nil { if c.IdExercice == nil {
return nil, nil return nil, nil
} else if e, err := GetExercice(*c.IdExercice); err != nil { } else if e, err := GetExercice(*c.IdExercice); err != nil {
return nil, err return nil, err
} else { } else {
return &e, nil return e, nil
} }
} }
// SetExercice defines the Exercice that is linked to this issue. // SetExercice defines the Exercice that is linked to this issue.
func (c Claim) SetExercice(e Exercice) { func (c *Claim) SetExercice(e Exercice) {
c.IdExercice = &e.Id c.IdExercice = &e.Id
} }
// Update applies modifications back to the database. // Update applies modifications back to the database.
func (c Claim) Update() (int64, error) { func (c *Claim) Update() (int64, error) {
if res, err := DBExec("UPDATE claims SET subject = ?, id_team = ?, id_exercice = ?, id_assignee = ?, creation = ?, state = ?, priority = ? WHERE id_claim = ?", c.Subject, c.IdTeam, c.IdExercice, c.IdAssignee, c.Creation, c.State, c.Priority, c.Id); err != nil { if res, err := DBExec("UPDATE claims SET subject = ?, id_team = ?, id_exercice = ?, id_assignee = ?, creation = ?, state = ?, priority = ? WHERE id_claim = ?", c.Subject, c.IdTeam, c.IdExercice, c.IdAssignee, c.Creation, c.State, c.Priority, c.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -167,7 +169,7 @@ func (c Claim) Update() (int64, error) {
} }
// Delete the issue from the database. // Delete the issue from the database.
func (c Claim) Delete() (int64, error) { func (c *Claim) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM claims WHERE id_claim = ?", c.Id); err != nil { if res, err := DBExec("DELETE FROM claims WHERE id_claim = ?", c.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -202,13 +204,13 @@ type ClaimDescription struct {
} }
// GetLastUpdate returns the date of the latest message written for the given Claim. // GetLastUpdate returns the date of the latest message written for the given Claim.
func (c Claim) GetLastUpdate() (res *time.Time, err error) { func (c *Claim) GetLastUpdate() (res *time.Time, err error) {
err = DBQueryRow("SELECT MAX(date) FROM claim_descriptions WHERE id_claim = ? GROUP BY id_claim", c.Id).Scan(&res) err = DBQueryRow("SELECT MAX(date) FROM claim_descriptions WHERE id_claim = ? GROUP BY id_claim", c.Id).Scan(&res)
return return
} }
// GetDescriptions returns a list of all descriptions stored in the database for the Claim. // GetDescriptions returns a list of all descriptions stored in the database for the Claim.
func (c Claim) GetDescriptions() (res []ClaimDescription, err error) { func (c *Claim) GetDescriptions() (res []*ClaimDescription, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_description, id_assignee, content, date, publish FROM claim_descriptions WHERE id_claim = ?", c.Id); err != nil { if rows, err = DBQuery("SELECT id_description, id_assignee, content, date, publish FROM claim_descriptions WHERE id_claim = ?", c.Id); err != nil {
return nil, err return nil, err
@ -216,7 +218,7 @@ func (c Claim) GetDescriptions() (res []ClaimDescription, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var d ClaimDescription d := &ClaimDescription{}
if err = rows.Scan(&d.Id, &d.IdAssignee, &d.Content, &d.Date, &d.Publish); err != nil { if err = rows.Scan(&d.Id, &d.IdAssignee, &d.Content, &d.Date, &d.Publish); err != nil {
return return
} }
@ -228,24 +230,30 @@ func (c Claim) GetDescriptions() (res []ClaimDescription, err error) {
} }
// AddDescription append in the database a new description; then returns the corresponding structure. // AddDescription append in the database a new description; then returns the corresponding structure.
func (c Claim) AddDescription(content string, assignee ClaimAssignee, publish bool) (ClaimDescription, error) { func (c *Claim) AddDescription(content string, assignee *ClaimAssignee, publish bool) (*ClaimDescription, error) {
if res, err := DBExec("INSERT INTO claim_descriptions (id_claim, id_assignee, content, date, publish) VALUES (?, ?, ?, ?, ?)", c.Id, assignee.Id, content, time.Now(), publish); err != nil { var assignee_id *int64
return ClaimDescription{}, err if assignee != nil {
assignee_id = &assignee.Id
}
if res, err := DBExec("INSERT INTO claim_descriptions (id_claim, id_assignee, content, date, publish) VALUES (?, ?, ?, ?, ?)", c.Id, assignee_id, content, time.Now(), publish); err != nil {
return nil, err
} else if did, err := res.LastInsertId(); err != nil { } else if did, err := res.LastInsertId(); err != nil {
return ClaimDescription{}, err return nil, err
} else { } else {
return ClaimDescription{did, assignee.Id, content, time.Now(), publish}, nil return &ClaimDescription{did, assignee.Id, content, time.Now(), publish}, nil
} }
} }
// GetAssignee retrieves an assignee from its identifier. // GetAssignee retrieves an assignee from its identifier.
func (d ClaimDescription) GetAssignee() (a ClaimAssignee, err error) { func (d *ClaimDescription) GetAssignee() (a *ClaimAssignee, err error) {
a = &ClaimAssignee{}
err = DBQueryRow("SELECT id_assignee, name FROM claim_assignees WHERE id_assignee = ?", d.IdAssignee).Scan(&a.Id, &a.Name) err = DBQueryRow("SELECT id_assignee, name FROM claim_assignees WHERE id_assignee = ?", d.IdAssignee).Scan(&a.Id, &a.Name)
return return
} }
// Update applies modifications back to the database // Update applies modifications back to the database
func (d ClaimDescription) Update() (int64, error) { func (d *ClaimDescription) Update() (int64, error) {
if res, err := DBExec("UPDATE claim_descriptions SET id_assignee = ?, content = ?, date = ?, publish = ? WHERE id_description = ?", d.IdAssignee, d.Content, d.Date, d.Publish, d.Id); err != nil { if res, err := DBExec("UPDATE claim_descriptions SET id_assignee = ?, content = ?, date = ?, publish = ? WHERE id_description = ?", d.IdAssignee, d.Content, d.Date, d.Publish, d.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -256,7 +264,7 @@ func (d ClaimDescription) Update() (int64, error) {
} }
// Delete the description in the database. // Delete the description in the database.
func (d ClaimDescription) Delete() (int64, error) { func (d *ClaimDescription) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM claim_descriptions WHERE id_description = ?", d.Id); err != nil { if res, err := DBExec("DELETE FROM claim_descriptions WHERE id_description = ?", d.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -273,13 +281,14 @@ type ClaimAssignee struct {
} }
// GetAssignee retrieves an assignee from its identifier. // GetAssignee retrieves an assignee from its identifier.
func GetAssignee(id int64) (a ClaimAssignee, err error) { func GetAssignee(id int64) (a *ClaimAssignee, err error) {
a = &ClaimAssignee{}
err = DBQueryRow("SELECT id_assignee, name FROM claim_assignees WHERE id_assignee = ?", id).Scan(&a.Id, &a.Name) err = DBQueryRow("SELECT id_assignee, name FROM claim_assignees WHERE id_assignee = ?", id).Scan(&a.Id, &a.Name)
return return
} }
// GetAssignees returns a list of all assignees found in the database. // GetAssignees returns a list of all assignees found in the database.
func GetAssignees() (res []ClaimAssignee, err error) { func GetAssignees() (res []*ClaimAssignee, err error) {
var rows *sql.Rows var rows *sql.Rows
if rows, err = DBQuery("SELECT id_assignee, name FROM claim_assignees"); err != nil { if rows, err = DBQuery("SELECT id_assignee, name FROM claim_assignees"); err != nil {
return return
@ -287,7 +296,7 @@ func GetAssignees() (res []ClaimAssignee, err error) {
defer rows.Close() defer rows.Close()
for rows.Next() { for rows.Next() {
var a ClaimAssignee a := &ClaimAssignee{}
if err = rows.Scan(&a.Id, &a.Name); err != nil { if err = rows.Scan(&a.Id, &a.Name); err != nil {
return return
} }
@ -299,18 +308,18 @@ func GetAssignees() (res []ClaimAssignee, err error) {
} }
// NewClaimAssignee creates and fills a new struct ClaimAssignee and registers it into the database. // NewClaimAssignee creates and fills a new struct ClaimAssignee and registers it into the database.
func NewClaimAssignee(name string) (ClaimAssignee, error) { func NewClaimAssignee(name string) (*ClaimAssignee, error) {
if res, err := DBExec("INSERT INTO claim_assignees (name) VALUES (?)", name); err != nil { if res, err := DBExec("INSERT INTO claim_assignees (name) VALUES (?)", name); err != nil {
return ClaimAssignee{}, err return nil, err
} else if aid, err := res.LastInsertId(); err != nil { } else if aid, err := res.LastInsertId(); err != nil {
return ClaimAssignee{}, err return nil, err
} else { } else {
return ClaimAssignee{aid, name}, nil return &ClaimAssignee{aid, name}, nil
} }
} }
// Update applies modifications back to the database // Update applies modifications back to the database
func (a ClaimAssignee) Update() (int64, error) { func (a *ClaimAssignee) Update() (int64, error) {
if res, err := DBExec("UPDATE claim_assignees SET name = ? WHERE id_assignee = ?", a.Name, a.Id); err != nil { if res, err := DBExec("UPDATE claim_assignees SET name = ? WHERE id_assignee = ?", a.Name, a.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -321,7 +330,7 @@ func (a ClaimAssignee) Update() (int64, error) {
} }
// Delete the assignee in the database. // Delete the assignee in the database.
func (a ClaimAssignee) Delete() (int64, error) { func (a *ClaimAssignee) Delete() (int64, error) {
if res, err := DBExec("DELETE FROM claim_assignees WHERE id_assignee = ?", a.Id); err != nil { if res, err := DBExec("DELETE FROM claim_assignees WHERE id_assignee = ?", a.Id); err != nil {
return 0, err return 0, err
} else if nb, err := res.RowsAffected(); err != nil { } else if nb, err := res.RowsAffected(); err != nil {
@ -343,18 +352,18 @@ func ClearAssignees() (int64, error) {
} }
// GetAssignee returns the assignee assigned to the claim. // GetAssignee returns the assignee assigned to the claim.
func (c Claim) GetAssignee() (*ClaimAssignee, error) { func (c *Claim) GetAssignee() (*ClaimAssignee, error) {
if c.IdAssignee == nil { if c.IdAssignee == nil {
return nil, nil return nil, nil
} else if a, err := GetAssignee(*c.IdAssignee); err != nil { } else if a, err := GetAssignee(*c.IdAssignee); err != nil {
return nil, err return nil, err
} else { } else {
return &a, nil return a, nil
} }
} }
// SetAssignee defines the assignee that'll handle the claim. // SetAssignee defines the assignee that'll handle the claim.
func (c Claim) SetAssignee(a ClaimAssignee) { func (c *Claim) SetAssignee(a ClaimAssignee) {
c.IdAssignee = &a.Id c.IdAssignee = &a.Id
} }
@ -375,8 +384,8 @@ type teamIssueFile struct {
Texts []teamIssueText `json:"texts"` Texts []teamIssueText `json:"texts"`
} }
func (t Team) MyIssueFile() (ret []teamIssueFile, err error) { func (t *Team) MyIssueFile() (ret []teamIssueFile, err error) {
var claims []Claim var claims []*Claim
if claims, err = t.GetClaims(); err == nil { if claims, err = t.GetClaims(); err == nil {
for _, claim := range claims { for _, claim := range claims {
var exercice *string = nil var exercice *string = nil
@ -395,7 +404,7 @@ func (t Team) MyIssueFile() (ret []teamIssueFile, err error) {
} }
if descriptions, err := claim.GetDescriptions(); err != nil { if descriptions, err := claim.GetDescriptions(); err != nil {
return nil, fmt.Errorf("Error occurs during description retrieval (cid=%d): %w", claim.Id, err) return nil, fmt.Errorf("error occurs during description retrieval (cid=%d): %w", claim.Id, err)
} else { } else {
tif := teamIssueFile{ tif := teamIssueFile{
Id: claim.Id, Id: claim.Id,
@ -411,7 +420,7 @@ func (t Team) MyIssueFile() (ret []teamIssueFile, err error) {
for _, description := range descriptions { for _, description := range descriptions {
if description.Publish { if description.Publish {
if people, err := description.GetAssignee(); err != nil { if people, err := description.GetAssignee(); err != nil {
return nil, fmt.Errorf("Error ocurs during assignee retrieval (aid=%d): %w", description.IdAssignee, err) return nil, fmt.Errorf("error ocurs during assignee retrieval (aid=%d): %w", description.IdAssignee, err)
} else { } else {
tif.Texts = append(tif.Texts, teamIssueText{ tif.Texts = append(tif.Texts, teamIssueText{
Content: description.Content, Content: description.Content,
@ -426,7 +435,7 @@ func (t Team) MyIssueFile() (ret []teamIssueFile, err error) {
} }
} }
} else { } else {
err = fmt.Errorf("Error occurs during claim retrieval: %w", err) err = fmt.Errorf("error occurs during claim retrieval: %w", err)
} }
return return

View file

@ -14,7 +14,7 @@ func init() {
router.GET("/api/exercices/:eid", apiHandler(exerciceHandler(showExercice))) router.GET("/api/exercices/:eid", apiHandler(exerciceHandler(showExercice)))
} }
func exerciceHandler(f func(QAUser, fic.Exercice, []byte) (interface{}, error)) func(QAUser, httprouter.Params, []byte) (interface{}, error) { func exerciceHandler(f func(QAUser, *fic.Exercice, []byte) (interface{}, error)) func(QAUser, httprouter.Params, []byte) (interface{}, error) {
return func(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) { return func(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) {
if eid, err := strconv.ParseInt(string(ps.ByName("eid")), 10, 64); err != nil { if eid, err := strconv.ParseInt(string(ps.ByName("eid")), 10, 64); err != nil {
return nil, err return nil, err
@ -31,6 +31,6 @@ func listExercices(_ QAUser, _ httprouter.Params, body []byte) (interface{}, err
return fic.GetExercices() return fic.GetExercices()
} }
func showExercice(_ QAUser, exercice fic.Exercice, body []byte) (interface{}, error) { func showExercice(_ QAUser, exercice *fic.Exercice, body []byte) (interface{}, error) {
return exercice, nil return exercice, nil
} }

View file

@ -23,9 +23,9 @@ func init() {
router.DELETE("/api/qa/:eid/:qid/comments/:cid", apiHandler(qaCommentHandler(deleteQAComment))) router.DELETE("/api/qa/:eid/:qid/comments/:cid", apiHandler(qaCommentHandler(deleteQAComment)))
} }
func qaHandler(f func(QAUser, fic.QAQuery, fic.Exercice, []byte) (interface{}, error)) func(QAUser, httprouter.Params, []byte) (interface{}, error) { func qaHandler(f func(QAUser, *fic.QAQuery, *fic.Exercice, []byte) (interface{}, error)) func(QAUser, httprouter.Params, []byte) (interface{}, error) {
return func(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) { return func(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) {
return exerciceHandler(func(u QAUser, exercice fic.Exercice, _ []byte) (interface{}, error) { return exerciceHandler(func(u QAUser, exercice *fic.Exercice, _ []byte) (interface{}, error) {
if qid, err := strconv.ParseInt(string(ps.ByName("qid")), 10, 64); err != nil { if qid, err := strconv.ParseInt(string(ps.ByName("qid")), 10, 64); err != nil {
return nil, err return nil, err
} else if query, err := exercice.GetQAQuery(qid); err != nil { } else if query, err := exercice.GetQAQuery(qid); err != nil {
@ -37,9 +37,9 @@ func qaHandler(f func(QAUser, fic.QAQuery, fic.Exercice, []byte) (interface{}, e
} }
} }
func qaCommentHandler(f func(QAUser, fic.QAComment, fic.QAQuery, fic.Exercice, []byte) (interface{}, error)) func(QAUser, httprouter.Params, []byte) (interface{}, error) { func qaCommentHandler(f func(QAUser, *fic.QAComment, *fic.QAQuery, *fic.Exercice, []byte) (interface{}, error)) func(QAUser, httprouter.Params, []byte) (interface{}, error) {
return func(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) { return func(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) {
return qaHandler(func(u QAUser, query fic.QAQuery, exercice fic.Exercice, _ []byte) (interface{}, error) { return qaHandler(func(u QAUser, query *fic.QAQuery, exercice *fic.Exercice, _ []byte) (interface{}, error) {
if cid, err := strconv.ParseInt(string(ps.ByName("cid")), 10, 64); err != nil { if cid, err := strconv.ParseInt(string(ps.ByName("cid")), 10, 64); err != nil {
return nil, err return nil, err
} else if comment, err := query.GetComment(cid); err != nil { } else if comment, err := query.GetComment(cid); err != nil {
@ -51,13 +51,13 @@ func qaCommentHandler(f func(QAUser, fic.QAComment, fic.QAQuery, fic.Exercice, [
} }
} }
func getExerciceQA(_ QAUser, exercice fic.Exercice, body []byte) (interface{}, error) { func getExerciceQA(_ QAUser, exercice *fic.Exercice, body []byte) (interface{}, error) {
return exercice.GetQAQueries() return exercice.GetQAQueries()
} }
func createExerciceQA(u QAUser, exercice fic.Exercice, body []byte) (interface{}, error) { func createExerciceQA(u QAUser, exercice *fic.Exercice, body []byte) (interface{}, error) {
// Create a new query // Create a new query
var uq fic.QAQuery var uq *fic.QAQuery
if err := json.Unmarshal(body, &uq); err != nil { if err := json.Unmarshal(body, &uq); err != nil {
return nil, err return nil, err
} }
@ -77,7 +77,7 @@ func createExerciceQA(u QAUser, exercice fic.Exercice, body []byte) (interface{}
if qa, err := exercice.NewQAQuery(uq.Subject, &u.TeamId, u.User, uq.State); err != nil { if qa, err := exercice.NewQAQuery(uq.Subject, &u.TeamId, u.User, uq.State); err != nil {
return nil, err return nil, err
} else { } else {
var uc fic.QAComment var uc *fic.QAComment
if err := json.Unmarshal(body, &uc); err != nil { if err := json.Unmarshal(body, &uc); err != nil {
return nil, err return nil, err
} }
@ -90,8 +90,8 @@ func createExerciceQA(u QAUser, exercice fic.Exercice, body []byte) (interface{}
} }
} }
func updateExerciceQA(u QAUser, query fic.QAQuery, exercice fic.Exercice, body []byte) (interface{}, error) { func updateExerciceQA(u QAUser, query *fic.QAQuery, exercice *fic.Exercice, body []byte) (interface{}, error) {
var uq fic.QAQuery var uq *fic.QAQuery
if err := json.Unmarshal(body, &uq); err != nil { if err := json.Unmarshal(body, &uq); err != nil {
return nil, err return nil, err
} }
@ -109,7 +109,7 @@ func updateExerciceQA(u QAUser, query fic.QAQuery, exercice fic.Exercice, body [
} }
} }
func deleteExerciceQA(u QAUser, query fic.QAQuery, exercice fic.Exercice, body []byte) (interface{}, error) { func deleteExerciceQA(u QAUser, query *fic.QAQuery, exercice *fic.Exercice, body []byte) (interface{}, error) {
if u.User != query.User { if u.User != query.User {
return nil, errors.New("You can only delete your own entry.") return nil, errors.New("You can only delete your own entry.")
} }
@ -117,13 +117,13 @@ func deleteExerciceQA(u QAUser, query fic.QAQuery, exercice fic.Exercice, body [
return query.Delete() return query.Delete()
} }
func getQAComments(_ QAUser, query fic.QAQuery, exercice fic.Exercice, body []byte) (interface{}, error) { func getQAComments(_ QAUser, query *fic.QAQuery, exercice *fic.Exercice, body []byte) (interface{}, error) {
return query.GetComments() return query.GetComments()
} }
func createQAComment(u QAUser, query fic.QAQuery, exercice fic.Exercice, body []byte) (interface{}, error) { func createQAComment(u QAUser, query *fic.QAQuery, exercice *fic.Exercice, body []byte) (interface{}, error) {
// Create a new query // Create a new query
var uc fic.QAComment var uc *fic.QAComment
if err := json.Unmarshal(body, &uc); err != nil { if err := json.Unmarshal(body, &uc); err != nil {
return nil, err return nil, err
} }
@ -135,7 +135,7 @@ func createQAComment(u QAUser, query fic.QAQuery, exercice fic.Exercice, body []
return query.AddComment(uc.Content, &u.TeamId, u.User) return query.AddComment(uc.Content, &u.TeamId, u.User)
} }
func deleteQAComment(u QAUser, comment fic.QAComment, query fic.QAQuery, exercice fic.Exercice, body []byte) (interface{}, error) { func deleteQAComment(u QAUser, comment *fic.QAComment, query *fic.QAQuery, exercice *fic.Exercice, body []byte) (interface{}, error) {
if u.User != comment.User { if u.User != comment.User {
return nil, errors.New("You can only delete your own comment.") return nil, errors.New("You can only delete your own comment.")
} }

View file

@ -19,7 +19,7 @@ func init() {
router.GET("/api/themes/:thid/exercices/:eid", apiHandler(exerciceHandler(showExercice))) router.GET("/api/themes/:thid/exercices/:eid", apiHandler(exerciceHandler(showExercice)))
} }
func themeHandler(f func(QAUser, fic.Theme, []byte) (interface{}, error)) func(QAUser, httprouter.Params, []byte) (interface{}, error) { func themeHandler(f func(QAUser, *fic.Theme, []byte) (interface{}, error)) func(QAUser, httprouter.Params, []byte) (interface{}, error) {
return func(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) { return func(u QAUser, ps httprouter.Params, body []byte) (interface{}, error) {
if thid, err := strconv.ParseInt(string(ps.ByName("thid")), 10, 64); err != nil { if thid, err := strconv.ParseInt(string(ps.ByName("thid")), 10, 64); err != nil {
return nil, err return nil, err
@ -31,13 +31,13 @@ func themeHandler(f func(QAUser, fic.Theme, []byte) (interface{}, error)) func(Q
} }
} }
func getExercice(args []string) (fic.Exercice, error) { func getExercice(args []string) (*fic.Exercice, error) {
if tid, err := strconv.ParseInt(string(args[0]), 10, 64); err != nil { if tid, err := strconv.ParseInt(string(args[0]), 10, 64); err != nil {
return fic.Exercice{}, err return nil, err
} else if theme, err := fic.GetTheme(tid); err != nil { } else if theme, err := fic.GetTheme(tid); err != nil {
return fic.Exercice{}, err return nil, err
} else if eid, err := strconv.Atoi(string(args[1])); err != nil { } else if eid, err := strconv.Atoi(string(args[1])); err != nil {
return fic.Exercice{}, err return nil, err
} else { } else {
return theme.GetExercice(eid) return theme.GetExercice(eid)
} }
@ -51,14 +51,14 @@ func exportThemes(_ QAUser, _ httprouter.Params, _ []byte) (interface{}, error)
return fic.ExportThemes() return fic.ExportThemes()
} }
func showTheme(_ QAUser, theme fic.Theme, _ []byte) (interface{}, error) { func showTheme(_ QAUser, theme *fic.Theme, _ []byte) (interface{}, error) {
return theme, nil return theme, nil
} }
func listThemedExercices(_ QAUser, theme fic.Theme, _ []byte) (interface{}, error) { func listThemedExercices(_ QAUser, theme *fic.Theme, _ []byte) (interface{}, error) {
return theme.GetExercices() return theme.GetExercices()
} }
func showThemedExercice(_ QAUser, theme fic.Theme, exercice fic.Exercice, body []byte) (interface{}, error) { func showThemedExercice(_ QAUser, theme *fic.Theme, exercice *fic.Exercice, body []byte) (interface{}, error) {
return exercice, nil return exercice, nil
} }

View file

@ -30,7 +30,7 @@ func getExerciceTested(u QAUser, ps httprouter.Params, body []byte) (interface{}
for _, exercice := range exercices { for _, exercice := range exercices {
if team.HasAccess(exercice) { if team.HasAccess(exercice) {
if ok, _ := team.HasSolved(exercice); ok { if t := team.HasSolved(exercice); t != nil {
ret[exercice.Id] = "solved" ret[exercice.Id] = "solved"
} else if cnt, _ := team.CountTries(exercice); cnt > 0 { } else if cnt, _ := team.CountTries(exercice); cnt > 0 {
ret[exercice.Id] = "tried" ret[exercice.Id] = "tried"
@ -74,7 +74,7 @@ func getQATodo(u QAUser, ps httprouter.Params, body []byte) (interface{}, error)
} else { } else {
for _, exercice := range exercices { for _, exercice := range exercices {
if cnt, _ := team.CountTries(exercice); cnt > 0 { if cnt, _ := team.CountTries(exercice); cnt > 0 {
todo = append(todo, fic.QATodo{0, team.Id, exercice.Id}) todo = append(todo, &fic.QATodo{0, team.Id, exercice.Id})
} }
} }
} }

View file

@ -106,7 +106,7 @@ func searchBinaryInGit(edir string) (ret []string) {
return return
} }
func checkExercice(theme fic.Theme, edir string, dmap *map[int64]fic.Exercice) (errs []string) { func checkExercice(theme *fic.Theme, edir string, dmap *map[int64]*fic.Exercice) (errs []string) {
e, _, eid, _, berrs := sync.BuildExercice(sync.GlobalImporter, theme, path.Join(theme.Path, edir), dmap) e, _, eid, _, berrs := sync.BuildExercice(sync.GlobalImporter, theme, path.Join(theme.Path, edir), dmap)
errs = append(errs, berrs...) errs = append(errs, berrs...)
@ -115,26 +115,26 @@ func checkExercice(theme fic.Theme, edir string, dmap *map[int64]fic.Exercice) (
var files []string var files []string
var cerrs []string var cerrs []string
if !skipFileChecks { if !skipFileChecks {
files, cerrs = sync.CheckExerciceFiles(sync.GlobalImporter, *e) files, cerrs = sync.CheckExerciceFiles(sync.GlobalImporter, e)
log.Printf("%d files checked.\n", len(files)) log.Printf("%d files checked.\n", len(files))
} else { } else {
files, cerrs = sync.CheckExerciceFilesPresence(sync.GlobalImporter, *e) files, cerrs = sync.CheckExerciceFilesPresence(sync.GlobalImporter, e)
log.Printf("%d files presents but not checked (please check digest yourself).\n", len(files)) log.Printf("%d files presents but not checked (please check digest yourself).\n", len(files))
} }
errs = append(errs, cerrs...) errs = append(errs, cerrs...)
// Flags // Flags
flags, cerrs := sync.CheckExerciceFlags(sync.GlobalImporter, *e, files) flags, cerrs := sync.CheckExerciceFlags(sync.GlobalImporter, e, files)
errs = append(errs, cerrs...) errs = append(errs, cerrs...)
log.Printf("%d flags checked.\n", len(flags)) log.Printf("%d flags checked.\n", len(flags))
// Hints // Hints
hints, cerrs := sync.CheckExerciceHints(sync.GlobalImporter, *e) hints, cerrs := sync.CheckExerciceHints(sync.GlobalImporter, e)
errs = append(errs, cerrs...) errs = append(errs, cerrs...)
log.Printf("%d hints checked.\n", len(hints)) log.Printf("%d hints checked.\n", len(hints))
if dmap != nil { if dmap != nil {
(*dmap)[int64(eid)] = *e (*dmap)[int64(eid)] = e
} }
} }
return return
@ -236,17 +236,17 @@ func main() {
log.Println(err) log.Println(err)
} }
exercices, err := sync.GetExercices(sync.GlobalImporter, *theme) exercices, err := sync.GetExercices(sync.GlobalImporter, theme)
if err != nil { if err != nil {
nberr += 1 nberr += 1
log.Println(err) log.Println(err)
continue continue
} }
dmap := map[int64]fic.Exercice{} dmap := map[int64]*fic.Exercice{}
for _, edir := range exercices { for _, edir := range exercices {
for _, err := range checkExercice(*theme, edir, &dmap) { for _, err := range checkExercice(theme, edir, &dmap) {
nberr += 1 nberr += 1
log.Println(err) log.Println(err)
} }
@ -267,7 +267,7 @@ func main() {
} else { } else {
log.Printf("This is not a theme directory, run checks for exercice.\n\n") log.Printf("This is not a theme directory, run checks for exercice.\n\n")
for _, err := range checkExercice(fic.Theme{}, p, &map[int64]fic.Exercice{}) { for _, err := range checkExercice(&fic.Theme{}, p, &map[int64]*fic.Exercice{}) {
nberr += 1 nberr += 1
log.Println(err) log.Println(err)
} }