2018-02-10 23:07:10 +00:00
|
|
|
package postctl
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"html/template"
|
2018-04-14 16:29:03 +00:00
|
|
|
"math"
|
2018-02-10 23:07:10 +00:00
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
|
2018-02-12 00:24:43 +00:00
|
|
|
"github.com/kirsle/blog/internal/log"
|
2018-04-12 01:59:30 +00:00
|
|
|
"github.com/kirsle/blog/internal/render"
|
|
|
|
"github.com/kirsle/blog/internal/types"
|
2018-02-12 00:24:43 +00:00
|
|
|
"github.com/kirsle/blog/models/comments"
|
|
|
|
"github.com/kirsle/blog/models/posts"
|
|
|
|
"github.com/kirsle/blog/models/users"
|
2018-02-10 23:07:10 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2018-04-12 01:59:30 +00:00
|
|
|
perPage := 10 // TODO: configurable
|
2018-02-10 23:07:10 +00:00
|
|
|
offset := (page - 1) * perPage
|
|
|
|
stop := offset + perPage
|
|
|
|
|
2018-04-12 01:59:30 +00:00
|
|
|
// Calculate page total.
|
2018-04-14 16:29:03 +00:00
|
|
|
var pages = math.Ceil(float64(len(pool)) / float64(perPage))
|
2018-04-12 01:59:30 +00:00
|
|
|
if pages == 0 {
|
|
|
|
pages = 1
|
|
|
|
}
|
|
|
|
|
2018-02-10 23:07:10 +00:00
|
|
|
// 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) {
|
2018-04-12 01:59:30 +00:00
|
|
|
break
|
2018-02-10 23:07:10 +00:00
|
|
|
}
|
|
|
|
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,
|
2018-04-12 01:59:30 +00:00
|
|
|
"Page": page,
|
|
|
|
"Pages": pages,
|
2018-02-10 23:07:10 +00:00
|
|
|
"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,
|
|
|
|
})
|
|
|
|
}
|