server/admin/api/handlers.go

353 lines
11 KiB
Go

package api
import (
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"strconv"
"strings"
"time"
"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())
// Read the body
if r.ContentLength < 0 || r.ContentLength > 6553600 {
http.Error(w, fmt.Sprintf("{errmsg:\"Request too large or request size unknown\"}"), 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
}
}
}
var ret interface{}
var err error = nil
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
}
w.Header().Set("X-FIC-Time", fmt.Sprintf("%f", float64(time.Now().UnixNano()/1000)/1000000))
if str, found := ret.(string); found {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(resStatus)
io.WriteString(w, str)
} else if bts, found := ret.([]byte); found {
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", "attachment")
w.Header().Set("Content-Transfer-Encoding", "binary")
w.WriteHeader(resStatus)
w.Write(bts)
} else if j, err := json.Marshal(ret); err != nil {
w.Header().Set("Content-Type", "application/json")
http.Error(w, fmt.Sprintf("{\"errmsg\":%q}", err), http.StatusInternalServerError)
} else {
w.Header().Set("Content-Type", "application/json")
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.ParseInt(string(ps.ByName("tid")), 10, 64); err != nil {
return nil, err
} 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.ParseInt(string(ps.ByName("tid")), 10, 64); err != nil {
return nil, err
} else if team, err := fic.GetTeam(tid); err != nil {
return nil, err
} else {
return f(team, body)
}
}
}
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) {
var team fic.Team
teamHandler(func(tm fic.Team, _ []byte) (interface{}, error) {
team = tm
return nil, nil
})(ps, body)
return f(team, string(ps.ByName("assoc")), 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.ParseInt(string(ps.ByName("thid")), 10, 64); 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.ParseInt(string(ps.ByName("eid")), 10, 64); err != nil {
return nil, err
} else if exercice, err := fic.GetExercice(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.ParseInt(string(ps.ByName("hid")), 10, 64); err != nil {
return nil, err
} else if hint, err := fic.GetHint(hid); err != nil {
return nil, err
} else {
return f(hint, body)
}
}
}
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) {
var exercice fic.Exercice
exerciceHandler(func(ex fic.Exercice, _ []byte) (interface{}, error) {
exercice = ex
return nil, nil
})(ps, body)
if kid, err := strconv.ParseInt(string(ps.ByName("kid")), 10, 64); err != nil {
return nil, err
} else if flags, err := exercice.GetFlagKeys(); err != nil {
return nil, err
} else {
for _, flag := range flags {
if flag.Id == int(kid) {
return f(flag, exercice, body)
}
}
return nil, errors.New("Unable to find the requested key")
}
}
}
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) {
var exercice fic.Exercice
var flag fic.FlagKey
flagKeyHandler(func(fl fic.FlagKey, ex fic.Exercice, _ []byte) (interface{}, error) {
exercice = ex
flag = fl
return nil, nil
})(ps, body)
if cid, err := strconv.ParseInt(string(ps.ByName("cid")), 10, 32); err != nil {
return nil, err
} else if choice, err := flag.GetChoice(int(cid)); err != nil {
return nil, err
} else {
return f(choice, exercice, body)
}
}
}
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.ParseInt(string(ps.ByName("qid")), 10, 64); err != nil {
return nil, err
} else if mcqs, err := exercice.GetMCQ(); err != nil {
return nil, err
} else {
for _, mcq := range mcqs {
if mcq.Id == int(qid) {
return f(mcq, exercice, body)
}
}
return nil, errors.New("Unable to find the requested key")
}
}
}
func exerciceFileHandler(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.ParseInt(string(ps.ByName("fid")), 10, 64); err != nil {
return nil, err
} else if files, err := exercice.GetFiles(); err != nil {
return nil, err
} else {
for _, file := range files {
if file.Id == 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.ParseInt(string(ps.ByName("evid")), 10, 64); err != nil {
return nil, err
} else if event, err := fic.GetEvent(evid); err != nil {
return nil, err
} else {
return f(event, body)
}
}
}
func claimHandler(f func(fic.Claim, []byte) (interface{}, error)) func(httprouter.Params, []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 {
return nil, err
} else if claim, err := fic.GetClaim(cid); err != nil {
return nil, err
} else {
return f(claim, body)
}
}
}
func claimAssigneeHandler(f func(fic.ClaimAssignee, []byte) (interface{}, error)) func(httprouter.Params, []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 {
return nil, err
} else if assignee, err := fic.GetAssignee(aid); err != nil {
return nil, err
} else {
return f(assignee, body)
}
}
}
func fileHandler(f func(fic.EFile, []byte) (interface{}, error)) func(httprouter.Params, []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 {
return nil, err
} else if file, err := fic.GetFile(fileid); err != nil {
return nil, err
} else {
return f(file, body)
}
}
}
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) {
if depid, err := strconv.ParseInt(string(ps.ByName("depid")), 10, 64); err != nil {
return nil, err
} else {
return fileHandler(func(file fic.EFile, b []byte) (interface{}, error) {
return f(file, int(depid), b)
})(ps, body)
}
}
}
func certificateHandler(f func(fic.Certificate, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
return func(ps httprouter.Params, body []byte) (interface{}, error) {
var cid uint64
var err error
certid := strings.TrimSuffix(ps.ByName("certid"), ".p12")
if cid, err = strconv.ParseUint(certid, 10, 64); err != nil {
if cid, err = strconv.ParseUint(certid, 16, 64); err != nil {
return nil, err
}
}
if cert, err := fic.GetCertificate(cid); err != nil {
return nil, err
} else {
return f(cert, body)
}
}
}
func notFound(ps httprouter.Params, _ []byte) (interface{}, error) {
return nil, nil
}