hmn/src/website/landing.go

149 lines
3.9 KiB
Go

package website
import (
"net/http"
"time"
"git.handmade.network/hmn/hmn/src/db"
"git.handmade.network/hmn/hmn/src/models"
"git.handmade.network/hmn/hmn/src/oops"
"git.handmade.network/hmn/hmn/src/templates"
"github.com/julienschmidt/httprouter"
)
type LandingTemplateData struct {
templates.BaseData
PostColumns [][]LandingPageProject
ShowcaseTimelineJson string
}
type LandingPageProject struct {
Project templates.Project
FeaturedPost *LandingPagePost
Posts []LandingPagePost
}
type LandingPagePost struct {
Post templates.Post
HasRead bool
}
func (s *websiteRoutes) Index(c *RequestContext, p httprouter.Params) {
const maxPosts = 5
const numProjectsToGet = 7
iterProjects, err := db.Query(c.Context(), s.conn, models.Project{},
"SELECT $columns FROM handmade_project WHERE flags = 0 OR id = $1",
models.HMNProjectID,
)
if err != nil {
c.Errored(http.StatusInternalServerError, oops.New(err, "failed to get projects for home page"))
return
}
defer iterProjects.Close()
var pageProjects []LandingPageProject
_ = pageProjects // TODO: NO
for _, projRow := range iterProjects.ToSlice() {
proj := projRow.(*models.Project)
type ProjectPost struct {
Post models.Post `db:"post"`
ThreadLastReadTime *time.Time `db:"tlri.lastread"`
CatLastReadTime *time.Time `db:"clri.lastread"`
}
memberId := 3 // TODO: NO
projectPostIter, err := db.Query(c.Context(), s.conn, ProjectPost{},
`
SELECT $columns
FROM
handmade_post AS post
JOIN handmade_thread AS thread ON thread.id = post.thread_id
JOIN handmade_category AS cat ON cat.id = thread.category_id
LEFT OUTER JOIN handmade_threadlastreadinfo AS tlri ON (
tlri.thread_id = thread.id
AND tlri.member_id = $1
)
LEFT OUTER JOIN handmade_categorylastreadinfo AS clri ON (
clri.category_id = cat.id
AND clri.member_id = $1
)
WHERE
cat.project_id = $2
AND cat.kind IN ($3, $4, $5, $6)
AND post.moderated = FALSE
AND post.thread_id IS NOT NULL
ORDER BY postdate DESC
LIMIT $7
`,
memberId,
proj.ID,
models.CatTypeBlog, models.CatTypeForum, models.CatTypeWiki, models.CatTypeLibraryResource,
maxPosts,
)
if err != nil {
c.Logger.Error().Err(err).Msg("failed to fetch project posts")
continue
}
projectPosts := projectPostIter.ToSlice()
landingPageProject := LandingPageProject{
Project: templates.Project{ // TODO: Use a common function to map from model to template data
Name: *proj.Name,
Subdomain: *proj.Slug,
// ...
},
}
for _, projectPostRow := range projectPosts {
projectPost := projectPostRow.(*ProjectPost)
hasRead := false
if projectPost.ThreadLastReadTime != nil && projectPost.ThreadLastReadTime.After(projectPost.Post.PostDate) {
hasRead = true
} else if projectPost.CatLastReadTime != nil && projectPost.CatLastReadTime.After(projectPost.Post.PostDate) {
hasRead = true
}
landingPageProject.Posts = append(landingPageProject.Posts, LandingPagePost{
Post: templates.Post{}, // TODO: Use a common function to map from model to template again
HasRead: hasRead,
})
}
}
type newsThreadQuery struct {
Thread models.Thread `db:"thread"`
}
newsThreadRow, err := db.QueryOne(c.Context(), s.conn, newsThreadQuery{},
`
SELECT $columns
FROM
handmade_thread as thread
JOIN handmade_category AS cat ON thread.category_id = cat.id
WHERE
cat.project_id = $1
AND cat.kind = $2
`,
models.HMNProjectID,
models.CatTypeBlog,
)
if err != nil {
c.Errored(http.StatusInternalServerError, oops.New(err, "failed to fetch latest news post"))
return
}
newsThread := newsThreadRow.(*newsThreadQuery)
_ = newsThread // TODO: NO
baseData := s.getBaseData(c)
baseData.BodyClasses = append(baseData.BodyClasses, "hmdev", "landing") // TODO: Is "hmdev" necessary any more?
err = c.WriteTemplate("index.html", s.getBaseData(c))
if err != nil {
panic(err)
}
}