Use github.com/julienschmidt/httprouter instead of gorilla

This commit is contained in:
nemunaire 2016-12-16 00:51:56 +01:00
parent 5a0b81ba32
commit 3b320469b5
13 changed files with 226 additions and 172 deletions

View File

@ -5,25 +5,26 @@ import (
"os" "os"
"srs.epita.fr/fic-server/libfic" "srs.epita.fr/fic-server/libfic"
"github.com/julienschmidt/httprouter"
) )
func init() { func init() {
router.Path("/ca").Methods("GET").HandlerFunc(apiHandler(genCA)) router.GET("/api/ca", apiHandler(genCA))
rt := router.PathPrefix("/teams/{tid}/certificate").Subrouter() router.GET("/api/teams/:tid/certificate/", apiHandler(teamHandler(GetTeamCertificate)))
rt.Path("/").Methods("GET").HandlerFunc(apiHandler(teamHandler(GetTeamCertificate))) router.GET("/api/teams/:tid/certificate/generate", apiHandler(teamHandler(
rt.Path("/generate").Methods("GET").HandlerFunc(apiHandler(teamHandler( func(team fic.Team, _ []byte) (interface{}, error) { return team.GenerateCert(), nil })))
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) { return team.GenerateCert(), nil }))) router.GET("/api/teams/:tid/certificate/revoke", apiHandler(teamHandler(
rt.Path("/revoke").Methods("GET").HandlerFunc(apiHandler(teamHandler( func(team fic.Team, _ []byte) (interface{}, error) { return team.RevokeCert(), nil })))
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) { return team.RevokeCert(), nil })))
} }
func genCA(args map[string]string, body []byte) (interface{}, error) { func genCA(_ httprouter.Params, body []byte) (interface{}, error) {
return fic.GenerateCA(), nil return fic.GenerateCA(), nil
} }
func GetTeamCertificate(team fic.Team, args map[string]string, body []byte) (interface{}, error) { func GetTeamCertificate(team fic.Team, body []byte) (interface{}, error) {
if fd, err := os.Open("../PKI/pkcs/" + team.Name + ".p12"); err == nil { if fd, err := os.Open("../PKI/pkcs/" + team.Name + ".p12"); err == nil {
return ioutil.ReadAll(fd) return ioutil.ReadAll(fd)
} else { } else {
return nil, err return nil, err

View File

@ -2,13 +2,15 @@ package api
import ( import (
"srs.epita.fr/fic-server/libfic" "srs.epita.fr/fic-server/libfic"
"github.com/julienschmidt/httprouter"
) )
func init() { func init() {
router.Path("/events/").Methods("GET").HandlerFunc(apiHandler(getEvents)) router.GET("/api/events/", apiHandler(getEvents))
} }
func getEvents(args map[string]string, body []byte) (interface{}, error) { func getEvents(_ httprouter.Params, _ []byte) (interface{}, error) {
if evts, err := fic.GetEvents(); err != nil { if evts, err := fic.GetEvents(); err != nil {
return nil, err return nil, err
} else { } else {

View File

@ -6,27 +6,29 @@ import (
"strconv" "strconv"
"srs.epita.fr/fic-server/libfic" "srs.epita.fr/fic-server/libfic"
"github.com/julienschmidt/httprouter"
) )
func init() { func init() {
router.Path("/exercices/").Methods("GET").HandlerFunc(apiHandler(listExercices)) router.GET("/api/exercices/", apiHandler(listExercices))
re := router.Path("/exercices/{eid:[0-9]+}").Subrouter()
re.Methods("GET").HandlerFunc(apiHandler(exerciceHandler(showExercice))) router.GET("/api/exercices/:eid", apiHandler(exerciceHandler(showExercice)))
re.Methods("PUT").HandlerFunc(apiHandler(updateExercice)) router.PUT("/api/exercices/:eid", apiHandler(updateExercice))
re.Methods("DELETE").HandlerFunc(apiHandler(deleteExercice)) router.DELETE("/api/exercices/:eid", apiHandler(deleteExercice))
} }
func listExercices(args map[string]string, body []byte) (interface{}, error) { func listExercices(_ httprouter.Params, body []byte) (interface{}, error) {
// List all exercices // List all exercices
return fic.GetExercices() return fic.GetExercices()
} }
func showExercice(exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) { func showExercice(exercice fic.Exercice, body []byte) (interface{}, error) {
return exercice, nil return exercice, nil
} }
func deleteExercice(args map[string]string, body []byte) (interface{}, error) { func deleteExercice(ps httprouter.Params, body []byte) (interface{}, error) {
if eid, err := strconv.Atoi(args["eid"]); err != nil { if eid, err := strconv.Atoi(ps.ByName("eid")); err != nil {
return nil, err return nil, err
} else if exercice, err := fic.GetExercice(int64(eid)); err != nil { } else if exercice, err := fic.GetExercice(int64(eid)); err != nil {
return nil, err return nil, err
@ -43,8 +45,8 @@ type uploadedExercice struct {
VideoURI string VideoURI string
} }
func updateExercice(args map[string]string, body []byte) (interface{}, error) { func updateExercice(ps httprouter.Params, body []byte) (interface{}, error) {
if eid, err := strconv.Atoi(args["eid"]); err != nil { if eid, err := strconv.Atoi(ps.ByName("eid")); err != nil {
return nil, err return nil, err
} else if exercice, err := fic.GetExercice(int64(eid)); err != nil { } else if exercice, err := fic.GetExercice(int64(eid)); err != nil {
return nil, err return nil, err
@ -75,7 +77,7 @@ func updateExercice(args map[string]string, body []byte) (interface{}, error) {
} }
} }
func createExercice(theme fic.Theme, args map[string]string, body []byte) (interface{}, error) { func createExercice(theme fic.Theme, body []byte) (interface{}, error) {
// Create a new exercice // Create a new exercice
var ue uploadedExercice var ue uploadedExercice
if err := json.Unmarshal(body, &ue); err != nil { if err := json.Unmarshal(body, &ue); err != nil {
@ -103,7 +105,7 @@ type uploadedKey struct {
Key string Key string
} }
func createExerciceKey(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) { func createExerciceKey(theme fic.Theme, exercice fic.Exercice, body []byte) (interface{}, error) {
var uk uploadedKey var uk uploadedKey
if err := json.Unmarshal(body, &uk); err != nil { if err := json.Unmarshal(body, &uk); err != nil {
return nil, err return nil, err
@ -122,7 +124,7 @@ type uploadedHint struct {
Cost int64 Cost int64
} }
func createExerciceHint(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) { func createExerciceHint(theme fic.Theme, 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

View File

@ -27,7 +27,7 @@ type uploadedFile struct {
Parts []string Parts []string
} }
func createExerciceFile(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) { func createExerciceFile(theme fic.Theme, 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

View File

@ -10,14 +10,14 @@ import (
"srs.epita.fr/fic-server/libfic" "srs.epita.fr/fic-server/libfic"
"github.com/gorilla/mux" "github.com/julienschmidt/httprouter"
) )
type DispatchFunction func([]string, []byte) (interface{}, error) type DispatchFunction func(httprouter.Params, []byte) (interface{}, error)
func apiHandler(f func (map[string]string,[]byte) (interface{}, error)) func(http.ResponseWriter, *http.Request) { func apiHandler(f DispatchFunction) func(http.ResponseWriter, *http.Request, httprouter.Params) {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
log.Printf("Handling %s request from %s: %s [%s]\n", r.Method, r.RemoteAddr, r.URL.Path, r.UserAgent()) log.Printf("Handling %s request from %s: %s [%s]\n", r.Method, r.RemoteAddr, r.URL.Path, r.UserAgent())
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
@ -44,7 +44,7 @@ func apiHandler(f func (map[string]string,[]byte) (interface{}, error)) func(htt
} }
} }
ret, err = f(mux.Vars(r), body) ret, err = f(ps, body)
// Format response // Format response
resStatus := http.StatusOK resStatus := http.StatusOK
@ -74,58 +74,83 @@ func apiHandler(f func (map[string]string,[]byte) (interface{}, error)) func(htt
} }
} }
func teamHandler(f func(fic.Team,map[string]string,[]byte) (interface{}, error)) func (map[string]string,[]byte) (interface{}, error) { func teamPublicHandler(f func(*fic.Team,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) {
return func (args map[string]string, body []byte) (interface{}, error) { return func (ps httprouter.Params, body []byte) (interface{}, error) {
if tid, err := strconv.Atoi(string(args["tid"])); err != nil { if tid, err := strconv.Atoi(string(ps.ByName("tid"))); err != nil {
if team, err := fic.GetTeamByInitialName(args["tid"]); err != nil { if team, err := fic.GetTeamByInitialName(ps.ByName("tid")); err != nil {
return nil, err return nil, err
} else { } else {
return f(team, args, body) return f(&team, body)
}
} else if tid == 0 {
return f(nil, body)
} else if team, err := fic.GetTeam(tid); err != nil {
return nil, err
} else {
return f(&team, body)
}
}
}
func teamHandler(f func(fic.Team,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) {
return func (ps httprouter.Params, body []byte) (interface{}, error) {
if tid, err := strconv.Atoi(string(ps.ByName("tid"))); err != nil {
if team, err := fic.GetTeamByInitialName(ps.ByName("tid")); err != nil {
return nil, err
} else {
return f(team, body)
} }
} 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, args, body) return f(team, body)
} }
} }
} }
func themeHandler(f func(fic.Theme,map[string]string,[]byte) (interface{}, error)) func (map[string]string,[]byte) (interface{}, error) { func themeHandler(f func(fic.Theme,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) {
return func (args map[string]string, body []byte) (interface{}, error) { return func (ps httprouter.Params, body []byte) (interface{}, error) {
if tid, err := strconv.Atoi(string(args["tid"])); err != nil { if thid, err := strconv.Atoi(string(ps.ByName("thid"))); err != nil {
return nil, err return nil, err
} else if theme, err := fic.GetTheme(tid); err != nil { } else if theme, err := fic.GetTheme(thid); err != nil {
return nil, err return nil, err
} else { } else {
return f(theme, args, body) return f(theme, body)
} }
} }
} }
func exerciceHandler(f func(fic.Exercice,map[string]string,[]byte) (interface{}, error)) func (map[string]string,[]byte) (interface{}, error) { func exerciceHandler(f func(fic.Exercice,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) {
return func (args map[string]string, body []byte) (interface{}, error) { return func (ps httprouter.Params, body []byte) (interface{}, error) {
if eid, err := strconv.Atoi(string(args["eid"])); err != nil { if eid, err := strconv.Atoi(string(ps.ByName("eid"))); err != nil {
return nil, err return nil, err
} else if exercice, err := fic.GetExercice(int64(eid)); err != nil { } else if exercice, err := fic.GetExercice(int64(eid)); err != nil {
return nil, err return nil, err
} else { } else {
return f(exercice, args, body) return f(exercice, body)
} }
} }
} }
func themedExerciceHandler(f func(fic.Theme,fic.Exercice,map[string]string,[]byte) (interface{}, error)) func (fic.Theme,map[string]string,[]byte) (interface{}, error) { func themedExerciceHandler(f func(fic.Theme,fic.Exercice,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) {
return func (theme fic.Theme, args map[string]string, body []byte) (interface{}, error) { return func (ps httprouter.Params, body []byte) (interface{}, error) {
if eid, err := strconv.Atoi(string(args["eid"])); err != nil { var theme fic.Theme
return nil, err var exercice fic.Exercice
} else if exercice, err := fic.GetExercice(int64(eid)); err != nil {
return nil, err themeHandler(func (th fic.Theme, _[]byte) (interface{}, error) {
} else { theme = th
return f(theme, exercice, args, body) return nil,nil
} })(ps, body)
exerciceHandler(func (ex fic.Exercice, _[]byte) (interface{}, error) {
exercice = ex
return nil,nil
})(ps, body)
return f(theme, exercice, body)
} }
} }
func notFound(args map[string]string, body []byte) (interface{}, error) { func notFound(ps httprouter.Params, _ []byte) (interface{}, error) {
return nil, nil return nil, nil
} }

View File

@ -1,14 +1,11 @@
package api package api
import ( import (
"github.com/gorilla/mux" "github.com/julienschmidt/httprouter"
) )
var api_router = mux.NewRouter().StrictSlash(true) var router = httprouter.New()
var router = api_router.PathPrefix("/api/").Subrouter() func Router() *httprouter.Router {
return router
func Router() *mux.Router {
return api_router
} }

View File

@ -6,66 +6,59 @@ import (
"strings" "strings"
"srs.epita.fr/fic-server/libfic" "srs.epita.fr/fic-server/libfic"
"github.com/julienschmidt/httprouter"
) )
func init() { func init() {
rts := router.PathPrefix("/teams").Subrouter() router.GET("/api/teams.json", apiHandler(
router.Path("/teams.json").Methods("GET").HandlerFunc(apiHandler( func(httprouter.Params,[]byte) (interface{}, error) {
func(map[string]string,[]byte) (interface{}, error) {
return fic.ExportTeams() })) return fic.ExportTeams() }))
rts.Path("/").Methods("GET").HandlerFunc(apiHandler( router.GET("/api/teams-binding", apiHandler(
func(map[string]string,[]byte) (interface{}, error) { func(httprouter.Params,[]byte) (interface{}, error) {
return fic.GetTeams() }))
rts.Path("/binding").Methods("GET").HandlerFunc(apiHandler(
func(map[string]string,[]byte) (interface{}, error) {
return bindingTeams() })) return bindingTeams() }))
rts.Path("/nginx").Methods("GET").HandlerFunc(apiHandler( router.GET("/api/teams-nginx", apiHandler(
func(map[string]string,[]byte) (interface{}, error) { func(httprouter.Params,[]byte) (interface{}, error) {
return nginxGenTeam() })) return nginxGenTeam() }))
rts.Path("/nginx-members").Methods("GET").HandlerFunc(apiHandler( router.GET("/api/teams-nginx-members", apiHandler(
func(map[string]string,[]byte) (interface{}, error) { func(httprouter.Params,[]byte) (interface{}, error) {
return nginxGenMember() })) return nginxGenMember() }))
rts.Path("/binding").Methods("GET").HandlerFunc(apiHandler( router.GET("/api/teams-tries.json", apiHandler(
func(map[string]string,[]byte) (interface{}, error) { func(httprouter.Params,[]byte) (interface{}, error) {
return fic.GetTries(nil, nil) })) return fic.GetTries(nil, nil) }))
rts.Path("/0/my.json").Methods("GET").HandlerFunc(apiHandler( router.GET("/api/teams/", apiHandler(
func(map[string]string,[]byte) (interface{}, error) { func(httprouter.Params,[]byte) (interface{}, error) {
return fic.MyJSONTeam(nil, true) })) return fic.GetTeams() }))
rts.Path("/0/wait.json").Methods("GET").HandlerFunc(apiHandler(
func(map[string]string,[]byte) (interface{}, error) {
return fic.MyJSONTeam(nil, false) }))
rts.Path("/0/stats.json").Methods("GET").HandlerFunc(apiHandler(
func(map[string]string,[]byte) (interface{}, error) {
return fic.GetTeamsStats(nil) }))
rts.Path("/0/tries").Methods("GET").HandlerFunc(apiHandler(
func(map[string]string,[]byte) (interface{}, error) {
return fic.GetTries(nil, nil) }))
rt := rts.PathPrefix("/{tid}").Subrouter() router.GET("/api/teams/:tid/", apiHandler(teamHandler(
rt.Path("/").Methods("GET").HandlerFunc(apiHandler(teamHandler( func(team fic.Team, _ []byte) (interface{}, error) {
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) {
return team, nil }))) return team, nil })))
rt.Path("/").Methods("DELETE").HandlerFunc(apiHandler(teamHandler( router.DELETE("/api/teams/:tid/", apiHandler(teamHandler(
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) { func(team fic.Team, _ []byte) (interface{}, error) {
return team.Delete() }))) return team.Delete() })))
rt.Path("/my.json").Methods("GET").HandlerFunc(apiHandler(teamHandler( router.GET("/api/teams/:tid/my.json", apiHandler(teamPublicHandler(
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
return fic.MyJSONTeam(&team, true) }))) return fic.MyJSONTeam(team, true) })))
rt.Path("/wait.json").Methods("GET").HandlerFunc(apiHandler(teamHandler( router.GET("/api/teams/:tid/wait.json", apiHandler(teamPublicHandler(
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
return fic.MyJSONTeam(&team, false) }))) return fic.MyJSONTeam(team, false) })))
rt.Path("/stats.json").Methods("GET").HandlerFunc(apiHandler(teamHandler( router.GET("/api/teams/:tid/stats.json", apiHandler(teamPublicHandler(
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) { func(team *fic.Team, _ []byte) (interface{}, error) {
return team.GetStats() }))) if team != nil {
rt.Path("/tries").Methods("GET").HandlerFunc(apiHandler(teamHandler( return team.GetStats()
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) { } else {
return fic.GetTries(&team, nil) }))) return fic.GetTeamsStats(nil)
rt.Path("/members").Methods("GET").HandlerFunc(apiHandler(teamHandler( }
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) { })))
router.GET("/api/teams/:tid/tries", apiHandler(teamPublicHandler(
func(team *fic.Team, _ []byte) (interface{}, error) {
return fic.GetTries(team, nil) })))
router.GET("/api/teams/:tid/members", apiHandler(teamHandler(
func(team fic.Team, _ []byte) (interface{}, error) {
return team.GetMembers() }))) return team.GetMembers() })))
rt.Path("/name").Methods("GET").HandlerFunc(apiHandler(teamHandler( router.GET("/api/teams/:tid/name", apiHandler(teamHandler(
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) { func(team fic.Team, _ []byte) (interface{}, error) {
return team.Name, nil }))) return team.Name, nil })))
} }

View File

@ -7,42 +7,39 @@ import (
"strconv" "strconv"
"srs.epita.fr/fic-server/libfic" "srs.epita.fr/fic-server/libfic"
"github.com/julienschmidt/httprouter"
) )
func init() { func init() {
router.Path("/themes/").Methods("GET").HandlerFunc(apiHandler(listThemes)) router.GET("/api/themes", apiHandler(listThemes))
router.Path("/themes/").Methods("POST").HandlerFunc(apiHandler(createTheme)) router.POST("/api/themes", apiHandler(createTheme))
router.Path("/themes.json").Methods("GET").HandlerFunc(apiHandler(exportThemes)) router.GET("/api/themes.json", apiHandler(exportThemes))
router.Path("/themes/files-bindings").Methods("GET").HandlerFunc(apiHandler(bindingFiles)) router.GET("/api/files-bindings", apiHandler(bindingFiles))
rt := router.PathPrefix("/themes/{tid:[0-9]+}").Subrouter() router.GET("/api/themes/:thid", apiHandler(themeHandler(showTheme)))
rt.Path("/").Methods("GET").HandlerFunc(apiHandler(themeHandler(showTheme))) router.PUT("/api/themes/:thid", apiHandler(themeHandler(updateTheme)))
rt.Path("/").Methods("PUT").HandlerFunc(apiHandler(themeHandler(updateTheme))) router.DELETE("/api/themes/:thid", apiHandler(themeHandler(deleteTheme)))
rt.Path("/").Methods("DELETE").HandlerFunc(apiHandler(themeHandler(deleteTheme)))
rtes := rt.PathPrefix("/exercices").Subrouter() router.GET("/api/themes/:thid/exercices", apiHandler(themeHandler(listThemedExercices)))
rtes.Path("/").Methods("GET").HandlerFunc(apiHandler(themeHandler(listThemedExercices))) router.POST("/api/themes/:thid/exercices", apiHandler(themeHandler(createExercice)))
rtes.Path("/").Methods("POST").HandlerFunc(apiHandler(themeHandler(createExercice)))
rte := rtes.PathPrefix("/{eid:[0-9]+}").Subrouter() router.GET("/api/themes/:thid/exercices/:eid", apiHandler(themedExerciceHandler(showThemedExercice)))
rte.Path("/").Methods("GET").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(showThemedExercice)))) router.PUT("/api/themes/:thid/exercices/:eid", apiHandler(themedExerciceHandler(updateThemedExercice)))
rte.Path("/").Methods("PUT").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(updateThemedExercice)))) router.DELETE("/api/themes/:thid/exercices/:eid", apiHandler(themedExerciceHandler(deleteThemedExercice)))
rte.Path("/").Methods("DELETE").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(deleteThemedExercice))))
rtef := rte.Path("/files").Subrouter()
rtef.Methods("GET").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(listThemedExerciceFiles))))
rtef.Methods("POST").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(createExerciceFile))))
rteh := rte.Path("/hints").Subrouter() router.GET("/api/themes/:thid/exercices/:eid/files", apiHandler(themedExerciceHandler(listThemedExerciceFiles)))
rteh.Methods("GET").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(listThemedExerciceHints)))) router.POST("/api/themes/:thid/exercices/:eid/files", apiHandler(themedExerciceHandler(createExerciceFile)))
rteh.Methods("POST").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(createExerciceHint))))
rtek := rte.Path("/keys").Subrouter() router.GET("/api/themes/:thid/exercices/:eid/hints", apiHandler(themedExerciceHandler(listThemedExerciceHints)))
rtek.Methods("GET").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(listThemedExerciceKeys)))) router.POST("/api/themes/:thid/exercices/:eid/hints", apiHandler(themedExerciceHandler(createExerciceHint)))
rtek.Methods("POST").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(createExerciceKey))))
router.GET("/api/themes/:thid/exercices/:eid/keys", apiHandler(themedExerciceHandler(listThemedExerciceKeys)))
router.POST("/api/themes/:thid/exercices/:eid/keys", apiHandler(themedExerciceHandler(createExerciceKey)))
} }
func bindingFiles(args map[string]string, body []byte) (interface{}, error) { func bindingFiles(_ httprouter.Params, body []byte) (interface{}, error) {
if files, err := fic.GetFiles(); err != nil { if files, err := fic.GetFiles(); err != nil {
return "", err return "", err
} else { } else {
@ -66,35 +63,35 @@ func getExercice(args []string) (fic.Exercice, error) {
} }
} }
func listThemes(args map[string]string, body []byte) (interface{}, error) { func listThemes(_ httprouter.Params, _ []byte) (interface{}, error) {
return fic.GetThemes() return fic.GetThemes()
} }
func exportThemes(args map[string]string, body []byte) (interface{}, error) { func exportThemes(_ httprouter.Params, _ []byte) (interface{}, error) {
return fic.ExportThemes() return fic.ExportThemes()
} }
func showTheme(theme fic.Theme, args map[string]string, body []byte) (interface{}, error) { func showTheme(theme fic.Theme, _ []byte) (interface{}, error) {
return theme, nil return theme, nil
} }
func listThemedExercices(theme fic.Theme, args map[string]string, body []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, args map[string]string, body []byte) (interface{}, error) { func showThemedExercice(theme fic.Theme, exercice fic.Exercice, body []byte) (interface{}, error) {
return exercice, nil return exercice, nil
} }
func listThemedExerciceFiles(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) { func listThemedExerciceFiles(theme fic.Theme, exercice fic.Exercice, body []byte) (interface{}, error) {
return exercice.GetFiles() return exercice.GetFiles()
} }
func listThemedExerciceHints(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) { func listThemedExerciceHints(theme fic.Theme, exercice fic.Exercice, body []byte) (interface{}, error) {
return exercice.GetHints() return exercice.GetHints()
} }
func listThemedExerciceKeys(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) { func listThemedExerciceKeys(theme fic.Theme, exercice fic.Exercice, body []byte) (interface{}, error) {
return exercice.GetKeys() return exercice.GetKeys()
} }
@ -104,7 +101,7 @@ type uploadedTheme struct {
Authors string Authors string
} }
func createTheme(args map[string]string, body []byte) (interface{}, error) { func createTheme(_ httprouter.Params, body []byte) (interface{}, error) {
var ut uploadedTheme var ut uploadedTheme
if err := json.Unmarshal(body, &ut); err != nil { if err := json.Unmarshal(body, &ut); err != nil {
return nil, err return nil, err
@ -117,7 +114,7 @@ func createTheme(args map[string]string, body []byte) (interface{}, error) {
return fic.CreateTheme(ut.Name, ut.Authors) return fic.CreateTheme(ut.Name, ut.Authors)
} }
func updateTheme(theme fic.Theme, args map[string]string, 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
@ -132,7 +129,7 @@ func updateTheme(theme fic.Theme, args map[string]string, body []byte) (interfac
return ut.Update() return ut.Update()
} }
func updateThemedExercice(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) { func updateThemedExercice(theme fic.Theme, exercice fic.Exercice, body []byte) (interface{}, error) {
// Update an exercice // Update an 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 {
@ -152,10 +149,10 @@ func updateThemedExercice(theme fic.Theme, exercice fic.Exercice, args map[strin
return ue, nil return ue, nil
} }
func deleteTheme(theme fic.Theme, args map[string]string, body []byte) (interface{}, error) { func deleteTheme(theme fic.Theme, _ []byte) (interface{}, error) {
return theme.Delete() return theme.Delete()
} }
func deleteThemedExercice(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) { func deleteThemedExercice(_ fic.Theme, exercice fic.Exercice, _ []byte) (interface{}, error) {
return exercice.Delete() return exercice.Delete()
} }

View File

@ -1,11 +1,13 @@
package api package api
import () import (
"github.com/julienschmidt/httprouter"
)
func init() { func init() {
router.Path("/version").Methods("GET").HandlerFunc(apiHandler(showVersion)) router.GET("/api/version", apiHandler(showVersion))
} }
func showVersion(args map[string]string, body []byte) (interface{}, error) { func showVersion(_ httprouter.Params, body []byte) (interface{}, error) {
return map[string]interface{}{"version": 0.1}, nil return map[string]interface{}{"version": 0.1}, nil
} }

View File

@ -8,7 +8,7 @@ CLOUDPASS=fic:'f>t\nV33R|(+?$i*'
new_theme() { new_theme() {
NAME=`echo $1 | sed 's/"/\\\\"/g'` NAME=`echo $1 | sed 's/"/\\\\"/g'`
AUTHORS=`echo $2 | sed 's/"/\\\\"/g'` AUTHORS=`echo $2 | sed 's/"/\\\\"/g'`
curl -f -s -d "{\"name\": \"$NAME\", \"authors\": \"$AUTHORS\"}" "${BASEURL}/api/themes/" | curl -f -s -d "{\"name\": \"$NAME\", \"authors\": \"$AUTHORS\"}" "${BASEURL}/api/themes" |
grep -Eo '"id":[0-9]+,' | grep -Eo "[0-9]+" grep -Eo '"id":[0-9]+,' | grep -Eo "[0-9]+"
} }
@ -20,7 +20,7 @@ new_exercice() {
GAIN="$5" GAIN="$5"
VIDEO="$6" VIDEO="$6"
curl -f -s -d "{\"title\": \"$TITLE\", \"statement\": \"$STATEMENT\", \"depend\": $DEPEND, \"gain\": $GAIN, \"videoURI\": \"$VIDEO\"}" "${BASEURL}/api/themes/$THEME/exercices/" | curl -f -s -d "{\"title\": \"$TITLE\", \"statement\": \"$STATEMENT\", \"depend\": $DEPEND, \"gain\": $GAIN, \"videoURI\": \"$VIDEO\"}" "${BASEURL}/api/themes/$THEME/exercices" |
grep -Eo '"id":[0-9]+,' | grep -Eo "[0-9]+" grep -Eo '"id":[0-9]+,' | grep -Eo "[0-9]+"
} }

View File

@ -51,6 +51,13 @@ func main() {
if fic.FilesDir, err = filepath.Abs(fic.FilesDir); err != nil { if fic.FilesDir, err = filepath.Abs(fic.FilesDir); err != nil {
log.Fatal(err) log.Fatal(err)
} }
if *baseURL != "/" {
tmp := path.Clean(*baseURL)
baseURL = &tmp
} else {
tmp := ""
baseURL = &tmp
}
log.Println("Opening database...") log.Println("Opening database...")
if err := fic.DBInit(fmt.Sprintf("%s?parseTime=true", *dsn)); err != nil { if err := fic.DBInit(fmt.Sprintf("%s?parseTime=true", *dsn)); err != nil {
@ -63,12 +70,12 @@ func main() {
log.Fatal("Cannot create database: ", err) log.Fatal("Cannot create database: ", err)
} }
log.Println("Changing base url...") log.Println("Changing base URL to", *baseURL,"...")
if file, err := os.OpenFile(path.Join(StaticDir, "index.html"), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0644)); err != nil { if file, err := os.OpenFile(path.Join(StaticDir, "index.html"), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.FileMode(0644)); err != nil {
log.Println("Unable to open index.html: ", err) log.Println("Unable to open index.html: ", err)
} else if indexTmpl, err := template.New("index").Parse(indextpl); err != nil { } else if indexTmpl, err := template.New("index").Parse(indextpl); err != nil {
log.Println("Cannot create template: ", err) log.Println("Cannot create template: ", err)
} else if err := indexTmpl.Execute(file, map[string]string{"urlbase": path.Clean(path.Join(baseURL + "/", "nuke"))[:len(path.Clean(path.Join(baseURL + "/", "nuke"))) - 4]}); err != nil { } else if err := indexTmpl.Execute(file, map[string]string{"urlbase": path.Clean(path.Join(*baseURL + "/", "nuke"))[:len(path.Clean(path.Join(*baseURL + "/", "nuke"))) - 4]}); err != nil {
log.Println("An error occurs during template execution: ", err) log.Println("An error occurs during template execution: ", err)
} }

View File

@ -3,16 +3,42 @@ package main
import ( import (
"net/http" "net/http"
"path" "path"
"srs.epita.fr/fic-server/admin/api"
"github.com/julienschmidt/httprouter"
) )
type staticRouting struct { func init() {
StaticDir string api.Router().GET("/", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
} http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
})
api.Router().GET("/exercices/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
})
api.Router().GET("/events/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
})
api.Router().GET("/teams/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
})
api.Router().GET("/themes/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, "index.html"))
})
func StaticHandler(staticDir string) http.Handler { api.Router().GET("/css/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
return staticRouting{staticDir} http.ServeFile(w, r, path.Join(StaticDir, r.URL.Path))
} })
api.Router().GET("/fonts/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
func (a staticRouting) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.ServeFile(w, r, path.Join(StaticDir, r.URL.Path))
http.ServeFile(w, r, path.Join(a.StaticDir, "index.html")) })
api.Router().GET("/img/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, r.URL.Path))
})
api.Router().GET("/js/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, r.URL.Path))
})
api.Router().GET("/views/*_", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
http.ServeFile(w, r, path.Join(StaticDir, r.URL.Path))
})
} }

