handlers.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. package api
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "log"
  6. "net/http"
  7. "path/filepath"
  8. "runtime/debug"
  9. "gogs.carducci-dante.gov.it/karmen/core/orm"
  10. "gogs.carducci-dante.gov.it/karmen/core/renderer"
  11. jwtmiddleware "github.com/auth0/go-jwt-middleware"
  12. jwt "github.com/dgrijalva/jwt-go"
  13. "github.com/gorilla/mux"
  14. "github.com/gorilla/sessions"
  15. )
  16. var (
  17. signingKey = []byte("secret")
  18. store = sessions.NewCookieStore([]byte("something-very-secret"))
  19. jwtMiddleware = jwtmiddleware.New(jwtmiddleware.Options{
  20. ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
  21. return signingKey, nil
  22. },
  23. SigningMethod: jwt.SigningMethodHS256,
  24. Extractor: fromCookie,
  25. ErrorHandler: onError,
  26. })
  27. crud []string = []string{"add", "show", "update", "delete"}
  28. )
  29. type User struct {
  30. Name string
  31. Admin bool
  32. }
  33. // Generate CRUD handlers
  34. func generateHandler(r *mux.Router, base string) {
  35. r.Handle(fmt.Sprintf("/%s", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s", base))))).Methods("GET")
  36. r.Handle(fmt.Sprintf("/%s/{id}", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/{id}", base))))).Methods("GET")
  37. r.Handle(fmt.Sprintf("/%s/add/", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/add/", base))))).Methods("GET", "POST")
  38. r.Handle(fmt.Sprintf("/%s/{id}/update", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/{id}/update", base))))).Methods("GET", "POST")
  39. r.Handle(fmt.Sprintf("/%s/{id}/delete", base), jwtMiddleware.Handler(recoverHandler(generalHandler(base, fmt.Sprintf("/%s/{id}/delete", base))))).Methods("POST")
  40. }
  41. func Handlers() *mux.Router {
  42. r := mux.NewRouter()
  43. // Authentication
  44. r.Handle("/login", loginHandler())
  45. r.Handle("/logout", logoutHandler())
  46. // Dashboard
  47. r.Handle("/", jwtMiddleware.Handler(recoverHandler(dashboardHandler())))
  48. // Generate handlers
  49. for _, model := range []string{"teachers", "activities"} {
  50. generateHandler(r, model)
  51. }
  52. // Static file server
  53. r.PathPrefix("/").Handler(http.FileServer(http.Dir("./dist/")))
  54. return r
  55. }
  56. func onError(w http.ResponseWriter, r *http.Request, err string) {
  57. http.Redirect(w, r, "/login", http.StatusTemporaryRedirect)
  58. }
  59. func respondWithStaticFile(w http.ResponseWriter, filename string) error {
  60. f, err := ioutil.ReadFile(filepath.Join("public/html", filename))
  61. if err != nil {
  62. return err
  63. }
  64. w.Write(f)
  65. return nil
  66. }
  67. func fromCookie(r *http.Request) (string, error) {
  68. session, err := store.Get(r, "login-session")
  69. if err != nil {
  70. return "", nil
  71. }
  72. if session.Values["token"] == nil {
  73. return "", nil
  74. }
  75. token := session.Values["token"].([]uint8)
  76. return string(token), nil
  77. }
  78. func recoverHandler(next http.Handler) http.Handler {
  79. fn := func(w http.ResponseWriter, r *http.Request) {
  80. defer func() {
  81. if err := recover(); err != nil {
  82. panicMsg := fmt.Sprintf("PANIC: %v\n\n== STACKTRACE ==\n%s", err, debug.Stack())
  83. log.Print(panicMsg)
  84. http.Error(w, panicMsg, http.StatusInternalServerError)
  85. }
  86. }()
  87. next.ServeHTTP(w, r)
  88. }
  89. return http.HandlerFunc(fn)
  90. }
  91. func generalHandler(base, path string) http.Handler {
  92. fn := func(w http.ResponseWriter, r *http.Request) {
  93. var (
  94. ok bool
  95. getFn orm.GetFn
  96. postFn orm.PostFn
  97. )
  98. if r.Method == "GET" {
  99. getFn, ok = orm.Get[path]
  100. } else {
  101. postFn, ok = orm.Post[path]
  102. }
  103. if !ok {
  104. renderer.Render[r.URL.Query()["format"][0]](w, r, fmt.Errorf("Can't find ORM function for path %s!", path))
  105. } else {
  106. if r.Method == "GET" {
  107. data, err := getFn(mux.Vars(r))
  108. if err != nil {
  109. renderer.Render[r.URL.Query()["format"][0]](w, r, err)
  110. } else {
  111. renderer.Render[r.URL.Query()["format"][0]](w, r, data, r.URL.Query())
  112. }
  113. } else {
  114. data, err := postFn(mux.Vars(r), r)
  115. if err != nil {
  116. renderer.Render["html"](w, r, err)
  117. } else {
  118. if mux.Vars(r)["id"] != "" {
  119. http.Redirect(w, r,
  120. fmt.Sprintf(
  121. "/%s/%s?format=html&tpl_layout=base&tpl_content=%s_show",
  122. base,
  123. mux.Vars(r)["id"],
  124. base,
  125. ),
  126. http.StatusSeeOther,
  127. )
  128. } else {
  129. http.Redirect(w, r,
  130. fmt.Sprintf(
  131. "/%s/%d?format=html&tpl_layout=base&tpl_content=%s_show",
  132. base,
  133. data.GetID(),
  134. base,
  135. ),
  136. http.StatusSeeOther,
  137. )
  138. }
  139. }
  140. }
  141. }
  142. }
  143. return http.HandlerFunc(fn)
  144. }