package handler import ( "fmt" "html/template" "io" "git.phc.dm.unipi.it/phc/website/appunti" "git.phc.dm.unipi.it/phc/website/articles" "git.phc.dm.unipi.it/phc/website/auth" "git.phc.dm.unipi.it/phc/website/lista_utenti" "git.phc.dm.unipi.it/phc/website/model" "git.phc.dm.unipi.it/phc/website/rss" "git.phc.dm.unipi.it/phc/website/storia" "git.phc.dm.unipi.it/phc/website/templates" "git.phc.dm.unipi.it/phc/website/util" ) type Service interface { // // Pages // HandleStaticPage(w io.Writer, view string, ctx Context) error // Storia HandleStoriaPage(w io.Writer, ctx Context) error // Appunti HandleAppuntiPage(w io.Writer, query string, ctx Context) error HandleAppuntiCondivisiPage(w io.Writer, ctx Context) error HandleDispensaPage(w io.Writer, id string, ctx Context) error // News HandleNewsPage(w io.Writer, ctx Context) error // Guide HandleGuidePage(w io.Writer, ctx Context) error // User HandleProfilePage(w io.Writer, ctx Context) error // Article Pages HandleNewsArticlePage(w io.Writer, articleID string, ctx Context) error HandleGuideArticlePage(w io.Writer, articleID string, ctx Context) error // RSS HandleNewsFeedPage(w io.Writer) error HandleGuideFeedPage(w io.Writer) error // // API // // User HandleLogin(username, password string) (*model.Session, error) HandleUser(token string) *model.User HandleRequiredUser(ctx Context) (*model.User, error) // User Listing HandleUtenti() ([]*model.User, error) HandleListaUtenti() ([]*model.ListUser, error) // Appunti HandleCreateDispensa(template model.Dispensa, ctx Context) (*model.Dispensa, 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 AppuntiService appunti.Service Renderer *templates.TemplateRenderer NewsArticlesRegistry *articles.Registry GuideArticlesRegistry *articles.Registry ListaUtenti lista_utenti.Service Storia storia.StoriaService } var _ Service = &DefaultHandler{} 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) HandleListaUtenti() ([]*model.ListUser, error) { utenti, err := h.ListaUtenti.GetUtenti() 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) HandleAppuntiPage(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) HandleAppuntiCondivisiPage(w io.Writer, ctx Context) error { return h.Renderer.Render(w, "appunti-condivisi.html", util.Map{ "User": ctx.getUser(), }) } func (h *DefaultHandler) HandleDispensaPage(w io.Writer, id string, ctx Context) error { dispensa, err := h.AppuntiService.GetDispensa(id) if err != nil { return err } return h.Renderer.Render(w, "dispensa.html", util.Map{ "User": ctx.getUser(), "Dispensa": dispensa, }) } 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) HandleGuidePage(w io.Writer, ctx Context) error { articles, err := h.GuideArticlesRegistry.GetArticles() if err != nil { return err } return h.Renderer.Render(w, "guide.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) HandleNewsArticlePage(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), }) } func (h *DefaultHandler) HandleGuideArticlePage(w io.Writer, articleID string, ctx Context) error { article, err := h.GuideArticlesRegistry.GetArticle(articleID) if err != nil { return err } html, err := article.Render() if err != nil { return err } return h.Renderer.Render(w, "guide-base.html", util.Map{ "User": ctx.getUser(), "Article": article, "ContentHTML": template.HTML(html), }) } func (h *DefaultHandler) HandleNewsFeedPage(w io.Writer) error { registry, err := h.NewsArticlesRegistry.GetArticles() if err != nil { return err } newsFeed := rss.GenerateRssFeed(registry, "news", "Feed Notizie PHC", "https://phc.dm.unipi.it/news", "Le ultime nuove sul PHC.") return newsFeed.WriteRss(w) } func (h *DefaultHandler) HandleGuideFeedPage(w io.Writer) error { registry, err := h.GuideArticlesRegistry.GetArticles() if err != nil { return err } guideFeed := rss.GenerateRssFeed(registry, "guide", "Feed Guide PHC", "https://phc.dm.unipi.it/guide", "Le piĆ¹ recenti guide a carattere informatico a cura dei macchinisti del PHC.") return guideFeed.WriteRss(w) } // // API // func (h *DefaultHandler) HandleCreateDispensa(template model.Dispensa, ctx Context) (*model.Dispensa, error) { user := ctx.getUser() if user == nil { return nil, ErrNoUser } template.OwnerId = user.Username id, err := h.AppuntiService.CreateDispensa(template) if err != nil { return nil, err } template.Id = id if len(template.Tags) > 0 { h.AppuntiService.SetDispensaTags(id, template.Tags) } return &template, nil }