package postctl import ( "bytes" "fmt" "html/template" "math" "net/http" "strconv" "github.com/kirsle/blog/internal/log" "github.com/kirsle/blog/internal/render" "github.com/kirsle/blog/internal/types" "github.com/kirsle/blog/models/comments" "github.com/kirsle/blog/models/posts" "github.com/kirsle/blog/models/users" ) // partialIndex renders and returns the blog index partial. func partialIndex(r *http.Request, tag, privacy string) template.HTML { // Get the recent blog entries, filtered by the tag/privacy settings. pool := RecentPosts(r, tag, privacy) if len(pool) == 0 { return template.HTML("No blog posts were found.") } // Query parameters. page, _ := strconv.Atoi(r.URL.Query().Get("page")) if page <= 0 { page = 1 } perPage := 10 // TODO: configurable offset := (page - 1) * perPage stop := offset + perPage // Calculate page total. var pages = math.Ceil(float64(len(pool)) / float64(perPage)) if pages == 0 { pages = 1 } // Handle pagination. var previousPage, nextPage int if page > 1 { previousPage = page - 1 } else { previousPage = 0 } if offset+perPage < len(pool) { nextPage = page + 1 } else { nextPage = 0 } var view []PostMeta for i := offset; i < stop; i++ { if i >= len(pool) { break } post, err := posts.Load(pool[i].ID) if err != nil { log.Error("couldn't load full post data for ID %d (found in index.json)", pool[i].ID) continue } // Look up the author's information. author, err := users.LoadReadonly(post.AuthorID) if err != nil { log.Error("Failed to look up post author ID %d (post %d): %v", post.AuthorID, post.ID, err) author = users.DeletedUser() } // Count the comments on this post. var numComments int if thread, err := comments.Load(fmt.Sprintf("post-%d", post.ID)); err == nil { numComments = len(thread.Comments) } view = append(view, PostMeta{ Post: post, Author: author, NumComments: numComments, }) } // Render the blog index partial. var output bytes.Buffer v := map[string]interface{}{ "PreviousPage": previousPage, "NextPage": nextPage, "Page": page, "Pages": pages, "View": view, } render.Template(&output, r, "blog/index.partial", v) return template.HTML(output.String()) } // indexHandler renders the main index page of the blog. func indexHandler(w http.ResponseWriter, r *http.Request) { commonIndexHandler(w, r, "", "") } // drafts renders an index view of only draft posts. Login required. func drafts(w http.ResponseWriter, r *http.Request) { commonIndexHandler(w, r, "", types.DRAFT) } // privatePosts renders an index view of only private posts. Login required. func privatePosts(w http.ResponseWriter, r *http.Request) { commonIndexHandler(w, r, "", types.PRIVATE) } // commonIndexHandler handles common logic for blog index views. func commonIndexHandler(w http.ResponseWriter, r *http.Request, tag, privacy string) { // Page title. var title string if privacy == types.DRAFT { title = "Draft Posts" } else if privacy == types.PRIVATE { title = "Private Posts" } else if tag != "" { title = "Tagged as: " + tag } else { title = "Blog" } render.Template(w, r, "blog/index", map[string]interface{}{ "Title": title, "Tag": tag, "Privacy": privacy, }) }