package handlers import ( "fmt" "strconv" "github.com/gofiber/fiber/v3" "lmika.dev/lmika/weiro/models" "lmika.dev/lmika/weiro/providers/db" "lmika.dev/lmika/weiro/services/categories" "lmika.dev/lmika/weiro/services/posts" ) type PostsHandler struct { PostService *posts.Service CategoryService *categories.Service } func (ph PostsHandler) Index(c fiber.Ctx) error { var req struct { Filter string `query:"filter"` Page int `query:"page"` } if err := c.Bind().Query(&req); err != nil { return fiber.ErrBadRequest } const perPage = 25 if req.Page < 1 { req.Page = 1 } result, err := ph.PostService.ListPosts(c.Context(), req.Filter == "deleted", db.PagingParams{ Offset: int64((req.Page - 1) * perPage), Limit: perPage, }) if err != nil { return err } totalPages := int(result.TotalCount+int64(perPage)-1) / perPage if totalPages < 1 { totalPages = 1 } pageInfo := models.PageInfo{ CurrentPage: req.Page, TotalPages: totalPages, PostsPerPage: perPage, } return accepts(c, json(func() any { return result.Posts }), html(func(c fiber.Ctx) error { return c.Render("posts/index", fiber.Map{ "req": req, "posts": result.Posts, "pageInfo": pageInfo, }) })) } func (ph PostsHandler) New(c fiber.Ctx) error { p := models.Post{ GUID: models.NewNanoID(), State: models.StateDraft, } cats, err := ph.CategoryService.ListCategories(c.Context()) if err != nil { return err } return c.Render("posts/edit", fiber.Map{ "post": p, "categories": cats, "selectedCategories": map[int64]bool{}, "bodyClass": "large-editor", }) } func (ph PostsHandler) Edit(c fiber.Ctx) error { postIDStr := c.Params("postID") if postIDStr == "" { return fiber.ErrBadRequest } postID, err := strconv.ParseInt(postIDStr, 10, 64) if err != nil { return fiber.ErrBadRequest } post, err := ph.PostService.GetPost(c.Context(), postID) if err != nil { return err } cats, err := ph.CategoryService.ListCategories(c.Context()) if err != nil { return err } postCats, err := ph.PostService.GetPostCategories(c.Context(), postID) if err != nil { return err } selectedCategories := make(map[int64]bool) for _, pc := range postCats { selectedCategories[pc.ID] = true } return accepts(c, json(func() any { return post }), html(func(c fiber.Ctx) error { return c.Render("posts/edit", fiber.Map{ "post": post, "categories": cats, "selectedCategories": selectedCategories, "bodyClass": "large-editor", }) })) } func (ph PostsHandler) Update(c fiber.Ctx) error { var req posts.CreatePostParams if err := c.Bind().Body(&req); err != nil { return err } post, err := ph.PostService.UpdatePost(c.Context(), req) if err != nil { return err } return accepts(c, json(func() any { // TODO: should be created if brand new return post }), html(func(c fiber.Ctx) error { return c.Redirect().To(fmt.Sprintf("/sites/%v/posts", post.SiteID)) })) } func (ph PostsHandler) Patch(c fiber.Ctx) error { postIDStr := c.Params("postID") if postIDStr == "" { return fiber.ErrBadRequest } postID, err := strconv.ParseInt(postIDStr, 10, 64) if err != nil { return fiber.ErrBadRequest } var req struct { Action string `json:"action"` } if err := c.Bind().Body(&req); err != nil { return err } switch req.Action { case "restore": if err := ph.PostService.RestorePost(c.Context(), postID); err != nil { return err } default: return fiber.ErrBadRequest } return accepts(c, json(func() any { return struct{}{} }), html(func(c fiber.Ctx) error { return c.Redirect().To(fmt.Sprintf("/sites/%v/posts", models.MustGetSite(c.Context()).ID)) })) } func (ph PostsHandler) Delete(c fiber.Ctx) error { postIDStr := c.Params("postID") if postIDStr == "" { return fiber.ErrBadRequest } postID, err := strconv.ParseInt(postIDStr, 10, 64) if err != nil { return fiber.ErrBadRequest } var req struct { Hard bool `query:"hard"` } if err := c.Bind().Query(&req); err != nil { return err } if err := ph.PostService.DeletePost(c.Context(), postID, req.Hard); err != nil { return err } return accepts(c, json(func() any { return fiber.Map{} }), html(func(c fiber.Ctx) error { return c.Redirect().To("/") })) }