admin/api: use gorilla/mux instead of Go router
This commit is contained in:
parent
3e74f5f9ef
commit
173dafa69e
18 changed files with 643 additions and 720 deletions
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)
|
||||
}
|
89
admin/api/file.go
Normal file
89
admin/api/file.go
Normal file
|
@ -0,0 +1,89 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/sha512"
|
||||
"encoding/base32"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"srs.epita.fr/fic-server/libfic"
|
||||
)
|
||||
|
||||
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
|
||||
if err := json.Unmarshal(body, &uf); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var hash [sha512.Size]byte
|
||||
var logStr string
|
||||
var fromURI string
|
||||
var getFile func(string) (error)
|
||||
|
||||
if URI, ok := uf["URI"]; ok {
|
||||
hash = sha512.Sum512([]byte(URI))
|
||||
logStr = "Import file from Cloud: " + URI + " =>"
|
||||
fromURI = URI
|
||||
getFile = func(dest string) error { return getCloudFile(URI, dest); }
|
||||
} else if path, ok := uf["path"]; ok {
|
||||
hash = sha512.Sum512([]byte(path))
|
||||
logStr = "Import file from local FS: " + path + " =>"
|
||||
fromURI = path
|
||||
getFile = func(dest string) error { return os.Symlink(path, dest); }
|
||||
} else {
|
||||
return nil, errors.New("URI or path not filled")
|
||||
}
|
||||
|
||||
pathname := path.Join(fic.FilesDir, strings.ToLower(base32.StdEncoding.EncodeToString(hash[:])), path.Base(fromURI))
|
||||
|
||||
if _, err := os.Stat(pathname); os.IsNotExist(err) {
|
||||
log.Println(logStr, pathname)
|
||||
if err := os.MkdirAll(path.Dir(pathname), 0777); err != nil {
|
||||
return nil, err
|
||||
} else if err := getFile(pathname); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return exercice.ImportFile(pathname, fromURI)
|
||||
}
|
||||
|
||||
func getCloudFile(pathname string, dest string) error {
|
||||
client := http.Client{}
|
||||
if req, err := http.NewRequest("GET", CloudDAVBase+pathname, nil); err != nil {
|
||||
return err
|
||||
} else {
|
||||
req.SetBasicAuth(CloudUsername, CloudPassword)
|
||||
if resp, err := client.Do(req); err != nil {
|
||||
return err
|
||||
} else {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if fd, err := os.Create(dest); err != nil {
|
||||
return err
|
||||
} else {
|
||||
defer fd.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return errors.New(resp.Status)
|
||||
} else {
|
||||
writer := bufio.NewWriter(fd)
|
||||
reader := bufio.NewReader(resp.Body)
|
||||
reader.WriteTo(writer)
|
||||
writer.Flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
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
|
||||
}
|
43
admin/api/stats.go
Normal file
43
admin/api/stats.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"srs.epita.fr/fic-server/libfic"
|
||||
)
|
||||
|
||||
type statsTheme struct {
|
||||
SolvedByLevel []int `json:"solvedByLevel"`
|
||||
}
|
||||
|
||||
type stats struct {
|
||||
Themes map[string]statsTheme `json:"themes"`
|
||||
TryRank []int64 `json:"tryRank"`
|
||||
}
|
||||
|
||||
func genStats() (interface{}, error) {
|
||||
ret := map[string]statsTheme{}
|
||||
|
||||
if themes, err := fic.GetThemes(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
for _, theme := range themes {
|
||||
if exercices, err := theme.GetExercices(); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
exos := map[string]fic.ExportedExercice{}
|
||||
for _, exercice := range exercices {
|
||||
exos[fmt.Sprintf("%d", exercice.Id)] = fic.ExportedExercice{
|
||||
exercice.Title,
|
||||
exercice.Gain,
|
||||
exercice.SolvedCount(),
|
||||
exercice.TriedTeamCount(),
|
||||
}
|
||||
}
|
||||
ret[fmt.Sprintf("%d", theme.Id)] = statsTheme{}
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
}
|
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
|
||||
}
|
Reference in a new issue