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 <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" , func ( c * fiber . Ctx ) error {
var dispensaTemplate model . Dispensa
if err := c . BodyParser ( & dispensaTemplate ) ; err != nil {
return err
}
dispensa , err := h . HandleCreateDispensa ( dispensaTemplate , CreateContext ( c ) )
if err != nil {
return err
}
return c . JSON ( dispensa )
} )
}