Convert the feed to use the new thread and post functions.

This commit is contained in:
Asaf Gartner 2021-09-23 23:02:45 +03:00
parent 9c7acd7dbb
commit 89e58c9a24
1 changed files with 27 additions and 105 deletions

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"math" "math"
"net/http" "net/http"
"strconv"
"strings" "strings"
"time" "time"
@ -30,40 +29,19 @@ type FeedData struct {
func Feed(c *RequestContext) ResponseData { func Feed(c *RequestContext) ResponseData {
const postsPerPage = 30 const postsPerPage = 30
c.Perf.StartBlock("SQL", "Count posts") numPosts, err := CountPosts(c.Context(), c.Conn, c.CurrentUser, PostsQuery{
numPosts, err := db.QueryInt(c.Context(), c.Conn, ThreadTypes: []models.ThreadType{models.ThreadTypeForumPost, models.ThreadTypeProjectBlogPost},
` })
SELECT COUNT(*)
FROM
handmade_post AS post
WHERE
post.thread_type = ANY ($1)
AND deleted = FALSE
AND post.thread_id IS NOT NULL
`,
[]models.ThreadType{models.ThreadTypeForumPost, models.ThreadTypeProjectBlogPost},
)
c.Perf.EndBlock()
if err != nil { if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get count of feed posts")) return c.ErrorResponse(http.StatusInternalServerError, err)
} }
numPages := int(math.Ceil(float64(numPosts) / postsPerPage)) numPages := int(math.Ceil(float64(numPosts) / postsPerPage))
page := 1 page, numPages, ok := getPageInfo(c.PathParams["page"], numPosts, postsPerPage)
pageString, hasPage := c.PathParams["page"] if !ok {
if hasPage && pageString != "" { return c.Redirect(hmnurl.BuildFeed(), http.StatusSeeOther)
if pageParsed, err := strconv.Atoi(pageString); err == nil {
page = pageParsed
} else {
return c.Redirect(hmnurl.BuildFeed(), http.StatusSeeOther)
}
} }
if page < 1 || numPages < page {
return c.Redirect(hmnurl.BuildFeedWithPage(utils.IntClamp(1, page, numPages)), http.StatusSeeOther)
}
howManyPostsToSkip := (page - 1) * postsPerPage
pagination := templates.Pagination{ pagination := templates.Pagination{
Current: page, Current: page,
@ -75,17 +53,7 @@ func Feed(c *RequestContext) ResponseData {
PreviousUrl: hmnurl.BuildFeedWithPage(utils.IntClamp(1, page-1, numPages)), PreviousUrl: hmnurl.BuildFeedWithPage(utils.IntClamp(1, page-1, numPages)),
} }
var currentUserId *int posts, err := fetchAllPosts(c, (page-1)*postsPerPage, postsPerPage)
if c.CurrentUser != nil {
currentUserId = &c.CurrentUser.ID
}
c.Perf.StartBlock("SQL", "Fetch subforum tree")
subforumTree := models.GetFullSubforumTree(c.Context(), c.Conn)
lineageBuilder := models.MakeSubforumLineageBuilder(subforumTree)
c.Perf.EndBlock()
posts, err := fetchAllPosts(c, lineageBuilder, currentUserId, howManyPostsToSkip, postsPerPage)
if err != nil { if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed posts")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed posts"))
} }
@ -158,12 +126,7 @@ func AtomFeed(c *RequestContext) ResponseData {
feedData.AtomFeedUrl = hmnurl.BuildAtomFeed() feedData.AtomFeedUrl = hmnurl.BuildAtomFeed()
feedData.FeedUrl = hmnurl.BuildFeed() feedData.FeedUrl = hmnurl.BuildFeed()
c.Perf.StartBlock("SQL", "Fetch subforum tree") posts, err := fetchAllPosts(c, 0, itemsPerFeed)
subforumTree := models.GetFullSubforumTree(c.Context(), c.Conn)
lineageBuilder := models.MakeSubforumLineageBuilder(subforumTree)
c.Perf.EndBlock()
posts, err := fetchAllPosts(c, lineageBuilder, nil, 0, itemsPerFeed)
if err != nil { if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed posts")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed posts"))
} }
@ -306,78 +269,37 @@ func AtomFeed(c *RequestContext) ResponseData {
return res return res
} }
func fetchAllPosts(c *RequestContext, lineageBuilder *models.SubforumLineageBuilder, currentUserID *int, offset int, limit int) ([]templates.PostListItem, error) { func fetchAllPosts(c *RequestContext, offset int, limit int) ([]templates.PostListItem, error) {
c.Perf.StartBlock("SQL", "Fetch posts") postsAndStuff, err := FetchPosts(c.Context(), c.Conn, c.CurrentUser, PostsQuery{
type feedPostQuery struct { ThreadTypes: []models.ThreadType{models.ThreadTypeForumPost, models.ThreadTypeProjectBlogPost},
Post models.Post `db:"post"` Limit: limit,
PostVersion models.PostVersion `db:"version"` Offset: offset,
Thread models.Thread `db:"thread"` SortDescending: true,
Proj models.Project `db:"proj"` })
User models.User `db:"auth_user"`
ThreadLastReadTime *time.Time `db:"tlri.lastread"`
SubforumLastReadTime *time.Time `db:"slri.lastread"`
}
posts, err := db.Query(c.Context(), c.Conn, feedPostQuery{},
`
SELECT $columns
FROM
handmade_post AS post
JOIN handmade_postversion AS version ON version.id = post.current_id
JOIN handmade_thread AS thread ON thread.id = post.thread_id
JOIN handmade_project AS proj ON proj.id = post.project_id
LEFT JOIN handmade_threadlastreadinfo AS tlri ON (
tlri.thread_id = post.thread_id
AND tlri.user_id = $1
)
LEFT JOIN handmade_subforumlastreadinfo AS slri ON (
slri.subforum_id = thread.subforum_id
AND slri.user_id = $1
)
LEFT JOIN auth_user ON post.author_id = auth_user.id
WHERE
thread.type = ANY ($2)
AND post.deleted = FALSE
AND post.thread_id IS NOT NULL
ORDER BY postdate DESC
LIMIT $3 OFFSET $4
`,
currentUserID,
[]models.ThreadType{models.ThreadTypeForumPost, models.ThreadTypeProjectBlogPost},
limit,
offset,
)
c.Perf.EndBlock()
if err != nil { if err != nil {
return nil, err return nil, err
} }
c.Perf.StartBlock("SQL", "Fetch subforum tree")
subforumTree := models.GetFullSubforumTree(c.Context(), c.Conn)
lineageBuilder := models.MakeSubforumLineageBuilder(subforumTree)
c.Perf.EndBlock()
c.Perf.StartBlock("FEED", "Build post items") c.Perf.StartBlock("FEED", "Build post items")
var postItems []templates.PostListItem var postItems []templates.PostListItem
for _, iPostResult := range posts.ToSlice() { for _, postAndStuff := range postsAndStuff {
postResult := iPostResult.(*feedPostQuery)
hasRead := false
if c.CurrentUser != nil && c.CurrentUser.MarkedAllReadAt.After(postResult.Post.PostDate) {
hasRead = true
} else if postResult.ThreadLastReadTime != nil && postResult.ThreadLastReadTime.After(postResult.Post.PostDate) {
hasRead = true
} else if postResult.SubforumLastReadTime != nil && postResult.SubforumLastReadTime.After(postResult.Post.PostDate) {
hasRead = true
}
postItem := MakePostListItem( postItem := MakePostListItem(
lineageBuilder, lineageBuilder,
&postResult.Proj, &postAndStuff.Project,
&postResult.Thread, &postAndStuff.Thread,
&postResult.Post, &postAndStuff.Post,
&postResult.User, postAndStuff.Author,
!hasRead, postAndStuff.ThreadUnread,
true, true,
c.Theme, c.Theme,
) )
postItem.UUID = uuid.NewSHA1(uuid.NameSpaceURL, []byte(postItem.Url)).URN() postItem.UUID = uuid.NewSHA1(uuid.NameSpaceURL, []byte(postItem.Url)).URN()
postItem.LastEditDate = postResult.PostVersion.Date postItem.LastEditDate = postAndStuff.CurrentVersion.Date
postItems = append(postItems, postItem) postItems = append(postItems, postItem)
} }