View File

@ -37,7 +37,7 @@ angular.module("FICApp")
}) })
.factory("Team", function($resource) { .factory("Team", function($resource) {
return $resource("/api/teams/:teamId", { teamId: '@id' }, { return $resource("/api/teams/:teamId", { teamId: '@id' }, {
'save': {method: 'PATCH'}, 'update': {method: 'PUT'},
}) })
}) })
.factory("TeamMember", function($resource) { .factory("TeamMember", function($resource) {
@ -47,7 +47,7 @@ angular.module("FICApp")
return $resource("/api/teams/:teamId/my.json", { teamId: '@id' }) return $resource("/api/teams/:teamId/my.json", { teamId: '@id' })
}) })
.factory("Teams", function($resource) { .factory("Teams", function($resource) {
return $resource("/api/teams/teams.json") return $resource("/api/teams.json")
}) })
.factory("TeamStats", function($resource) { .factory("TeamStats", function($resource) {
return $resource("/api/teams/:teamId/stats.json", { teamId: '@id' }) return $resource("/api/teams/:teamId/stats.json", { teamId: '@id' })
@ -56,17 +56,19 @@ angular.module("FICApp")
return $resource("/api/teams/:teamId/tries", { teamId: '@id' }) return $resource("/api/teams/:teamId/tries", { teamId: '@id' })
}) })
.factory("Theme", function($resource) { .factory("Theme", function($resource) {
return $resource("/api/themes/:themeId", null, { return $resource("/api/themes/:themeId", { themeId: '@id' }, {
'save': {method: 'PATCH'}, update: {method: 'PUT'}
}) });
}) })
.factory("Themes", function($resource) { .factory("Themes", function($resource) {
return $resource("/api/themes/themes.json", null, { return $resource("/api/themes.json", null, {
'get': {method: 'GET'}, 'get': {method: 'GET'},
}) })
}) })
.factory("Exercice", function($resource) { .factory("Exercice", function($resource) {
return $resource("/api/exercices/:exerciceId") return $resource("/api/exercices/:exerciceId", { exerciceId: '@id' }, {
update: {method: 'PUT'}
})
}); });
String.prototype.capitalize = function() { String.prototype.capitalize = function() {