Big refactor
@ -0,0 +1 @@
|
|||||||
|
@import"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;700&display=swap";:root{--fg-300: #777;--fg-400: #666;--fg-500: #333;--fg-600: #222;--bg-000: #f0f0f0;--bg-100: #f0f0f0;--bg-500: #eaeaea;--bg-550: #ecedee;--bg-600: #e4e5e7;--bg-700: #d5d5d5;--bg-750: #c8c8c8;--bg-800: #c0c0c0;--bg-850: #b8b8b8;--accent-300: #5cc969;--accent-400: #4eaa59;--accent-500: #278542;--accent-600: #2e974c;--accent-700: #154d24;--accent-800: #002d0d;--ft-ss: "Inter", sans-serif;--ft-ss-wt-light: 300;--ft-ss-wt-normal: 400;--ft-ss-wt-medium: 500;--ft-ss-wt-bold: 700;--shadow-500: 0 0 16px 0 #00000018;--text-input-bg: var(--bg-000);--text-input-readonly-bg: var(--bg-600);--text-input-readonly-fg: var(--fg-300)}*{box-sizing:border-box}html,body{margin:0}html{height:100%;width:100%}body{background:var(--bg-500);color:var(--fg-500);font-family:var(--ft-ss);font-size:17px;font-weight:var(--ft-ss-wt-normal);width:100%;min-height:100%;position:relative}h1,h2,h3,h4{margin:0;margin-top:1rem;margin-bottom:.5rem;font-weight:var(--font-weight-light)}h1{font-size:2rem}h2{font-size:1.5rem}h3{font-size:1.35rem}h4{font-size:1.2rem;font-weight:var(--font-weight-bold)}p,ul,ol,li{margin:0;width:70ch;max-width:100%;line-height:1.8}p+p{padding-top:.5rem}ul,ol{padding:0 0 0 1.5rem}hr{width:50ch;height:1px;margin:0;border:none;background-color:var(--bg-darker-2)}pre{margin:.5rem 0;background:var(--bg-lighter);border:1px solid #cbcbcb;border-radius:2px;box-shadow:0 2px 4px 0 rgba(0,0,0,.2);font-size:90%;display:flex;overflow-x:auto}pre>code{display:block;margin:.25rem}p.center{text-align:center}
|
Before Width: | Height: | Size: 790 B After Width: | Height: | Size: 790 B |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 765 B After Width: | Height: | Size: 765 B |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 4.6 MiB After Width: | Height: | Size: 4.6 MiB |
@ -0,0 +1 @@
|
|||||||
|
!function(a){"use strict";function o(a){return a&&"object"==typeof a&&"default"in a?a:{default:a}}var s=o(a);s.default.data("profilo",(()=>({init(){console.log("Profilo!")}}))),s.default.data("passwordForm",(()=>({password:"",passwordAgain:"",passwordSame:!0,onUpdate(){this.passwordSame=this.password===this.passwordAgain}})))}(Alpine);
|
@ -0,0 +1 @@
|
|||||||
|
!function(e,s){"use strict";function t(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var o=t(e),r=t(s);const i={includeScore:!0,keys:["nome","cognome","tags",{name:"nomeCompleto",getFn:e=>`${e.nome} ${e.cognome}`}]},h={chronological:()=>0,name:(e,s)=>e.nome<s.nome?-1:1,surname:(e,s)=>e.cognome<s.cognome?-1:1};o.default.data("utenti",(()=>({searchField:"",sortMode:"chronological",fetchedUsers:[],sortedUserBuffer:[],fuse:new r.default([],i),searchResultsBuffer:[],searchResults:[],async init(){const e=await fetch("/api/utenti");this.fetchedUsers=await e.json(),new IntersectionObserver((e=>{e.forEach((e=>{e.isIntersecting&&(console.log("Near the bottom of the page"),this.showMore())}))})).observe(this.$refs.spinner),this.updateSortMode(),this.updateSearch()},showMore(){const e=this.searchResults.length+15;this.searchResults=this.searchResultsBuffer.slice(0,e)},setResults(e){this.searchResultsBuffer=e.filter((e=>void 0===e.score||e.score<=.25)),this.searchResults=this.searchResultsBuffer.slice(0,15)},updateSortMode(){var e,s;this.sortedUserBuffer=(e=this.fetchedUsers,s=this.sortMode,[...e].sort(h[s])),this.fuse.setCollection(this.sortedUserBuffer),this.updateSearch()},updateSearch(){console.time("search"),0===this.searchField.trim().length?this.setResults(this.sortedUserBuffer.map((e=>({item:e})))):this.setResults(this.fuse.search(this.searchField)),console.timeEnd("search")}})))}(Alpine,Fuse);
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 140 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 620 KiB After Width: | Height: | Size: 620 KiB |
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
@ -0,0 +1,41 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"git.phc.dm.unipi.it/phc/website"
|
||||||
|
"git.phc.dm.unipi.it/phc/website/articles"
|
||||||
|
"git.phc.dm.unipi.it/phc/website/auth"
|
||||||
|
"git.phc.dm.unipi.it/phc/website/config"
|
||||||
|
"git.phc.dm.unipi.it/phc/website/handler"
|
||||||
|
"git.phc.dm.unipi.it/phc/website/server"
|
||||||
|
"git.phc.dm.unipi.it/phc/website/templates"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
config.Load()
|
||||||
|
|
||||||
|
h := &handler.DefaultHandler{
|
||||||
|
AuthService: auth.NewDefaultService(config.AuthServiceHost),
|
||||||
|
Renderer: templates.NewRenderer(
|
||||||
|
"./views/",
|
||||||
|
"./views/base.html",
|
||||||
|
"./views/partials/*.html",
|
||||||
|
),
|
||||||
|
NewsArticlesRegistry: articles.NewRegistry("./news"),
|
||||||
|
ListaUtenti: &website.JsonFileListUtenti{
|
||||||
|
Path: "./utenti-poisson-2022.local.json",
|
||||||
|
},
|
||||||
|
Storia: &website.JsonFileStoria{
|
||||||
|
Path: "./storia.json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
app := server.NewFiberServer(h)
|
||||||
|
|
||||||
|
log.Printf("Starting server on host %q", config.Host)
|
||||||
|
err := app.Listen(config.Host)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
type ContextKey[T any] string
|
||||||
|
|
||||||
|
type Context map[string]any
|
||||||
|
|
||||||
|
func GetContextValue[T any](ctx Context, key ContextKey[T]) T {
|
||||||
|
value, present := ctx[string(key)]
|
||||||
|
if !present {
|
||||||
|
var zero T
|
||||||
|
return zero
|
||||||
|
}
|
||||||
|
|
||||||
|
typedValue, _ := value.(T)
|
||||||
|
|
||||||
|
return typedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetContextValue[T any](ctx Context, key ContextKey[T], value T) {
|
||||||
|
ctx[string(key)] = value
|
||||||
|
}
|
@ -0,0 +1,147 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"git.phc.dm.unipi.it/phc/website"
|
||||||
|
"git.phc.dm.unipi.it/phc/website/articles"
|
||||||
|
"git.phc.dm.unipi.it/phc/website/auth"
|
||||||
|
"git.phc.dm.unipi.it/phc/website/model"
|
||||||
|
"git.phc.dm.unipi.it/phc/website/templates"
|
||||||
|
"git.phc.dm.unipi.it/phc/website/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service interface {
|
||||||
|
HandleStaticPage(w io.Writer, view string, ctx Context) error
|
||||||
|
HandleUtenti() ([]*model.User, error)
|
||||||
|
HandleStoriaPage(w io.Writer, ctx Context) error
|
||||||
|
HandleQueryAppunti(w io.Writer, query string, ctx Context) error
|
||||||
|
HandleNewsPage(w io.Writer, ctx Context) error
|
||||||
|
HandleLogin(username, password string) (*model.Session, error)
|
||||||
|
HandleUser(token string) *model.User
|
||||||
|
HandleRequiredUser(ctx Context) (*model.User, error)
|
||||||
|
HandleProfilePage(w io.Writer, ctx Context) error
|
||||||
|
HandleArticlePage(w io.Writer, articleID string, ctx Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Typed context
|
||||||
|
//
|
||||||
|
|
||||||
|
// UserKey is a typed type for *model.User used to extract a user form a [handler.Context]
|
||||||
|
const UserKey ContextKey[*model.User] = "user"
|
||||||
|
|
||||||
|
func (ctx Context) getUser() *model.User {
|
||||||
|
return GetContextValue(ctx, UserKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler holds references to abstract services for easy testing provided by every module (TODO: Make every field an interface of -Service)
|
||||||
|
type DefaultHandler struct {
|
||||||
|
AuthService auth.Service
|
||||||
|
Renderer *templates.TemplateRenderer
|
||||||
|
NewsArticlesRegistry *articles.Registry
|
||||||
|
ListaUtenti website.ListaUtentiService
|
||||||
|
Storia website.StoriaService
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultHandler) HandleStaticPage(w io.Writer, view string, ctx Context) error {
|
||||||
|
return h.Renderer.Render(w, view, util.Map{
|
||||||
|
"User": ctx.getUser(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultHandler) HandleUtenti() ([]*model.User, error) {
|
||||||
|
utenti, err := h.AuthService.GetUsers()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return utenti, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultHandler) HandleStoriaPage(w io.Writer, ctx Context) error {
|
||||||
|
storia, err := h.Storia.GetStoria()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.Renderer.Render(w, "storia.html", util.Map{
|
||||||
|
"User": ctx.getUser(),
|
||||||
|
"Storia": storia,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultHandler) HandleQueryAppunti(w io.Writer, query string, ctx Context) error {
|
||||||
|
return h.Renderer.Render(w, "appunti.html", util.Map{
|
||||||
|
"User": ctx.getUser(),
|
||||||
|
"Query": query,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultHandler) HandleNewsPage(w io.Writer, ctx Context) error {
|
||||||
|
articles, err := h.NewsArticlesRegistry.GetArticles()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.Renderer.Render(w, "news.html", util.Map{
|
||||||
|
"User": ctx.getUser(),
|
||||||
|
"Articles": articles,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultHandler) HandleLogin(username, password string) (*model.Session, error) {
|
||||||
|
session, err := h.AuthService.Login(username, password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return session, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultHandler) HandleUser(token string) *model.User {
|
||||||
|
user, _ := auth.UserForSession(h.AuthService, token)
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
var ErrNoUser = fmt.Errorf(`user not logged in`)
|
||||||
|
|
||||||
|
func (h *DefaultHandler) HandleRequiredUser(ctx Context) (*model.User, error) {
|
||||||
|
user := ctx.getUser()
|
||||||
|
if user == nil {
|
||||||
|
return nil, ErrNoUser
|
||||||
|
}
|
||||||
|
|
||||||
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultHandler) HandleProfilePage(w io.Writer, ctx Context) error {
|
||||||
|
user := ctx.getUser()
|
||||||
|
if user == nil {
|
||||||
|
return ErrNoUser
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.Renderer.Render(w, "profilo.html", util.Map{
|
||||||
|
"User": user,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *DefaultHandler) HandleArticlePage(w io.Writer, articleID string, ctx Context) error {
|
||||||
|
article, err := h.NewsArticlesRegistry.GetArticle(articleID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
html, err := article.Render()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.Renderer.Render(w, "news-base.html", util.Map{
|
||||||
|
"User": ctx.getUser(),
|
||||||
|
"Article": article,
|
||||||
|
"ContentHTML": template.HTML(html),
|
||||||
|
})
|
||||||
|
}
|
@ -1,208 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"html/template"
|
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.phc.dm.unipi.it/phc/website/articles"
|
|
||||||
"git.phc.dm.unipi.it/phc/website/auth"
|
|
||||||
"git.phc.dm.unipi.it/phc/website/config"
|
|
||||||
"git.phc.dm.unipi.it/phc/website/model"
|
|
||||||
"git.phc.dm.unipi.it/phc/website/templates"
|
|
||||||
"git.phc.dm.unipi.it/phc/website/util"
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
|
||||||
"github.com/gofiber/fiber/v2/middleware/recover"
|
|
||||||
"github.com/gofiber/redirect/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
func UserMiddleware(as auth.Service) fiber.Handler {
|
|
||||||
return func(c *fiber.Ctx) error {
|
|
||||||
token := c.Cookies("session-token")
|
|
||||||
user, _ := auth.UserForSession(as, token)
|
|
||||||
c.Locals("user", user)
|
|
||||||
return c.Next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
config.Load()
|
|
||||||
|
|
||||||
app := fiber.New()
|
|
||||||
|
|
||||||
app.Use(logger.New())
|
|
||||||
app.Use(recover.New())
|
|
||||||
|
|
||||||
// Remove trailing slash from URLs
|
|
||||||
app.Use(redirect.New(redirect.Config{
|
|
||||||
Rules: map[string]string{
|
|
||||||
"/*/": "/$1",
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
|
|
||||||
// Serve content statically from "./public", mounted on the "/public/" route
|
|
||||||
app.Static("/public/", "./public")
|
|
||||||
|
|
||||||
authService := auth.NewDefaultService(config.AuthServiceHost)
|
|
||||||
app.Use(UserMiddleware(authService))
|
|
||||||
|
|
||||||
// Templates & Renderer
|
|
||||||
renderer := templates.NewRenderer(
|
|
||||||
"./views/",
|
|
||||||
"./views/base.html",
|
|
||||||
"./views/partials/*.html",
|
|
||||||
)
|
|
||||||
|
|
||||||
newsArticlesRegistry := articles.NewRegistry("./news")
|
|
||||||
|
|
||||||
// Routes
|
|
||||||
|
|
||||||
actuallyStaticRoutes := map[string]string{
|
|
||||||
"/": "home.html",
|
|
||||||
"/link": "link.html",
|
|
||||||
"/login": "login.html",
|
|
||||||
"/utenti": "utenti.html",
|
|
||||||
}
|
|
||||||
|
|
||||||
for route, view := range actuallyStaticRoutes {
|
|
||||||
localView := view
|
|
||||||
app.Get(route, func(c *fiber.Ctx) error {
|
|
||||||
c.Type("html")
|
|
||||||
return renderer.Render(c, localView, util.H{
|
|
||||||
"User": c.Locals("user"),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
app.Get("/api/utenti", func(c *fiber.Ctx) error {
|
|
||||||
utenti, err := authService.GetUsers()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(utenti)
|
|
||||||
})
|
|
||||||
|
|
||||||
app.Get("/api/profilo", func(c *fiber.Ctx) error {
|
|
||||||
user := c.Locals("user")
|
|
||||||
if user == nil {
|
|
||||||
return fmt.Errorf(`user not logged in`)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(user)
|
|
||||||
})
|
|
||||||
|
|
||||||
app.Get("/storia", func(c *fiber.Ctx) error {
|
|
||||||
storia, err := GetStoria()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Type("html")
|
|
||||||
return renderer.Render(c, "storia.html", util.H{
|
|
||||||
"User": c.Locals("user"),
|
|
||||||
"Storia": storia,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
app.Get("/appunti", func(c *fiber.Ctx) error {
|
|
||||||
searchQuery := c.Query("q", "")
|
|
||||||
|
|
||||||
c.Type("html")
|
|
||||||
return renderer.Render(c, "appunti.html", util.H{
|
|
||||||
"User": c.Locals("user"),
|
|
||||||
"Query": searchQuery,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
app.Get("/news", func(c *fiber.Ctx) error {
|
|
||||||
articles, err := newsArticlesRegistry.GetArticles()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Type("html")
|
|
||||||
return renderer.Render(c, "news.html", util.H{
|
|
||||||
"User": c.Locals("user"),
|
|
||||||
"Articles": articles,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
app.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 := authService.Login(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")
|
|
||||||
})
|
|
||||||
|
|
||||||
app.Get("/profilo", func(c *fiber.Ctx) error {
|
|
||||||
user, ok := c.Locals("user").(*model.User)
|
|
||||||
if !ok || user == nil {
|
|
||||||
return fmt.Errorf(`user not logged in`)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Type("html")
|
|
||||||
return renderer.Render(c, "profilo.html", util.H{
|
|
||||||
"User": c.Locals("user"),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
app.Get("/logout", func(c *fiber.Ctx) error {
|
|
||||||
c.Cookie(&fiber.Cookie{
|
|
||||||
Name: "session-token",
|
|
||||||
Path: "/",
|
|
||||||
Value: "",
|
|
||||||
Expires: time.Now(),
|
|
||||||
})
|
|
||||||
return c.Redirect("/")
|
|
||||||
})
|
|
||||||
|
|
||||||
app.Get("/news/:article", func(c *fiber.Ctx) error {
|
|
||||||
articleID := c.Params("article")
|
|
||||||
|
|
||||||
article, err := newsArticlesRegistry.GetArticle(articleID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
html, err := article.Render()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Type("html")
|
|
||||||
return renderer.Render(c, "news-base.html", util.H{
|
|
||||||
"User": c.Locals("user"),
|
|
||||||
"Article": article,
|
|
||||||
"ContentHTML": template.HTML(html),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
log.Printf("Starting server on host %q", config.Host)
|
|
||||||
err := app.Listen(config.Host)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,172 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"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/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
|
||||||
|
}
|
||||||
|
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Serve content statically from "./public", mounted on the "/public/" route
|
||||||
|
r.Static("/public/", "./public")
|
||||||
|
|
||||||
|
// 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("/news", func(c *fiber.Ctx) error {
|
||||||
|
c.Type("html")
|
||||||
|
return h.HandleNewsPage(c, CreateContext(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.HandleArticlePage(c, articleID, CreateContext(c))
|
||||||
|
})
|
||||||
|
|
||||||
|
routesApi(h, r.Group("/api"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func routesApi(h handler.Service, r fiber.Router) {
|
||||||
|
r.Get("/api/utenti", func(c *fiber.Ctx) error {
|
||||||
|
utenti, err := h.HandleUtenti()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(utenti)
|
||||||
|
})
|
||||||
|
|
||||||
|
r.Get("/api/profilo", func(c *fiber.Ctx) error {
|
||||||
|
user, err := h.HandleRequiredUser(CreateContext(c))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(user)
|
||||||
|
})
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
package util
|
|