package api import ( "encoding/json" "errors" "fmt" "path" "strconv" "strings" "srs.epita.fr/fic-server/admin/sync" "srs.epita.fr/fic-server/libfic" "srs.epita.fr/fic-server/settings" "github.com/julienschmidt/httprouter" ) func init() { router.GET("/api/themes", apiHandler(listThemes)) router.POST("/api/themes", apiHandler(createTheme)) router.GET("/api/themes.json", apiHandler(exportThemes)) router.GET("/api/session-forensic.yaml", apiHandler(func(_ httprouter.Params, _ []byte) (interface{}, error) { if s, err := settings.ReadSettings(path.Join(settings.SettingsDir, settings.SettingsFile)); err != nil { return nil, err } else if c, err := settings.ReadChallengeInfo(path.Join(settings.SettingsDir, settings.ChallengeFile)); err != nil { return nil, err } else { return fic.GenZQDSSessionFile(c, s) } })) router.GET("/api/files-bindings", apiHandler(bindingFiles)) router.GET("/api/themes/:thid", apiHandler(themeHandler(showTheme))) router.PUT("/api/themes/:thid", apiHandler(themeHandler(updateTheme))) router.DELETE("/api/themes/:thid", apiHandler(themeHandler(deleteTheme))) router.GET("/api/themes/:thid/exercices", apiHandler(themeHandler(listThemedExercices))) router.POST("/api/themes/:thid/exercices", apiHandler(themeHandler(createExercice))) router.GET("/api/themes/:thid/exercices_stats.json", apiHandler(themeHandler(getThemedExercicesStats))) router.GET("/api/themes/:thid/exercices/:eid", apiHandler(exerciceHandler(showExercice))) router.PUT("/api/themes/:thid/exercices/:eid", apiHandler(exerciceHandler(updateExercice))) router.DELETE("/api/themes/:thid/exercices/:eid", apiHandler(exerciceHandler(deleteExercice))) router.GET("/api/themes/:thid/exercices/:eid/files", apiHandler(exerciceHandler(listExerciceFiles))) router.POST("/api/themes/:thid/exercices/:eid/files", apiHandler(exerciceHandler(createExerciceFile))) router.GET("/api/themes/:thid/exercices/:eid/hints", apiHandler(exerciceHandler(listExerciceHints))) router.POST("/api/themes/:thid/exercices/:eid/hints", apiHandler(exerciceHandler(createExerciceHint))) router.GET("/api/themes/:thid/exercices/:eid/keys", apiHandler(exerciceHandler(listExerciceFlags))) router.POST("/api/themes/:thid/exercices/:eid/keys", apiHandler(exerciceHandler(createExerciceFlag))) // Remote router.GET("/api/remote/themes", apiHandler(sync.ApiListRemoteThemes)) router.GET("/api/remote/themes/:thid", apiHandler(sync.ApiGetRemoteTheme)) router.GET("/api/remote/themes/:thid/exercices", apiHandler(sync.ApiListRemoteExercices)) // Synchronize router.GET("/api/sync/deep", apiHandler( func(_ httprouter.Params, _ []byte) (interface{}, error) { if sync.DeepSyncProgress == 0 { return nil, errors.New("Pas de synchronisation en cours") } else { return map[string]interface{}{"progress": sync.DeepSyncProgress}, nil } })) router.POST("/api/sync/base", apiHandler( func(_ httprouter.Params, _ []byte) (interface{}, error) { err := sync.GlobalImporter.Sync() return true, err })) router.POST("/api/sync/speed", apiHandler( func(_ httprouter.Params, _ []byte) (interface{}, error) { st := sync.SpeedySyncDeep(sync.GlobalImporter) sync.EditDeepReport(st, false) return st, nil })) router.POST("/api/sync/deep", apiHandler( func(_ httprouter.Params, _ []byte) (interface{}, error) { return sync.SyncDeep(sync.GlobalImporter), nil })) router.POST("/api/sync/deep/:thid", apiHandler(themeHandler( func(theme *fic.Theme, _ []byte) (interface{}, error) { st := sync.SyncThemeDeep(sync.GlobalImporter, theme, 0, 250) sync.EditDeepReport(map[string][]string{theme.Name: st}, false) sync.DeepSyncProgress = 255 return st, nil }))) router.POST("/api/sync/auto/*p", apiHandler( func(ps httprouter.Params, _ []byte) (interface{}, error) { p := strings.TrimPrefix(ps.ByName("p"), "/") themes, err := fic.GetThemes() if err != nil { return nil, err } if p == "" { if !IsProductionEnv { for _, theme := range themes { theme.DeleteDeep() } } st := sync.SyncDeep(sync.GlobalImporter) return st, nil } for _, theme := range themes { if theme.Path == p { if !IsProductionEnv { exercices, err := theme.GetExercices() if err == nil { for _, exercice := range exercices { exercice.DeleteDeep() } } } st := sync.SyncThemeDeep(sync.GlobalImporter, theme, 0, 250) sync.EditDeepReport(map[string][]string{theme.Name: st}, false) sync.DeepSyncProgress = 255 settings.ForceRegeneration() return st, nil } } return nil, fmt.Errorf("Theme not found %q", p) })) router.POST("/api/sync/themes", apiHandler( func(_ httprouter.Params, _ []byte) (interface{}, error) { return sync.SyncThemes(sync.GlobalImporter), nil })) router.POST("/api/sync/themes/:thid/exercices", apiHandler(themeHandler( func(theme *fic.Theme, _ []byte) (interface{}, error) { return sync.SyncExercices(sync.GlobalImporter, theme), nil }))) router.POST("/api/sync/themes/:thid/exercices/:eid/files", apiHandler(exerciceHandler( func(exercice *fic.Exercice, _ []byte) (interface{}, error) { return sync.SyncExerciceFiles(sync.GlobalImporter, exercice), nil }))) router.POST("/api/sync/themes/:thid/exercices/:eid/hints", apiHandler(exerciceHandler( func(exercice *fic.Exercice, _ []byte) (interface{}, error) { _, errs := sync.SyncExerciceHints(sync.GlobalImporter, exercice, sync.ExerciceFlagsMap(sync.GlobalImporter, exercice)) return errs, nil }))) router.POST("/api/sync/themes/:thid/exercices/:eid/keys", apiHandler(exerciceHandler( func(exercice *fic.Exercice, _ []byte) (interface{}, error) { _, errs := sync.SyncExerciceFlags(sync.GlobalImporter, exercice) _, herrs := sync.SyncExerciceHints(sync.GlobalImporter, exercice, sync.ExerciceFlagsMap(sync.GlobalImporter, exercice)) return append(errs, herrs...), nil }))) router.POST("/api/sync/themes/:thid/fixurlid", apiHandler(themeHandler( func(theme *fic.Theme, _ []byte) (interface{}, error) { if theme.FixURLId() { return theme.Update() } return 0, nil }))) router.POST("/api/sync/fixurlids", apiHandler(fixAllURLIds)) } func fixAllURLIds(_ httprouter.Params, _ []byte) (interface{}, error) { nbFix := 0 if themes, err := fic.GetThemes(); err == nil { for _, theme := range themes { if theme.FixURLId() { theme.Update() nbFix += 1 } if exercices, err := theme.GetExercices(); err == nil { for _, exercice := range exercices { if exercice.FixURLId() { exercice.Update() nbFix += 1 } } } } } return nbFix, nil } func bindingFiles(_ httprouter.Params, body []byte) (interface{}, error) { if files, err := fic.GetFiles(); err != nil { return "", err } else { ret := "" for _, file := range files { ret += fmt.Sprintf("%s;%s\n", file.GetOrigin(), file.Path) } return ret, nil } } func getExercice(args []string) (*fic.Exercice, error) { if tid, err := strconv.ParseInt(string(args[0]), 10, 64); err != nil { return nil, err } else if theme, err := fic.GetTheme(tid); err != nil { return nil, err } else if eid, err := strconv.Atoi(string(args[1])); err != nil { return nil, err } else { return theme.GetExercice(eid) } } func listThemes(_ httprouter.Params, _ []byte) (interface{}, error) { return fic.GetThemes() } func exportThemes(_ httprouter.Params, _ []byte) (interface{}, error) { return fic.ExportThemes() } func showTheme(theme *fic.Theme, _ []byte) (interface{}, error) { return theme, nil } func listThemedExercices(theme *fic.Theme, _ []byte) (interface{}, error) { return theme.GetExercices() } func showThemedExercice(theme *fic.Theme, exercice fic.Exercice, body []byte) (interface{}, error) { return exercice, nil } func createTheme(_ httprouter.Params, body []byte) (interface{}, error) { var ut fic.Theme if err := json.Unmarshal(body, &ut); err != nil { return nil, err } if len(ut.Name) == 0 { return nil, errors.New("Theme's name not filled") } return fic.CreateTheme(&ut) } func updateTheme(theme *fic.Theme, body []byte) (interface{}, error) { var ut fic.Theme if err := json.Unmarshal(body, &ut); err != nil { return nil, err } ut.Id = theme.Id if len(ut.Name) == 0 { return nil, errors.New("Theme's name not filled") } if _, err := ut.Update(); err != nil { return nil, err } else { return ut, nil } } func deleteTheme(theme *fic.Theme, _ []byte) (interface{}, error) { return theme.Delete() } func getThemedExercicesStats(theme *fic.Theme, body []byte) (interface{}, error) { if exercices, err := theme.GetExercices(); err != nil { return nil, err } else { ret := []exerciceStats{} for _, e := range exercices { ret = append(ret, exerciceStats{ IdExercice: e.Id, TeamTries: e.TriedTeamCount(), TotalTries: e.TriedCount(), SolvedCount: e.SolvedCount(), FlagSolved: e.FlagSolved(), MCQSolved: e.MCQSolved(), }) } return ret, nil } }