package blog import ( "arimelody-web/admin/core" "arimelody-web/admin/templates" "arimelody-web/controller" "arimelody-web/model" "fmt" "net/http" "os" "slices" ) func Handler(app *model.AppState) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { mux := http.NewServeMux() mux.Handle("/blogs/{id}", serveBlogPost(app)) mux.Handle("/blogs/", serveBlogIndex(app)) mux.ServeHTTP(w, r) }) } type ( blogPostCollection struct { Year int Posts []*model.BlogPost } ) func (c *blogPostCollection) Clone() blogPostCollection { return blogPostCollection{ Year: c.Year, Posts: slices.Clone(c.Posts), } } func serveBlogIndex(app *model.AppState) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { session := r.Context().Value("session").(*model.Session) posts, err := controller.GetBlogPosts(app.DB, false, -1, 0) if err != nil { fmt.Fprintf(os.Stderr, "WARN: Failed to fetch blog posts: %v\n", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } collections := []*blogPostCollection{} collection := blogPostCollection{ Posts: []*model.BlogPost{}, Year: -1, } for i, post := range posts { if i == 0 { collection.Year = post.PublishDate.Year() } if post.PublishDate.Year() != collection.Year { clone := collection.Clone() collections = append(collections, &clone) collection = blogPostCollection{ Year: post.PublishDate.Year(), Posts: []*model.BlogPost{}, } } collection.Posts = append(collection.Posts, post) if i == len(posts) - 1 { collections = append(collections, &collection) } } type blogsData struct { core.AdminPageData TotalPosts int Collections []*blogPostCollection } err = templates.BlogsTemplate.Execute(w, blogsData{ AdminPageData: core.AdminPageData{ Path: r.URL.Path, Session: session, }, TotalPosts: len(posts), Collections: collections, }) if err != nil { fmt.Fprintf(os.Stderr, "WARN: Error rendering admin blog index: %v\n", err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } }) } func serveBlogPost(app *model.AppState) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { session := r.Context().Value("session").(*model.Session) blogID := r.PathValue("id") post, err := controller.GetBlogPost(app.DB, blogID) if err != nil { fmt.Fprintf(os.Stderr, "WARN: Failed to fetch blog %s: %v\n", blogID, err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } if post == nil { http.NotFound(w, r) return } type blogPostData struct { core.AdminPageData Post *model.BlogPost } err = templates.EditBlogTemplate.Execute(w, blogPostData{ AdminPageData: core.AdminPageData{ Path: r.URL.Path, Session: session, }, Post: post, }) if err != nil { fmt.Fprintf(os.Stderr, "WARN: Error rendering admin edit page for blog %s: %v\n", blogID, err) http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return } }) }