Show project snippets on project pages

we need better filter UI, but do we really, though
This commit is contained in:
Ben Visness 2021-11-11 12:00:36 -08:00
parent 39d11b549a
commit df2942e84b
3 changed files with 79 additions and 27 deletions

View File

@ -18,16 +18,18 @@ func JamIndex(c *RequestContext) ResponseData {
daysUntil = 0 daysUntil = 0
} }
var tagIds []int tagId := -1
jamTag, err := FetchTag(c.Context(), c.Conn, "wheeljam") jamTag, err := FetchTag(c.Context(), c.Conn, TagQuery{
Text: []string{"wheeljam"},
})
if err == nil { if err == nil {
tagIds = []int{jamTag.ID} tagId = jamTag.ID
} else { } else {
c.Logger.Warn().Err(err).Msg("failed to fetch jam tag; will fetch all snippets as a result") c.Logger.Warn().Err(err).Msg("failed to fetch jam tag; will fetch all snippets as a result")
} }
snippets, err := FetchSnippets(c.Context(), c.Conn, c.CurrentUser, SnippetQuery{ snippets, err := FetchSnippets(c.Context(), c.Conn, c.CurrentUser, SnippetQuery{
Tags: tagIds, Tags: []int{tagId},
}) })
if err != nil { if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch jam snippets")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch jam snippets"))

View File

