package api import ( "encoding/json" "errors" "fmt" "io" "log" "net/http" "strconv" "srs.epita.fr/fic-server/libfic" "github.com/julienschmidt/httprouter" ) type DispatchFunction func(httprouter.Params, []byte) (interface{}, error) func apiHandler(f DispatchFunction) func(http.ResponseWriter, *http.Request, httprouter.Params) { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { if addr := r.Header.Get("X-Forwarded-For"); addr != "" { r.RemoteAddr = addr } log.Printf("%s \"%s %s\" [%s]\n", r.RemoteAddr, r.Method, r.URL.Path, r.UserAgent()) w.Header().Set("Content-Type", "application/json") var ret interface{} var err error = nil // Read the body if r.ContentLength < 0 || r.ContentLength > 6553600 { http.Error(w, fmt.Sprintf("{errmsg:\"Request too large or request size unknown\"}", err), http.StatusRequestEntityTooLarge) return } var body []byte if r.ContentLength > 0 { tmp := make([]byte, 1024) for { n, err := r.Body.Read(tmp) for j := 0; j < n; j++ { body = append(body, tmp[j]) } if err != nil || n <= 0 { break } } } ret, err = f(ps, body) // Format response resStatus := http.StatusOK if err != nil { ret = map[string]string{"errmsg": err.Error()} resStatus = http.StatusBadRequest log.Println(r.RemoteAddr, resStatus, err.Error()) } if ret == nil { ret = map[string]string{"errmsg": "Page not found"} resStatus = http.StatusNotFound } if str, found := ret.(string); found { w.WriteHeader(resStatus) io.WriteString(w, str) } else if bts, found := ret.([]byte); found { w.WriteHeader(resStatus) w.Write(bts) } else if j, err := json.Marshal(ret); err != nil { http.Error(w, fmt.Sprintf("{\"errmsg\":%q}", err), http.StatusInternalServerError) } else { w.WriteHeader(resStatus) w.Write(j) } } } func teamPublicHandler(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 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 { return nil, err } else { return f(team, body) } } } func themeHandler(f func(fic.Theme,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) { return func (ps httprouter.Params, body []byte) (interface{}, error) { if thid, err := strconv.Atoi(string(ps.ByName("thid"))); err != nil { return nil, err } else if theme, err := fic.GetTheme(thid); err != nil { return nil, err } else { return f(theme, body) } } } func exerciceHandler(f func(fic.Exercice,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) { return func (ps httprouter.Params, body []byte) (interface{}, error) { if eid, err := strconv.Atoi(string(ps.ByName("eid"))); err != nil { return nil, err } else if exercice, err := fic.GetExercice(int64(eid)); err != nil { return nil, err } else { return f(exercice, body) } } } 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) { var theme fic.Theme var exercice fic.Exercice themeHandler(func (th fic.Theme, _[]byte) (interface{}, error) { theme = th 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 hintHandler(f func(fic.EHint,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) { return func (ps httprouter.Params, body []byte) (interface{}, error) { if hid, err := strconv.Atoi(string(ps.ByName("hid"))); err != nil { return nil, err } else if hint, err := fic.GetHint(int64(hid)); err != nil { return nil, err } else { return f(hint, body) } } } func keyHandler(f func(fic.Key,fic.Exercice,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) { return func (ps httprouter.Params, body []byte) (interface{}, error) { var exercice fic.Exercice exerciceHandler(func (ex fic.Exercice, _[]byte) (interface{}, error) { exercice = ex return nil,nil })(ps, body) if kid, err := strconv.Atoi(string(ps.ByName("kid"))); err != nil { return nil, err } else if keys, err := exercice.GetKeys(); err != nil { return nil, err } else { for _, key := range keys { if (key.Id == int64(kid)) { return f(key, exercice, body) } } return nil, errors.New("Unable to find the requested key") } } } 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) { var exercice fic.Exercice exerciceHandler(func (ex fic.Exercice, _[]byte) (interface{}, error) { exercice = ex return nil,nil })(ps, body) if qid, err := strconv.Atoi(string(ps.ByName("qid"))); err != nil { return nil, err } else if mcqs, err := exercice.GetMCQ(); err != nil { return nil, err } else { for _, mcq := range mcqs { if (mcq.Id == int64(qid)) { return f(mcq, exercice, body) } } return nil, errors.New("Unable to find the requested key") } } } func fileHandler(f func(fic.EFile,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) { return func (ps httprouter.Params, body []byte) (interface{}, error) { var exercice fic.Exercice exerciceHandler(func (ex fic.Exercice, _[]byte) (interface{}, error) { exercice = ex return nil,nil })(ps, body) if fid, err := strconv.Atoi(string(ps.ByName("fid"))); err != nil { return nil, err } else if files, err := exercice.GetFiles(); err != nil { return nil, err } else { for _, file := range files { if (file.Id == int64(fid)) { return f(file, body) } } return nil, errors.New("Unable to find the requested file") } } } func eventHandler(f func(fic.Event,[]byte) (interface{}, error)) func (httprouter.Params,[]byte) (interface{}, error) { return func (ps httprouter.Params, body []byte) (interface{}, error) { if evid, err := strconv.Atoi(string(ps.ByName("evid"))); err != nil { return nil, err } else if event, err := fic.GetEvent(evid); err != nil { return nil, err } else { return f(event, body) } } } func notFound(ps httprouter.Params, _ []byte) (interface{}, error) { return nil, nil }