package api import ( "fmt" "io/ioutil" "log" "net/http" "path/filepath" "runtime/debug" "gogs.carducci-dante.gov.it/karmen/core/orm" "gogs.carducci-dante.gov.it/karmen/core/renderer" jwtmiddleware "github.com/auth0/go-jwt-middleware" jwt "github.com/dgrijalva/jwt-go" "github.com/gorilla/mux" "github.com/gorilla/sessions" ) var ( signingKey = []byte("secret") store = sessions.NewCookieStore([]byte("something-very-secret")) jwtMiddleware = jwtmiddleware.New(jwtmiddleware.Options{ ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) { return signingKey, nil }, SigningMethod: jwt.SigningMethodHS256, Extractor: fromCookie, ErrorHandler: onError, }) crud []string = []string{"add", "show", "update", "delete"} ) type User struct { Name string Admin bool } // Generate CRUD handlers func generateHandler(r *mux.Router, base string) { r.Handle(fmt.Sprintf("/%s", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s", base))))).Methods("GET") r.Handle(fmt.Sprintf("/%s/{id}", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/{id}", base))))).Methods("GET") r.Handle(fmt.Sprintf("/%s/add/", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/add/", base))))).Methods("GET", "POST") r.Handle(fmt.Sprintf("/%s/{id}/update", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/{id}/update", base))))).Methods("GET", "POST") r.Handle(fmt.Sprintf("/%s/{id}/delete", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/{id}/delete", base))))).Methods("POST") } func Handlers() *mux.Router { r := mux.NewRouter() // Authentication r.Handle("/login", loginHandler()) r.Handle("/logout", logoutHandler()) // Dashboard r.Handle("/", jwtMiddleware.Handler(recoverHandler(dashboardHandler()))) // Generate handlers for _, model := range []string{"teachers", "activities"} { generateHandler(r, model) } // Static file server r.PathPrefix("/").Handler(http.FileServer(http.Dir("./dist/"))) return r } func onError(w http.ResponseWriter, r *http.Request, err string) { http.Redirect(w, r, "/login", http.StatusTemporaryRedirect) } func respondWithStaticFile(w http.ResponseWriter, filename string) error { f, err := ioutil.ReadFile(filepath.Join("public/html", filename)) if err != nil { return err } w.Write(f) return nil } func fromCookie(r *http.Request) (string, error) { session, err := store.Get(r, "login-session") if err != nil { return "", nil } if session.Values["token"] == nil { return "", nil } token := session.Values["token"].([]uint8) return string(token), nil } func recoverHandler(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { defer func() { if err := recover(); err != nil { panicMsg := fmt.Sprintf("PANIC: %v\n\n== STACKTRACE ==\n%s", err, debug.Stack()) log.Print(panicMsg) http.Error(w, panicMsg, http.StatusInternalServerError) } }() next.ServeHTTP(w, r) } return http.HandlerFunc(fn) } func generalHandler(base, path string) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { var ( ok bool getFn orm.GetFn postFn orm.PostFn ) if r.Method == "GET" { getFn, ok = orm.Get[path] } else { postFn, ok = orm.Post[path] } if !ok { renderer.Render[r.URL.Query()["format"][0]](w, r, fmt.Errorf("Can't find ORM function for path %s!", path)) } else { if r.Method == "GET" { data, err := getFn(mux.Vars(r)) if err != nil { renderer.Render[r.URL.Query()["format"][0]](w, r, err) } else { renderer.Render[r.URL.Query()["format"][0]](w, r, data, r.URL.Query()) } } else { data, err := postFn(mux.Vars(r), r) if err != nil { renderer.Render["html"](w, r, err) } else { if mux.Vars(r)["id"] != "" { http.Redirect(w, r, fmt.Sprintf( "/%s/%s?format=html&tpl_layout=base&tpl_content=%s_show", base, mux.Vars(r)["id"], base, ), http.StatusSeeOther, ) } else { http.Redirect(w, r, fmt.Sprintf( "/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show", base, data.GetID(), base, ), http.StatusSeeOther, ) } } } } } return http.HandlerFunc(fn) }