package server import ( "log" "time" "git.phc.dm.unipi.it/phc/website/config" "git.phc.dm.unipi.it/phc/website/handler" "git.phc.dm.unipi.it/phc/website/model" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/etag" "github.com/gofiber/fiber/v2/middleware/logger" "github.com/gofiber/fiber/v2/middleware/recover" "github.com/gofiber/redirect/v2" ) func UserMiddleware(h handler.Service) fiber.Handler { return func(c *fiber.Ctx) error { token := c.Cookies("session-token") user := h.HandleUser(token) c.Locals("user", user) return c.Next() } } func CreateContext(ctx *fiber.Ctx) handler.Context { // the "_" here is required because Go cannot cast of type interface{} to *model.User, in other words of type *model.User and of type interface{} are different type. In this case the "_" returns a boolean that tells whether the cast succeeded or not, if it is false the user variable gets assigned its default zero value that is of type *model.User user, _ := ctx.Locals("user").(*model.User) context := handler.Context{} handler.SetContextValue(context, handler.UserKey, user) return context } func NewFiberServer(h handler.Service) *fiber.App { app := fiber.New() routes(h, app) return app } // routes defines routes under "/" func routes(h handler.Service, r fiber.Router) { // // Initial setup // r.Use(logger.New()) r.Use(recover.New()) // Remove trailing slash from URLs r.Use(redirect.New(redirect.Config{ Rules: map[string]string{ "/*/": "/$1", }, })) // Better static file serving setup r.Route("/public", func(r fiber.Router) { // Cache client side files based on checksum r.Use(etag.New()) staticConfig := fiber.Static{} if config.Mode == "development" { log.Printf("Disabling Cache-Control in development mode") // if no "Cache-Control" is present the browser will cache heuristically (and we don't want that) r.Use(func(c *fiber.Ctx) error { c.Set("Cache-Control", "no-cache") return c.Next() }) staticConfig.CacheDuration = 1 * time.Millisecond } r.Static("/", "./_frontend/out", staticConfig) r.Static("/", "./_public", staticConfig) }) // Serve generated css and js files and the static "./_public" folder // Process all request and add user to the request context if there is a session cookie r.Use(UserMiddleware(h)) // // Pages // r.Get("/", func(c *fiber.Ctx) error { c.Type("html") return h.HandleStaticPage(c, "home.html", CreateContext(c)) }) r.Get("/link", func(c *fiber.Ctx) error { c.Type("html") return h.HandleStaticPage(c, "link.html", CreateContext(c)) }) r.Get("/login", func(c *fiber.Ctx) error { c.Type("html") return h.HandleStaticPage(c, "login.html", CreateContext(c)) }) r.Get("/utenti", func(c *fiber.Ctx) error { c.Type("html") return h.HandleStaticPage(c, "utenti.html", CreateContext(c)) }) r.Get("/storia", func(c *fiber.Ctx) error { c.Type("html") return h.HandleStoriaPage(c, CreateContext(c)) }) r.Get("/appunti", func(c *fiber.Ctx) error { query := c.Query("q", "") c.Type("html") return h.HandleQueryAppunti(c, query, CreateContext(c)) }) r.Get("/appunti/condivisi", func(c *fiber.Ctx) error { c.Type("html") return h.HandleAppuntiCondivisiPage(c, CreateContext(c)) }) r.Get("/news", func(c *fiber.Ctx) error { c.Type("html") return h.HandleNewsPage(c, CreateContext(c)) }) r.Get("/guide", func(c *fiber.Ctx) error { c.Type("html") return h.HandleGuidePage(c, CreateContext(c)) }) r.Get("/news/rss", func(c *fiber.Ctx) error { c.Type("xml") return h.HandleNewsFeedPage(c) }) r.Get("/guide/rss", func(c *fiber.Ctx) error { c.Type("xml") return h.HandleGuideFeedPage(c) }) r.Post("/login", func(c *fiber.Ctx) error { var loginForm struct { Provider string `form:"provider"` Username string `form:"username"` Password string `form:"password"` } if err := c.BodyParser(&loginForm); err != nil { return err } session, err := h.HandleLogin(loginForm.Username, loginForm.Password) if err != nil { return err } inThreeDays := time.Now().Add(3 * 24 * time.Hour) c.Cookie(&fiber.Cookie{ Name: "session-token", Path: "/", Value: session.Token, Expires: inThreeDays, }) return c.Redirect("/profilo") }) r.Get("/profilo", func(c *fiber.Ctx) error { c.Type("html") return h.HandleProfilePage(c, CreateContext(c)) }) r.Get("/logout", func(c *fiber.Ctx) error { c.Cookie(&fiber.Cookie{ Name: "session-token", Path: "/", Value: "", Expires: time.Now(), }) return c.Redirect("/") }) r.Get("/news/:article", func(c *fiber.Ctx) error { articleID := c.Params("article") c.Type("html") return h.HandleNewsArticlePage(c, articleID, CreateContext(c)) }) r.Get("/guide/:article", func(c *fiber.Ctx) error { articleID := c.Params("article") c.Type("html") return h.HandleGuideArticlePage(c, articleID, CreateContext(c)) }) routesApi(h, r.Group("/api")) } // routesApi defines routes under "/api" func routesApi(h handler.Service, r fiber.Router) { r.Get("/utenti", func(c *fiber.Ctx) error { utenti, err := h.HandleListaUtenti() if err != nil { return err } return c.JSON(utenti) }) r.Get("/profilo", func(c *fiber.Ctx) error { user, err := h.HandleRequiredUser(CreateContext(c)) if err != nil { return err } return c.JSON(user) }) }