@ -5,6 +5,7 @@ import (
"math" "math"
"math/rand" "math/rand"
"net/http" "net/http"
"sort"
"time" "time"
"git.handmade.network/hmn/hmn/src/db" "git.handmade.network/hmn/hmn/src/db"
@ -241,25 +242,25 @@ func ProjectHomepage(c *RequestContext) ResponseData {
} }
c.Perf.EndBlock() c.Perf.EndBlock()
var projectHomepageData ProjectHomepageData var templateData ProjectHomepageData
projectHomepageData.BaseData = getBaseData(c, c.CurrentProject.Name, nil) templateData.BaseData = getBaseData(c, c.CurrentProject.Name, nil)
//if canEdit { //if canEdit {
// // TODO: Move to project-specific navigation // // TODO: Move to project-specific navigation
// // projectHomepageData.BaseData.Header.EditURL = hmnurl.BuildProjectEdit(project.Slug, "") // // templateData.BaseData.Header.EditURL = hmnurl.BuildProjectEdit(project.Slug, "")
//} //}
projectHomepageData.BaseData.OpenGraphItems = append(projectHomepageData.BaseData.OpenGraphItems, templates.OpenGraphItem{ templateData.BaseData.OpenGraphItems = append(templateData.BaseData.OpenGraphItems, templates.OpenGraphItem{
Property: "og:description", Property: "og:description",
Value: c.CurrentProject.Blurb, Value: c.CurrentProject.Blurb,
}) })
projectHomepageData.Project = templates.ProjectToTemplate(c.CurrentProject, c.UrlContext.BuildHomepage(), c.Theme) templateData.Project = templates.ProjectToTemplate(c.CurrentProject, c.UrlContext.BuildHomepage(), c.Theme)
for _, owner := range owners { for _, owner := range owners {
projectHomepageData.Owners = append(projectHomepageData.Owners, templates.UserToTemplate(owner, c.Theme)) templateData.Owners = append(templateData.Owners, templates.UserToTemplate(owner, c.Theme))
} }
if c.CurrentProject.Hidden { if c.CurrentProject.Hidden {
projectHomepageData.BaseData.AddImmediateNotice( templateData.BaseData.AddImmediateNotice(
"hidden", "hidden",
"NOTICE: This project is hidden. It is currently visible only to owners and site admins.", "NOTICE: This project is hidden. It is currently visible only to owners and site admins.",
) )
@ -268,7 +269,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
if c.CurrentProject.Lifecycle != models.ProjectLifecycleActive { if c.CurrentProject.Lifecycle != models.ProjectLifecycleActive {
switch c.CurrentProject.Lifecycle { switch c.CurrentProject.Lifecycle {
case models.ProjectLifecycleUnapproved: case models.ProjectLifecycleUnapproved:
projectHomepageData.BaseData.AddImmediateNotice( templateData.BaseData.AddImmediateNotice(
"unapproved", "unapproved",
fmt.Sprintf( fmt.Sprintf(
"NOTICE: This project has not yet been submitted for approval. It is only visible to owners. Please <a href=\"%s\">submit it for approval</a> when the project content is ready for review.", "NOTICE: This project has not yet been submitted for approval. It is only visible to owners. Please <a href=\"%s\">submit it for approval</a> when the project content is ready for review.",
@ -276,27 +277,27 @@ func ProjectHomepage(c *RequestContext) ResponseData {
), ),
) )
case models.ProjectLifecycleApprovalRequired: case models.ProjectLifecycleApprovalRequired:
projectHomepageData.BaseData.AddImmediateNotice( templateData.BaseData.AddImmediateNotice(
"unapproved", "unapproved",
"NOTICE: This project is awaiting approval. It is only visible to owners and site admins.", "NOTICE: This project is awaiting approval. It is only visible to owners and site admins.",
) )
case models.ProjectLifecycleHiatus: case models.ProjectLifecycleHiatus:
projectHomepageData.BaseData.AddImmediateNotice( templateData.BaseData.AddImmediateNotice(
"hiatus", "hiatus",
"NOTICE: This project is on hiatus and may not update for a while.", "NOTICE: This project is on hiatus and may not update for a while.",
) )
case models.ProjectLifecycleDead: case models.ProjectLifecycleDead:
projectHomepageData.BaseData.AddImmediateNotice( templateData.BaseData.AddImmediateNotice(
"dead", "dead",
"NOTICE: Site staff have marked this project as being dead. If you intend to revive it, please contact a member of the Handmade Network staff.", "NOTICE: Site staff have marked this project as being dead. If you intend to revive it, please contact a member of the Handmade Network staff.",
) )
case models.ProjectLifecycleLTSRequired: case models.ProjectLifecycleLTSRequired:
projectHomepageData.BaseData.AddImmediateNotice( templateData.BaseData.AddImmediateNotice(
"lts-reqd", "lts-reqd",
"NOTICE: This project is awaiting approval for maintenance-mode status.", "NOTICE: This project is awaiting approval for maintenance-mode status.",
) )
case models.ProjectLifecycleLTS: case models.ProjectLifecycleLTS:
projectHomepageData.BaseData.AddImmediateNotice( templateData.BaseData.AddImmediateNotice(
"lts", "lts",
"NOTICE: This project has reached a state of completion.", "NOTICE: This project has reached a state of completion.",
) )
@ -304,15 +305,15 @@ func ProjectHomepage(c *RequestContext) ResponseData {
} }
for _, screenshot := range screenshotQueryResult.ToSlice() { for _, screenshot := range screenshotQueryResult.ToSlice() {
projectHomepageData.Screenshots = append(projectHomepageData.Screenshots, hmnurl.BuildUserFile(screenshot.(*screenshotQuery).Filename)) templateData.Screenshots = append(templateData.Screenshots, hmnurl.BuildUserFile(screenshot.(*screenshotQuery).Filename))
} }
for _, link := range projectLinkResult.ToSlice() { for _, link := range projectLinkResult.ToSlice() {
projectHomepageData.ProjectLinks = append(projectHomepageData.ProjectLinks, templates.LinkToTemplate(&link.(*projectLinkQuery).Link)) templateData.ProjectLinks = append(templateData.ProjectLinks, templates.LinkToTemplate(&link.(*projectLinkQuery).Link))
} }
for _, post := range postQueryResult.ToSlice() { for _, post := range postQueryResult.ToSlice() {
projectHomepageData.RecentActivity = append(projectHomepageData.RecentActivity, PostToTimelineItem( templateData.RecentActivity = append(templateData.RecentActivity, PostToTimelineItem(
c.UrlContext, c.UrlContext,
lineageBuilder, lineageBuilder,
&post.(*postQuery).Post, &post.(*postQuery).Post,
@ -322,8 +323,38 @@ func ProjectHomepage(c *RequestContext) ResponseData {
)) ))
} }
tagId := -1
if c.CurrentProject.TagID != nil {
tagId = *c.CurrentProject.TagID
}
snippets, err := FetchSnippets(c.Context(), c.Conn, c.CurrentUser, SnippetQuery{
Tags: []int{tagId},
})
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch project snippets"))
}
for _, s := range snippets {
item := SnippetToTimelineItem(
&s.Snippet,
s.Asset,
s.DiscordMessage,
s.Tags,
s.Owner,
c.Theme,
)
item.SmallInfo = true
templateData.RecentActivity = append(templateData.RecentActivity, item)
}
c.Perf.StartBlock("PROFILE", "Sort timeline")
sort.Slice(templateData.RecentActivity, func(i, j int) bool {
return templateData.RecentActivity[j].Date.Before(templateData.RecentActivity[i].Date)
})
c.Perf.EndBlock()
var res ResponseData var res ResponseData
err = res.WriteTemplate("project_homepage.html", projectHomepageData, c.Perf) err = res.WriteTemplate("project_homepage.html", templateData, c.Perf)
if err != nil { if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render project homepage template")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render project homepage template"))
} }

View File

@ -153,19 +153,38 @@ func FetchSnippet(
return res[0], nil return res[0], nil
} }
func FetchTags(ctx context.Context, dbConn db.ConnOrTx, text []string) ([]*models.Tag, error) { type TagQuery struct {
IDs []int
Text []string
Limit, Offset int
}
func FetchTags(ctx context.Context, dbConn db.ConnOrTx, q TagQuery) ([]*models.Tag, error) {
perf := ExtractPerf(ctx) perf := ExtractPerf(ctx)
perf.StartBlock("SQL", "Fetch snippets") perf.StartBlock("SQL", "Fetch snippets")
defer perf.EndBlock() defer perf.EndBlock()
it, err := db.Query(ctx, dbConn, models.Tag{}, var qb db.QueryBuilder
qb.Add(
` `
SELECT $columns SELECT $columns
FROM tags FROM tags
WHERE text = ANY ($1) WHERE
TRUE
`, `,
text,
) )
if len(q.IDs) > 0 {
qb.Add(`AND id = ANY ($?)`, q.IDs)
}
if len(q.Text) > 0 {
qb.Add(`AND text = ANY ($?)`, q.Text)
}
if q.Limit > 0 {
qb.Add(`LIMIT $? OFFSET $?`, q.Limit, q.Offset)
}
it, err := db.Query(ctx, dbConn, models.Tag{}, qb.String(), qb.Args()...)
if err != nil { if err != nil {
return nil, oops.New(err, "failed to fetch tags") return nil, oops.New(err, "failed to fetch tags")
} }
@ -180,8 +199,8 @@ func FetchTags(ctx context.Context, dbConn db.ConnOrTx, text []string) ([]*model
return res, nil return res, nil
} }
func FetchTag(ctx context.Context, dbConn db.ConnOrTx, text string) (*models.Tag, error) { func FetchTag(ctx context.Context, dbConn db.ConnOrTx, q TagQuery) (*models.Tag, error) {
tags, err := FetchTags(ctx, dbConn, []string{text}) tags, err := FetchTags(ctx, dbConn, q)
if err != nil { if err != nil {
return nil, err return nil, err
} }