You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
website/server/fiber.go

249 lines
5.8 KiB
Go

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/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 <nil> of type interface{} to *model.User, in other words <nil> of type *model.User and <nil> 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 <nil> 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.HandleAppuntiPage(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)
})
r.Post("/appunti/dispense", func(c *fiber.Ctx) error {
var dispensaTemplate model.Dispensa
if err := c.BodyParser(&dispensaTemplate); err != nil {
return err
}
dispensaId, err := h.HandleCreateDispensa(dispensaTemplate, CreateContext(c))
if err != nil {
return err
}
return c.JSON(dispensaId)
})
r.Get("/appunti/dispense", func(c *fiber.Ctx) error {
dispensaId := c.Query("id")
dispensa, err := h.HandleGetDispensa(dispensaId)
if err != nil {
return err
}
return c.JSON(dispensa)
})
}