admin/api: use gorilla/mux instead of Go router
This commit is contained in:
parent
0e30259b7e
commit
307c253d7a
18 changed files with 643 additions and 720 deletions
102
admin/api.go
102
admin/api.go
|
@ -1,102 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DispatchFunction func([]string, []byte) (interface{}, error)
|
|
||||||
|
|
||||||
var apiRoutes = map[string]*(map[string]DispatchFunction){
|
|
||||||
"version": &ApiVersionRouting,
|
|
||||||
"ca": &ApiCARouting,
|
|
||||||
"events": &ApiEventsRouting,
|
|
||||||
"exercices": &ApiExercicesRouting,
|
|
||||||
"themes": &ApiThemesRouting,
|
|
||||||
"teams": &ApiTeamsRouting,
|
|
||||||
}
|
|
||||||
|
|
||||||
type apiRouting struct{}
|
|
||||||
|
|
||||||
func ApiHandler() http.Handler {
|
|
||||||
return apiRouting{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a apiRouting) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
log.Printf("Handling %s request from %s: %s [%s]\n", r.Method, r.RemoteAddr, r.URL.Path, r.UserAgent())
|
|
||||||
|
|
||||||
// Extract URL arguments
|
|
||||||
var sURL = strings.Split(r.URL.Path, "/")[1:]
|
|
||||||
if len(sURL) > 1 && sURL[len(sURL)-1] == "" {
|
|
||||||
// Remove trailing /
|
|
||||||
sURL = sURL[:len(sURL)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Route request
|
|
||||||
if len(sURL) > 0 {
|
|
||||||
if h, ok := apiRoutes[sURL[0]]; ok {
|
|
||||||
if f, ok := (*h)[r.Method]; ok {
|
|
||||||
ret, err = f(sURL[1:], body)
|
|
||||||
} else {
|
|
||||||
err = errors.New(fmt.Sprintf("Invalid action (%s) provided for %s.", r.Method, sURL[0]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = errors.New("No action provided.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
}
|
|
31
admin/api/certificate.go
Normal file
31
admin/api/certificate.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"srs.epita.fr/fic-server/libfic"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
router.Path("/ca").Methods("GET").HandlerFunc(apiHandler(genCA))
|
||||||
|
|
||||||
|
rt := router.PathPrefix("/teams/{tid}/certificate").Subrouter()
|
||||||
|
rt.Path("/").Methods("GET").HandlerFunc(apiHandler(teamHandler(GetTeamCertificate)))
|
||||||
|
rt.Path("/generate").Methods("GET").HandlerFunc(apiHandler(teamHandler(
|
||||||
|
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) { return team.GenerateCert(), nil })))
|
||||||
|
rt.Path("/revoke").Methods("GET").HandlerFunc(apiHandler(teamHandler(
|
||||||
|
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) {
|
||||||
|
return fic.GenerateCA(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTeamCertificate(team fic.Team, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
if fd, err := os.Open("../PKI/pkcs/" + team.Name + ".p12"); err == nil {
|
||||||
|
return ioutil.ReadAll(fd)
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
17
admin/api/events.go
Normal file
17
admin/api/events.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"srs.epita.fr/fic-server/libfic"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
router.Path("/events/").Methods("GET").HandlerFunc(apiHandler(getEvents))
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEvents(args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
if evts, err := fic.GetEvents(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return evts, nil
|
||||||
|
}
|
||||||
|
}
|
117
admin/api/exercice.go
Normal file
117
admin/api/exercice.go
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"srs.epita.fr/fic-server/libfic"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
router.Path("/exercices/").Methods("GET").HandlerFunc(apiHandler(listExercices))
|
||||||
|
re := router.Path("/exercices/{eid:[0-9]+}").Subrouter()
|
||||||
|
re.Methods("GET").HandlerFunc(apiHandler(exerciceHandler(showExercice)))
|
||||||
|
re.Methods("PUT").HandlerFunc(apiHandler(updateExercice))
|
||||||
|
re.Methods("DELETE").HandlerFunc(apiHandler(deleteExercice))
|
||||||
|
}
|
||||||
|
|
||||||
|
func listExercices(args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
// List all exercices
|
||||||
|
return fic.GetExercices()
|
||||||
|
}
|
||||||
|
|
||||||
|
func showExercice(exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return exercice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteExercice(args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
if eid, err := strconv.Atoi(args["eid"]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if exercice, err := fic.GetExercice(int64(eid)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return exercice.Delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type uploadedExercice struct {
|
||||||
|
Title string
|
||||||
|
Statement string
|
||||||
|
Depend *int64
|
||||||
|
Gain int
|
||||||
|
VideoURI string
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateExercice(args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
if eid, err := strconv.Atoi(args["eid"]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if exercice, err := fic.GetExercice(int64(eid)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
// Update an exercice
|
||||||
|
var ue uploadedExercice
|
||||||
|
if err := json.Unmarshal(body, &ue); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ue.Title) == 0 {
|
||||||
|
return nil, errors.New("Exercice's title not filled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ue.Depend != nil {
|
||||||
|
if _, err := fic.GetExercice(*ue.Depend); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exercice.Title = ue.Title
|
||||||
|
exercice.Statement = ue.Statement
|
||||||
|
exercice.Depend = ue.Depend
|
||||||
|
exercice.Gain = int64(ue.Gain)
|
||||||
|
exercice.VideoURI = ue.VideoURI
|
||||||
|
|
||||||
|
return exercice.Update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createExercice(theme fic.Theme, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
// Create a new exercice
|
||||||
|
var ue uploadedExercice
|
||||||
|
if err := json.Unmarshal(body, &ue); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ue.Title) == 0 {
|
||||||
|
return nil, errors.New("Title not filled")
|
||||||
|
}
|
||||||
|
|
||||||
|
var depend *fic.Exercice = nil
|
||||||
|
if ue.Depend != nil {
|
||||||
|
if d, err := fic.GetExercice(*ue.Depend); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
depend = &d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return theme.AddExercice(ue.Title, ue.Statement, depend, ue.Gain, ue.VideoURI)
|
||||||
|
}
|
||||||
|
|
||||||
|
type uploadedKey struct {
|
||||||
|
Name string
|
||||||
|
Key string
|
||||||
|
}
|
||||||
|
|
||||||
|
func createExerciceKey(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
var uk uploadedKey
|
||||||
|
if err := json.Unmarshal(body, &uk); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(uk.Key) == 0 {
|
||||||
|
return nil, errors.New("Key not filled")
|
||||||
|
}
|
||||||
|
|
||||||
|
return exercice.AddRawKey(uk.Name, uk.Key)
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
@ -15,7 +15,11 @@ import (
|
||||||
"srs.epita.fr/fic-server/libfic"
|
"srs.epita.fr/fic-server/libfic"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createExerciceFile(theme fic.Theme, exercice fic.Exercice, args []string, body []byte) (interface{}, error) {
|
var CloudDAVBase string
|
||||||
|
var CloudUsername string
|
||||||
|
var CloudPassword string
|
||||||
|
|
||||||
|
func createExerciceFile(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) {
|
||||||
var uf map[string]string
|
var uf map[string]string
|
||||||
if err := json.Unmarshal(body, &uf); err != nil {
|
if err := json.Unmarshal(body, &uf); err != nil {
|
||||||
return nil, err
|
return nil, err
|
131
admin/api/handlers.go
Normal file
131
admin/api/handlers.go
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"srs.epita.fr/fic-server/libfic"
|
||||||
|
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
type DispatchFunction func([]string, []byte) (interface{}, error)
|
||||||
|
|
||||||
|
func apiHandler(f func (map[string]string,[]byte) (interface{}, error)) func(http.ResponseWriter, *http.Request) {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
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")
|
||||||
|
|
||||||
|
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(mux.Vars(r), 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 teamHandler(f func(fic.Team,map[string]string,[]byte) (interface{}, error)) func (map[string]string,[]byte) (interface{}, error) {
|
||||||
|
return func (args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
if tid, err := strconv.Atoi(string(args["tid"])); err != nil {
|
||||||
|
if team, err := fic.GetTeamByInitialName(args["tid"]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return f(team, args, body)
|
||||||
|
}
|
||||||
|
} else if team, err := fic.GetTeam(tid); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return f(team, args, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func themeHandler(f func(fic.Theme,map[string]string,[]byte) (interface{}, error)) func (map[string]string,[]byte) (interface{}, error) {
|
||||||
|
return func (args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
if tid, err := strconv.Atoi(string(args["tid"])); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if theme, err := fic.GetTheme(tid); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return f(theme, args, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func exerciceHandler(f func(fic.Exercice,map[string]string,[]byte) (interface{}, error)) func (map[string]string,[]byte) (interface{}, error) {
|
||||||
|
return func (args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
if eid, err := strconv.Atoi(string(args["eid"])); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if exercice, err := fic.GetExercice(int64(eid)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return f(exercice, args, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func themedExerciceHandler(f func(fic.Theme,fic.Exercice,map[string]string,[]byte) (interface{}, error)) func (fic.Theme,map[string]string,[]byte) (interface{}, error) {
|
||||||
|
return func (theme fic.Theme, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
if eid, err := strconv.Atoi(string(args["eid"])); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if exercice, err := fic.GetExercice(int64(eid)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return f(theme, exercice, args, body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func notFound(args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
14
admin/api/router.go
Normal file
14
admin/api/router.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
|
var api_router = mux.NewRouter().StrictSlash(true)
|
||||||
|
|
||||||
|
var router = api_router.PathPrefix("/api/").Subrouter()
|
||||||
|
|
||||||
|
|
||||||
|
func Router() *mux.Router {
|
||||||
|
return api_router
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
156
admin/api/team.go
Normal file
156
admin/api/team.go
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"srs.epita.fr/fic-server/libfic"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rts := router.PathPrefix("/teams").Subrouter()
|
||||||
|
router.Path("/teams.json").Methods("GET").HandlerFunc(apiHandler(
|
||||||
|
func(map[string]string,[]byte) (interface{}, error) {
|
||||||
|
return fic.ExportTeams() }))
|
||||||
|
rts.Path("/").Methods("GET").HandlerFunc(apiHandler(
|
||||||
|
func(map[string]string,[]byte) (interface{}, error) {
|
||||||
|
return fic.GetTeams() }))
|
||||||
|
rts.Path("/binding").Methods("GET").HandlerFunc(apiHandler(
|
||||||
|
func(map[string]string,[]byte) (interface{}, error) {
|
||||||
|
return bindingTeams() }))
|
||||||
|
rts.Path("/nginx").Methods("GET").HandlerFunc(apiHandler(
|
||||||
|
func(map[string]string,[]byte) (interface{}, error) {
|
||||||
|
return nginxGenTeam() }))
|
||||||
|
rts.Path("/nginx-members").Methods("GET").HandlerFunc(apiHandler(
|
||||||
|
func(map[string]string,[]byte) (interface{}, error) {
|
||||||
|
return nginxGenMember() }))
|
||||||
|
rts.Path("/binding").Methods("GET").HandlerFunc(apiHandler(
|
||||||
|
func(map[string]string,[]byte) (interface{}, error) {
|
||||||
|
return fic.GetTries(nil, nil) }))
|
||||||
|
|
||||||
|
rts.Path("/0/my.json").Methods("GET").HandlerFunc(apiHandler(
|
||||||
|
func(map[string]string,[]byte) (interface{}, error) {
|
||||||
|
return fic.MyJSONTeam(nil, true) }))
|
||||||
|
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()
|
||||||
|
rt.Path("/").Methods("GET").HandlerFunc(apiHandler(teamHandler(
|
||||||
|
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return team, nil })))
|
||||||
|
rt.Path("/").Methods("DELETE").HandlerFunc(apiHandler(teamHandler(
|
||||||
|
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return team.Delete() })))
|
||||||
|
rt.Path("/my.json").Methods("GET").HandlerFunc(apiHandler(teamHandler(
|
||||||
|
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return fic.MyJSONTeam(&team, true) })))
|
||||||
|
rt.Path("/wait.json").Methods("GET").HandlerFunc(apiHandler(teamHandler(
|
||||||
|
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return fic.MyJSONTeam(&team, false) })))
|
||||||
|
rt.Path("/stats.json").Methods("GET").HandlerFunc(apiHandler(teamHandler(
|
||||||
|
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return team.GetStats() })))
|
||||||
|
rt.Path("/tries").Methods("GET").HandlerFunc(apiHandler(teamHandler(
|
||||||
|
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return fic.GetTries(&team, nil) })))
|
||||||
|
rt.Path("/members").Methods("GET").HandlerFunc(apiHandler(teamHandler(
|
||||||
|
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return team.GetMembers() })))
|
||||||
|
rt.Path("/name").Methods("GET").HandlerFunc(apiHandler(teamHandler(
|
||||||
|
func(team fic.Team, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return team.Name, nil })))
|
||||||
|
}
|
||||||
|
|
||||||
|
func nginxGenMember() (string, error) {
|
||||||
|
if teams, err := fic.GetTeams(); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
ret := ""
|
||||||
|
for _, team := range teams {
|
||||||
|
if members, err := team.GetMembers(); err == nil {
|
||||||
|
for _, member := range members {
|
||||||
|
ret += fmt.Sprintf(" if ($remote_user = \"%s\") { set $team \"%s\"; }\n", member.Nickname, team.InitialName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func nginxGenTeam() (string, error) {
|
||||||
|
if teams, err := fic.GetTeams(); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
ret := ""
|
||||||
|
for _, team := range teams {
|
||||||
|
ret += fmt.Sprintf(" if ($ssl_client_s_dn ~ \"/C=FR/ST=France/O=Epita/OU=SRS/CN=%s\") { set $team \"%s\"; }\n", team.InitialName, team.InitialName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func bindingTeams() (string, error) {
|
||||||
|
if teams, err := fic.GetTeams(); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
ret := ""
|
||||||
|
for _, team := range teams {
|
||||||
|
if members, err := team.GetMembers(); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else {
|
||||||
|
var mbs []string
|
||||||
|
for _, member := range members {
|
||||||
|
mbs = append(mbs, fmt.Sprintf("%s %s", member.Firstname, member.Lastname))
|
||||||
|
}
|
||||||
|
ret += fmt.Sprintf("%d;%s;%s\n", team.Id, team.Name, strings.Join(mbs, ";"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type uploadedTeam struct {
|
||||||
|
Name string
|
||||||
|
Color uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type uploadedMember struct {
|
||||||
|
Firstname string
|
||||||
|
Lastname string
|
||||||
|
Nickname string
|
||||||
|
Company string
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTeam(args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
var ut uploadedTeam
|
||||||
|
if err := json.Unmarshal(body, &ut); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fic.CreateTeam(ut.Name, ut.Color)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addTeamMember(team fic.Team, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
var members []uploadedMember
|
||||||
|
if err := json.Unmarshal(body, &members); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, member := range members {
|
||||||
|
team.AddMember(member.Firstname, member.Lastname, member.Nickname, member.Company)
|
||||||
|
}
|
||||||
|
|
||||||
|
return team.GetMembers()
|
||||||
|
}
|
153
admin/api/theme.go
Normal file
153
admin/api/theme.go
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"srs.epita.fr/fic-server/libfic"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
router.Path("/themes/").Methods("GET").HandlerFunc(apiHandler(listThemes))
|
||||||
|
router.Path("/themes/").Methods("POST").HandlerFunc(apiHandler(createTheme))
|
||||||
|
router.Path("/themes.json").Methods("GET").HandlerFunc(apiHandler(exportThemes))
|
||||||
|
router.Path("/themes/files-bindings").Methods("GET").HandlerFunc(apiHandler(bindingFiles))
|
||||||
|
|
||||||
|
rt := router.PathPrefix("/themes/{tid:[0-9]+}").Subrouter()
|
||||||
|
rt.Path("/").Methods("GET").HandlerFunc(apiHandler(themeHandler(showTheme)))
|
||||||
|
rt.Path("/").Methods("PUT").HandlerFunc(apiHandler(themeHandler(updateTheme)))
|
||||||
|
rt.Path("/").Methods("DELETE").HandlerFunc(apiHandler(themeHandler(deleteTheme)))
|
||||||
|
|
||||||
|
rtes := rt.PathPrefix("/exercices").Subrouter()
|
||||||
|
rtes.Path("/").Methods("GET").HandlerFunc(apiHandler(themeHandler(listThemedExercices)))
|
||||||
|
rtes.Path("/").Methods("POST").HandlerFunc(apiHandler(themeHandler(createExercice)))
|
||||||
|
|
||||||
|
rte := rtes.PathPrefix("/{eid:[0-9]+}").Subrouter()
|
||||||
|
rte.Path("/").Methods("GET").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(showThemedExercice))))
|
||||||
|
rte.Path("/").Methods("PUT").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(updateThemedExercice))))
|
||||||
|
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))))
|
||||||
|
|
||||||
|
rtek := rte.Path("/keys").Subrouter()
|
||||||
|
rtek.Methods("GET").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(listThemedExerciceKeys))))
|
||||||
|
rtek.Methods("POST").HandlerFunc(apiHandler(themeHandler(themedExerciceHandler(createExerciceKey))))
|
||||||
|
}
|
||||||
|
|
||||||
|
func bindingFiles(args map[string]string, 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.Atoi(string(args[0])); err != nil {
|
||||||
|
return fic.Exercice{}, err
|
||||||
|
} else if theme, err := fic.GetTheme(tid); err != nil {
|
||||||
|
return fic.Exercice{}, err
|
||||||
|
} else if eid, err := strconv.Atoi(string(args[1])); err != nil {
|
||||||
|
return fic.Exercice{}, err
|
||||||
|
} else {
|
||||||
|
return theme.GetExercice(eid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func listThemes(args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return fic.GetThemes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportThemes(args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return fic.ExportThemes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func showTheme(theme fic.Theme, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return theme, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listThemedExercices(theme fic.Theme, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return theme.GetExercices()
|
||||||
|
}
|
||||||
|
|
||||||
|
func showThemedExercice(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return exercice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listThemedExerciceFiles(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return exercice.GetFiles()
|
||||||
|
}
|
||||||
|
|
||||||
|
func listThemedExerciceKeys(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return exercice.GetKeys()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type uploadedTheme struct {
|
||||||
|
Name string
|
||||||
|
Authors string
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTheme(args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
var ut uploadedTheme
|
||||||
|
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.Name, ut.Authors)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateTheme(theme fic.Theme, args map[string]string, 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")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ut.Update()
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateThemedExercice(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
// Update an exercice
|
||||||
|
var ue fic.Exercice
|
||||||
|
if err := json.Unmarshal(body, &ue); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ue.Id = exercice.Id
|
||||||
|
|
||||||
|
if len(ue.Title) == 0 {
|
||||||
|
return nil, errors.New("Exercice's title not filled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := ue.Update(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteTheme(theme fic.Theme, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return theme.Delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteThemedExercice(theme fic.Theme, exercice fic.Exercice, args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return exercice.Delete()
|
||||||
|
}
|
11
admin/api/version.go
Normal file
11
admin/api/version.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import ()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
router.Path("/version").Methods("GET").HandlerFunc(apiHandler(showVersion))
|
||||||
|
}
|
||||||
|
|
||||||
|
func showVersion(args map[string]string, body []byte) (interface{}, error) {
|
||||||
|
return map[string]interface{}{"version": 0.1}, nil
|
||||||
|
}
|
|
@ -1,32 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"srs.epita.fr/fic-server/libfic"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CertificateAPI(team fic.Team, args []string) (interface{}, error) {
|
|
||||||
if len(args) == 1 {
|
|
||||||
if args[0] == "generate" {
|
|
||||||
return team.GenerateCert(), nil
|
|
||||||
} else if args[0] == "revoke" {
|
|
||||||
return team.RevokeCert(), nil
|
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
} else if fd, err := os.Open("../PKI/pkcs/" + team.Name + ".p12"); err == nil {
|
|
||||||
return ioutil.ReadAll(fd)
|
|
||||||
} else {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var ApiCARouting = map[string]DispatchFunction{
|
|
||||||
"GET": genCA,
|
|
||||||
}
|
|
||||||
|
|
||||||
func genCA(args []string, body []byte) (interface{}, error) {
|
|
||||||
return fic.GenerateCA(), nil
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"srs.epita.fr/fic-server/libfic"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ApiEventsRouting = map[string]DispatchFunction{
|
|
||||||
"GET": getEvents,
|
|
||||||
}
|
|
||||||
|
|
||||||
func getEvents(args []string, body []byte) (interface{}, error) {
|
|
||||||
if evts, err := fic.GetEvents(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return evts, nil
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,144 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"srs.epita.fr/fic-server/libfic"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ApiExercicesRouting = map[string]DispatchFunction{
|
|
||||||
"GET": listExercice,
|
|
||||||
"PATCH": updateExercice,
|
|
||||||
"DELETE": deletionExercice,
|
|
||||||
}
|
|
||||||
|
|
||||||
func listExercice(args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) == 1 {
|
|
||||||
if eid, err := strconv.Atoi(string(args[0])); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return fic.GetExercice(int64(eid))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// List all exercices
|
|
||||||
return fic.GetExercices()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func deletionExercice(args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) == 1 {
|
|
||||||
if eid, err := strconv.Atoi(string(args[0])); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if exercice, err := fic.GetExercice(int64(eid)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return exercice.Delete()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type uploadedExercice struct {
|
|
||||||
Title string
|
|
||||||
Statement string
|
|
||||||
Hint string
|
|
||||||
Depend *int64
|
|
||||||
Gain int
|
|
||||||
VideoURI string
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateExercice(args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) == 1 {
|
|
||||||
if eid, err := strconv.Atoi(string(args[0])); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if exercice, err := fic.GetExercice(int64(eid)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
// Update an exercice
|
|
||||||
var ue uploadedExercice
|
|
||||||
if err := json.Unmarshal(body, &ue); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ue.Title) == 0 {
|
|
||||||
return nil, errors.New("Exercice's title not filled")
|
|
||||||
}
|
|
||||||
|
|
||||||
if ue.Depend != nil {
|
|
||||||
if _, err := fic.GetExercice(*ue.Depend); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exercice.Title = ue.Title
|
|
||||||
exercice.Statement = ue.Statement
|
|
||||||
exercice.Hint = ue.Hint
|
|
||||||
exercice.Depend = ue.Depend
|
|
||||||
exercice.Gain = int64(ue.Gain)
|
|
||||||
exercice.VideoURI = ue.VideoURI
|
|
||||||
|
|
||||||
return exercice.Update()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createExercice(theme fic.Theme, args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) >= 1 {
|
|
||||||
if eid, err := strconv.Atoi(args[0]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if exercice, err := theme.GetExercice(eid); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
if args[1] == "files" {
|
|
||||||
return createExerciceFile(theme, exercice, args[2:], body)
|
|
||||||
} else if args[1] == "keys" {
|
|
||||||
return createExerciceKey(theme, exercice, args[2:], body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
} else {
|
|
||||||
// Create a new exercice
|
|
||||||
var ue uploadedExercice
|
|
||||||
if err := json.Unmarshal(body, &ue); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ue.Title) == 0 {
|
|
||||||
return nil, errors.New("Title not filled")
|
|
||||||
}
|
|
||||||
|
|
||||||
var depend *fic.Exercice = nil
|
|
||||||
if ue.Depend != nil {
|
|
||||||
if d, err := fic.GetExercice(*ue.Depend); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
depend = &d
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return theme.AddExercice(ue.Title, ue.Statement, ue.Hint, depend, ue.Gain, ue.VideoURI)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type uploadedKey struct {
|
|
||||||
Name string
|
|
||||||
Key string
|
|
||||||
}
|
|
||||||
|
|
||||||
func createExerciceKey(theme fic.Theme, exercice fic.Exercice, args []string, body []byte) (interface{}, error) {
|
|
||||||
var uk uploadedKey
|
|
||||||
if err := json.Unmarshal(body, &uk); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(uk.Key) == 0 {
|
|
||||||
return nil, errors.New("Key not filled")
|
|
||||||
}
|
|
||||||
|
|
||||||
return exercice.AddRawKey(uk.Name, uk.Key)
|
|
||||||
}
|
|
|
@ -1,231 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"srs.epita.fr/fic-server/libfic"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ApiTeamsRouting = map[string]DispatchFunction{
|
|
||||||
"GET": listTeam,
|
|
||||||
"PUT": creationTeamMembers,
|
|
||||||
"POST": creationTeam,
|
|
||||||
"DELETE": deletionTeam,
|
|
||||||
}
|
|
||||||
|
|
||||||
func nginxGenMember() (string, error) {
|
|
||||||
if teams, err := fic.GetTeams(); err != nil {
|
|
||||||
return "", err
|
|
||||||
} else {
|
|
||||||
ret := ""
|
|
||||||
for _, team := range teams {
|
|
||||||
if members, err := team.GetMembers(); err == nil {
|
|
||||||
for _, member := range members {
|
|
||||||
ret += fmt.Sprintf(" if ($remote_user = \"%s\") { set $team \"%s\"; }\n", member.Nickname, team.InitialName)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func nginxGenTeam() (string, error) {
|
|
||||||
if teams, err := fic.GetTeams(); err != nil {
|
|
||||||
return "", err
|
|
||||||
} else {
|
|
||||||
ret := ""
|
|
||||||
for _, team := range teams {
|
|
||||||
ret += fmt.Sprintf(" if ($ssl_client_s_dn ~ \"/C=FR/ST=France/O=Epita/OU=SRS/CN=%s\") { set $team \"%s\"; }\n", team.InitialName, team.InitialName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func bindingTeams() (string, error) {
|
|
||||||
if teams, err := fic.GetTeams(); err != nil {
|
|
||||||
return "", err
|
|
||||||
} else {
|
|
||||||
ret := ""
|
|
||||||
for _, team := range teams {
|
|
||||||
if members, err := team.GetMembers(); err != nil {
|
|
||||||
return "", err
|
|
||||||
} else {
|
|
||||||
var mbs []string
|
|
||||||
for _, member := range members {
|
|
||||||
mbs = append(mbs, fmt.Sprintf("%s %s", member.Firstname, member.Lastname))
|
|
||||||
}
|
|
||||||
ret += fmt.Sprintf("%d;%s;%s\n", team.Id, team.Name, strings.Join(mbs, ";"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type uploadedTeam struct {
|
|
||||||
Name string
|
|
||||||
Color uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
type uploadedMember struct {
|
|
||||||
Firstname string
|
|
||||||
Lastname string
|
|
||||||
Nickname string
|
|
||||||
Company string
|
|
||||||
}
|
|
||||||
|
|
||||||
func listTeam(args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) >= 2 {
|
|
||||||
var team *fic.Team
|
|
||||||
if tid, err := strconv.Atoi(args[0]); err != nil {
|
|
||||||
if t, err := fic.GetTeamByInitialName(args[0]); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
team = &t
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if tid == 0 {
|
|
||||||
team = nil
|
|
||||||
} else if t, err := fic.GetTeam(tid); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
team = &t
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if args[1] == "my.json" {
|
|
||||||
return fic.MyJSONTeam(team, true)
|
|
||||||
} else if args[1] == "wait.json" {
|
|
||||||
return fic.MyJSONTeam(team, false)
|
|
||||||
} else if args[1] == "stats.json" {
|
|
||||||
if team != nil {
|
|
||||||
return team.GetStats()
|
|
||||||
} else {
|
|
||||||
return fic.GetTeamsStats(nil)
|
|
||||||
}
|
|
||||||
} else if args[1] == "tries" {
|
|
||||||
return fic.GetTries(team, nil)
|
|
||||||
} else if team != nil && args[1] == "members" {
|
|
||||||
return team.GetMembers()
|
|
||||||
} else if args[1] == "certificate" && team != nil {
|
|
||||||
return CertificateAPI(*team, args[2:])
|
|
||||||
} else if team != nil && args[1] == "name" {
|
|
||||||
return team.Name, nil
|
|
||||||
}
|
|
||||||
} else if len(args) == 1 {
|
|
||||||
if args[0] == "teams.json" {
|
|
||||||
return fic.ExportTeams()
|
|
||||||
} else if args[0] == "tries" {
|
|
||||||
return fic.GetTries(nil, nil)
|
|
||||||
} else if args[0] == "nginx" {
|
|
||||||
return nginxGenTeam()
|
|
||||||
} else if args[0] == "nginx-members" {
|
|
||||||
return nginxGenMember()
|
|
||||||
} else if args[0] == "binding" {
|
|
||||||
return bindingTeams()
|
|
||||||
} else if tid, err := strconv.Atoi(string(args[0])); err != nil {
|
|
||||||
return fic.GetTeamByInitialName(args[0])
|
|
||||||
} else if team, err := fic.GetTeam(tid); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return team, nil
|
|
||||||
}
|
|
||||||
} else if len(args) == 0 {
|
|
||||||
// List all teams
|
|
||||||
return fic.GetTeams()
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func creationTeam(args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) == 1 {
|
|
||||||
// List given team
|
|
||||||
if tid, err := strconv.Atoi(string(args[0])); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if team, err := fic.GetTeam(tid); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
var members []uploadedMember
|
|
||||||
if err := json.Unmarshal(body, &members); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, member := range members {
|
|
||||||
team.AddMember(member.Firstname, member.Lastname, member.Nickname, member.Company)
|
|
||||||
}
|
|
||||||
|
|
||||||
return team.GetMembers()
|
|
||||||
}
|
|
||||||
} else if len(args) == 0 {
|
|
||||||
// Create a new team
|
|
||||||
var ut uploadedTeam
|
|
||||||
if err := json.Unmarshal(body, &ut); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return fic.CreateTeam(ut.Name, ut.Color)
|
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func creationTeamMembers(args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) == 1 {
|
|
||||||
// List given team
|
|
||||||
if tid, err := strconv.Atoi(string(args[0])); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if team, err := fic.GetTeam(tid); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
var member uploadedMember
|
|
||||||
if err := json.Unmarshal(body, &member); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
team.AddMember(member.Firstname, member.Lastname, member.Nickname, member.Company)
|
|
||||||
|
|
||||||
return team.GetMembers()
|
|
||||||
}
|
|
||||||
} else if len(args) == 0 {
|
|
||||||
// Create a new team
|
|
||||||
var members []uploadedMember
|
|
||||||
if err := json.Unmarshal(body, &members); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if team, err := fic.CreateTeam("", 0); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
for _, member := range members {
|
|
||||||
if _, err := team.AddMember(member.Firstname, member.Lastname, member.Nickname, member.Company); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return team, nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func deletionTeam(args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) == 1 {
|
|
||||||
if tid, err := strconv.Atoi(string(args[0])); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if team, err := fic.GetTeam(tid); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return team.Delete()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,164 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"srs.epita.fr/fic-server/libfic"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ApiThemesRouting = map[string]DispatchFunction{
|
|
||||||
"GET": listTheme,
|
|
||||||
"PATCH": updateTheme,
|
|
||||||
"POST": creationTheme,
|
|
||||||
"DELETE": deletionTheme,
|
|
||||||
}
|
|
||||||
|
|
||||||
func bindingFiles() (string, 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 getTheme(args []string) (fic.Theme, error) {
|
|
||||||
if tid, err := strconv.Atoi(string(args[0])); err != nil {
|
|
||||||
return fic.Theme{}, err
|
|
||||||
} else {
|
|
||||||
return fic.GetTheme(tid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getExercice(args []string) (fic.Exercice, error) {
|
|
||||||
if theme, err := getTheme(args); err != nil {
|
|
||||||
return fic.Exercice{}, err
|
|
||||||
} else if eid, err := strconv.Atoi(string(args[1])); err != nil {
|
|
||||||
return fic.Exercice{}, err
|
|
||||||
} else {
|
|
||||||
return theme.GetExercice(eid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func listTheme(args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) == 3 {
|
|
||||||
if e, err := getExercice(args); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
if args[2] == "files" {
|
|
||||||
return e.GetFiles()
|
|
||||||
} else if args[2] == "keys" {
|
|
||||||
return e.GetKeys()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if len(args) == 2 {
|
|
||||||
if args[1] == "exercices" {
|
|
||||||
if theme, err := getTheme(args); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return theme.GetExercices()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return getExercice(args)
|
|
||||||
}
|
|
||||||
} else if len(args) == 1 {
|
|
||||||
if args[0] == "files-bindings" {
|
|
||||||
return bindingFiles()
|
|
||||||
} else if args[0] == "themes.json" {
|
|
||||||
return fic.ExportThemes()
|
|
||||||
} else {
|
|
||||||
return getTheme(args)
|
|
||||||
}
|
|
||||||
} else if len(args) == 0 {
|
|
||||||
// List all themes
|
|
||||||
return fic.GetThemes()
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type uploadedTheme struct {
|
|
||||||
Name string
|
|
||||||
Authors string
|
|
||||||
}
|
|
||||||
|
|
||||||
func creationTheme(args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) >= 1 {
|
|
||||||
if theme, err := getTheme(args); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return createExercice(theme, args[1:], body)
|
|
||||||
}
|
|
||||||
} else if len(args) == 0 {
|
|
||||||
// Create a new theme
|
|
||||||
var ut uploadedTheme
|
|
||||||
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.Name, ut.Authors)
|
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateTheme(args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) == 2 {
|
|
||||||
// Update an exercice
|
|
||||||
var ue fic.Exercice
|
|
||||||
if err := json.Unmarshal(body, &ue); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ue.Title) == 0 {
|
|
||||||
return nil, errors.New("Exercice's title not filled")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := ue.Update(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ue, nil
|
|
||||||
} else if len(args) == 1 {
|
|
||||||
// Update a theme
|
|
||||||
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 ut.Update()
|
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func deletionTheme(args []string, body []byte) (interface{}, error) {
|
|
||||||
if len(args) == 2 {
|
|
||||||
if exercice, err := getExercice(args); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return exercice.Delete()
|
|
||||||
}
|
|
||||||
} else if len(args) == 1 {
|
|
||||||
if theme, err := getTheme(args); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
return theme.Delete()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import ()
|
|
||||||
|
|
||||||
var ApiVersionRouting = map[string]DispatchFunction{
|
|
||||||
"GET": showVersion,
|
|
||||||
}
|
|
||||||
|
|
||||||
func showVersion(args []string, body []byte) (interface{}, error) {
|
|
||||||
return map[string]interface{}{"version": 0.1}, nil
|
|
||||||
}
|
|
|
@ -10,29 +10,26 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
"srs.epita.fr/fic-server/admin/api"
|
||||||
"srs.epita.fr/fic-server/libfic"
|
"srs.epita.fr/fic-server/libfic"
|
||||||
)
|
)
|
||||||
|
|
||||||
var PKIDir string
|
var PKIDir string
|
||||||
var SubmissionDir string
|
var SubmissionDir string
|
||||||
var BaseURL string
|
|
||||||
var CloudDAVBase string
|
|
||||||
var CloudUsername string
|
|
||||||
var CloudPassword string
|
|
||||||
var StaticDir string
|
var StaticDir string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var bind = flag.String("bind", "127.0.0.1:8081", "Bind port/socket")
|
var bind = flag.String("bind", "127.0.0.1:8081", "Bind port/socket")
|
||||||
var dsn = flag.String("dsn", "fic:fic@/fic", "DSN to connect to the MySQL server")
|
var dsn = flag.String("dsn", "fic:fic@/fic", "DSN to connect to the MySQL server")
|
||||||
flag.StringVar(&BaseURL, "baseurl", "/", "URL prepended to each URL")
|
var baseURL = flag.String("baseurl", "/", "URL prepended to each URL")
|
||||||
flag.StringVar(&SubmissionDir, "submission", "./submissions/", "Base directory where save submissions")
|
flag.StringVar(&SubmissionDir, "submission", "./submissions/", "Base directory where save submissions")
|
||||||
flag.StringVar(&PKIDir, "pki", "./pki/", "Base directory where found PKI scripts")
|
flag.StringVar(&PKIDir, "pki", "./pki/", "Base directory where found PKI scripts")
|
||||||
flag.StringVar(&StaticDir, "static", "./htdocs-admin/", "Directory containing static files")
|
flag.StringVar(&StaticDir, "static", "./htdocs-admin/", "Directory containing static files")
|
||||||
flag.StringVar(&fic.FilesDir, "files", "./FILES/", "Base directory where found challenges files, local part")
|
flag.StringVar(&fic.FilesDir, "files", "./FILES/", "Base directory where found challenges files, local part")
|
||||||
flag.StringVar(&CloudDAVBase, "clouddav", "https://srs.epita.fr/owncloud/remote.php/webdav/FIC 2016",
|
flag.StringVar(&api.CloudDAVBase, "clouddav", "https://srs.epita.fr/owncloud/remote.php/webdav/FIC 2016",
|
||||||
"Base directory where found challenges files, cloud part")
|
"Base directory where found challenges files, cloud part")
|
||||||
flag.StringVar(&CloudUsername, "clouduser", "fic", "Username used to sync")
|
flag.StringVar(&api.CloudUsername, "clouduser", "fic", "Username used to sync")
|
||||||
flag.StringVar(&CloudPassword, "cloudpass", "", "Password used to sync")
|
flag.StringVar(&api.CloudPassword, "cloudpass", "", "Password used to sync")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
log.SetPrefix("[admin] ")
|
log.SetPrefix("[admin] ")
|
||||||
|
@ -78,15 +75,8 @@ func main() {
|
||||||
|
|
||||||
os.Chdir(PKIDir)
|
os.Chdir(PKIDir)
|
||||||
|
|
||||||
log.Println("Registering handlers...")
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
mux.Handle(path.Join(BaseURL, "api") + "/", http.StripPrefix(path.Join(BaseURL, "api"), ApiHandler()))
|
|
||||||
mux.Handle(path.Join(BaseURL, "teams") + "/", http.StripPrefix(BaseURL, StaticHandler(staticDir)))
|
|
||||||
mux.Handle(path.Join(BaseURL, "themes") + "/", http.StripPrefix(BaseURL, StaticHandler(staticDir)))
|
|
||||||
mux.Handle(BaseURL, http.StripPrefix(BaseURL, http.FileServer(http.Dir(staticDir))))
|
|
||||||
|
|
||||||
log.Println(fmt.Sprintf("Ready, listening on %s", *bind))
|
log.Println(fmt.Sprintf("Ready, listening on %s", *bind))
|
||||||
if err := http.ListenAndServe(*bind, mux); err != nil {
|
if err := http.ListenAndServe(*bind, http.StripPrefix(*baseURL, api.Router())); err != nil {
|
||||||
log.Fatal("Unable to listen and serve: ", err)
|
log.Fatal("Unable to listen and serve: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue