2016-12-08 08:12:18 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
2016-12-27 20:08:36 +00:00
|
|
|
"errors"
|
2016-12-08 08:12:18 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"srs.epita.fr/fic-server/libfic"
|
|
|
|
|
2016-12-15 23:51:56 +00:00
|
|
|
"github.com/julienschmidt/httprouter"
|
2016-12-08 08:12:18 +00:00
|
|
|
)
|
|
|
|
|
2016-12-15 23:51:56 +00:00
|
|
|
type DispatchFunction func(httprouter.Params, []byte) (interface{}, error)
|
2016-12-08 08:12:18 +00:00
|
|
|
|
2016-12-15 23:51:56 +00:00
|
|
|
func apiHandler(f DispatchFunction) func(http.ResponseWriter, *http.Request, httprouter.Params) {
|
|
|
|
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
2017-12-17 14:42:33 +00:00
|
|
|
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())
|
2016-12-08 08:12:18 +00:00
|
|
|
|
|
|
|
// Read the body
|
|
|
|
if r.ContentLength < 0 || r.ContentLength > 6553600 {
|
2018-02-16 09:50:44 +00:00
|
|
|
http.Error(w, fmt.Sprintf("{errmsg:\"Request too large or request size unknown\"}"), http.StatusRequestEntityTooLarge)
|
2016-12-08 08:12:18 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-16 09:50:44 +00:00
|
|
|
var ret interface{}
|
|
|
|
var err error = nil
|
|
|
|
|
2016-12-15 23:51:56 +00:00
|
|
|
ret, err = f(ps, body)
|
2016-12-08 08:12:18 +00:00
|
|
|
|
|
|
|
// 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 {
|
2018-01-21 13:16:31 +00:00
|
|
|
w.Header().Set("Content-Type", "application/json")
|
2016-12-08 08:12:18 +00:00
|
|
|
w.WriteHeader(resStatus)
|
|
|
|
io.WriteString(w, str)
|
|
|
|
} else if bts, found := ret.([]byte); found {
|
2018-01-21 13:16:31 +00:00
|
|
|
w.Header().Set("Content-Type", "application/octet-stream")
|
|
|
|
w.Header().Set("Content-Disposition", "attachment")
|
|
|
|
w.Header().Set("Content-Transfer-Encoding", "binary")
|
2016-12-08 08:12:18 +00:00
|
|
|
w.WriteHeader(resStatus)
|
|
|
|
w.Write(bts)
|
|
|
|
} else if j, err := json.Marshal(ret); err != nil {
|
2018-01-21 13:16:31 +00:00
|
|
|
w.Header().Set("Content-Type", "application/json")
|
2017-10-26 12:14:54 +00:00
|
|
|
http.Error(w, fmt.Sprintf("{\"errmsg\":%q}", err), http.StatusInternalServerError)
|
2016-12-08 08:12:18 +00:00
|
|
|
} else {
|
2018-01-21 13:16:31 +00:00
|
|
|
w.Header().Set("Content-Type", "application/json")
|
2016-12-08 08:12:18 +00:00
|
|
|
w.WriteHeader(resStatus)
|
|
|
|
w.Write(j)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
func teamPublicHandler(f func(*fic.Team, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
2018-01-21 13:18:26 +00:00
|
|
|
if tid, err := strconv.ParseInt(string(ps.ByName("tid")), 10, 64); err != nil {
|
2018-01-21 13:07:44 +00:00
|
|
|
return nil, err
|
2016-12-15 23:51:56 +00:00
|
|
|
} else if tid == 0 {
|
|
|
|
return f(nil, body)
|
2016-12-08 08:12:18 +00:00
|
|
|
} else if team, err := fic.GetTeam(tid); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
2016-12-15 23:51:56 +00:00
|
|
|
return f(&team, body)
|
2016-12-08 08:12:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
func teamHandler(f func(fic.Team, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
2018-01-21 13:18:26 +00:00
|
|
|
if tid, err := strconv.ParseInt(string(ps.ByName("tid")), 10, 64); err != nil {
|
2018-01-21 13:07:44 +00:00
|
|
|
return nil, err
|
2016-12-15 23:51:56 +00:00
|
|
|
} else if team, err := fic.GetTeam(tid); err != nil {
|
2016-12-08 08:12:18 +00:00
|
|
|
return nil, err
|
|
|
|
} else {
|
2016-12-15 23:51:56 +00:00
|
|
|
return f(team, body)
|
2016-12-08 08:12:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
func themeHandler(f func(fic.Theme, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
2016-12-15 23:51:56 +00:00
|
|
|
if thid, err := strconv.Atoi(string(ps.ByName("thid"))); err != nil {
|
2016-12-08 08:12:18 +00:00
|
|
|
return nil, err
|
2016-12-15 23:51:56 +00:00
|
|
|
} else if theme, err := fic.GetTheme(thid); err != nil {
|
2016-12-08 08:12:18 +00:00
|
|
|
return nil, err
|
|
|
|
} else {
|
2016-12-15 23:51:56 +00:00
|
|
|
return f(theme, body)
|
2016-12-08 08:12:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
func exerciceHandler(f func(fic.Exercice, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
2016-12-15 23:51:56 +00:00
|
|
|
if eid, err := strconv.Atoi(string(ps.ByName("eid"))); err != nil {
|
2016-12-08 08:12:18 +00:00
|
|
|
return nil, err
|
|
|
|
} else if exercice, err := fic.GetExercice(int64(eid)); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
2016-12-15 23:51:56 +00:00
|
|
|
return f(exercice, body)
|
2016-12-08 08:12:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
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) {
|
2016-12-15 23:51:56 +00:00
|
|
|
var theme fic.Theme
|
|
|
|
var exercice fic.Exercice
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
themeHandler(func(th fic.Theme, _ []byte) (interface{}, error) {
|
2016-12-15 23:51:56 +00:00
|
|
|
theme = th
|
2018-03-09 18:07:08 +00:00
|
|
|
return nil, nil
|
2016-12-15 23:51:56 +00:00
|
|
|
})(ps, body)
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
exerciceHandler(func(ex fic.Exercice, _ []byte) (interface{}, error) {
|
2016-12-15 23:51:56 +00:00
|
|
|
exercice = ex
|
2018-03-09 18:07:08 +00:00
|
|
|
return nil, nil
|
2016-12-15 23:51:56 +00:00
|
|
|
})(ps, body)
|
|
|
|
|
|
|
|
return f(theme, exercice, body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
func hintHandler(f func(fic.EHint, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
2016-12-27 20:08:36 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
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) {
|
2016-12-27 20:08:36 +00:00
|
|
|
var exercice fic.Exercice
|
2018-03-09 18:07:08 +00:00
|
|
|
exerciceHandler(func(ex fic.Exercice, _ []byte) (interface{}, error) {
|
2016-12-27 20:08:36 +00:00
|
|
|
exercice = ex
|
2018-03-09 18:07:08 +00:00
|
|
|
return nil, nil
|
2016-12-27 20:08:36 +00:00
|
|
|
})(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 {
|
2018-03-09 18:07:08 +00:00
|
|
|
if key.Id == int64(kid) {
|
2016-12-27 20:08:36 +00:00
|
|
|
return f(key, exercice, body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, errors.New("Unable to find the requested key")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
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) {
|
2017-12-17 01:50:01 +00:00
|
|
|
var exercice fic.Exercice
|
2018-03-09 18:07:08 +00:00
|
|
|
exerciceHandler(func(ex fic.Exercice, _ []byte) (interface{}, error) {
|
2017-12-17 01:50:01 +00:00
|
|
|
exercice = ex
|
2018-03-09 18:07:08 +00:00
|
|
|
return nil, nil
|
2017-12-17 01:50:01 +00:00
|
|
|
})(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 {
|
2018-03-09 18:07:08 +00:00
|
|
|
if mcq.Id == int64(qid) {
|
2017-12-17 01:50:01 +00:00
|
|
|
return f(mcq, exercice, body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, errors.New("Unable to find the requested key")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
func exerciceFileHandler(f func(fic.EFile, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
2016-12-27 20:08:36 +00:00
|
|
|
var exercice fic.Exercice
|
2018-03-09 18:07:08 +00:00
|
|
|
exerciceHandler(func(ex fic.Exercice, _ []byte) (interface{}, error) {
|
2016-12-27 20:08:36 +00:00
|
|
|
exercice = ex
|
2018-03-09 18:07:08 +00:00
|
|
|
return nil, nil
|
2016-12-27 20:08:36 +00:00
|
|
|
})(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 {
|
2018-03-09 18:07:08 +00:00
|
|
|
if file.Id == int64(fid) {
|
2016-12-27 20:08:36 +00:00
|
|
|
return f(file, body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, errors.New("Unable to find the requested file")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
func eventHandler(f func(fic.Event, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
2016-12-27 20:08:36 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
func claimHandler(f func(fic.Claim, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
2018-01-17 00:21:32 +00:00
|
|
|
if cid, err := strconv.Atoi(string(ps.ByName("cid"))); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if claim, err := fic.GetClaim(cid); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
return f(claim, body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
func claimAssigneeHandler(f func(fic.ClaimAssignee, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
2018-01-17 00:21:32 +00:00
|
|
|
if aid, err := strconv.Atoi(string(ps.ByName("aid"))); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if assignee, err := fic.GetAssignee(int64(aid)); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
return f(assignee, body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
func fileHandler(f func(fic.EFile, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
2017-12-27 00:53:01 +00:00
|
|
|
if fileid, err := strconv.Atoi(string(ps.ByName("fileid"))); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else if file, err := fic.GetFile(fileid); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
return f(file, body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 18:07:08 +00:00
|
|
|
func certificateHandler(f func(fic.Certificate, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) {
|
|
|
|
return func(ps httprouter.Params, body []byte) (interface{}, error) {
|
2018-02-02 19:29:16 +00:00
|
|
|
if certid, err := strconv.ParseUint(string(ps.ByName("certid")), 10, 64); err != nil {
|
2018-01-21 13:18:26 +00:00
|
|
|
return nil, err
|
|
|
|
} else if cert, err := fic.GetCertificate(certid); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
|
|
|
return f(cert, body)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-15 23:51:56 +00:00
|
|
|
func notFound(ps httprouter.Params, _ []byte) (interface{}, error) {
|
2016-12-08 08:12:18 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|