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
}
var tagIds []int
jamTag, err := FetchTag(c.Context(), c.Conn, "wheeljam")
tagId := -1
jamTag, err := FetchTag(c.Context(), c.Conn, TagQuery{
Text: []string{"wheeljam"},
})
if err == nil {
tagIds = []int{jamTag.ID}
tagId = jamTag.ID
} else {
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{
Tags: tagIds,
Tags: []int{tagId},
})
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch jam snippets"))

View File

@ -5,6 +5,7 @@ import (
"math"
"math/rand"
"net/http"
"sort"
"time"
"git.handmade.network/hmn/hmn/src/db"
@ -241,25 +242,25 @@ func ProjectHomepage(c *RequestContext) ResponseData {
}
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 {
// // 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",
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 {
projectHomepageData.Owners = append(projectHomepageData.Owners, templates.UserToTemplate(owner, c.Theme))
templateData.Owners = append(templateData.Owners, templates.UserToTemplate(owner, c.Theme))
}
if c.CurrentProject.Hidden {
projectHomepageData.BaseData.AddImmediateNotice(
templateData.BaseData.AddImmediateNotice(
"hidden",
"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 {
switch c.CurrentProject.Lifecycle {
case models.ProjectLifecycleUnapproved:
projectHomepageData.BaseData.AddImmediateNotice(
templateData.BaseData.AddImmediateNotice(
"unapproved",
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.",
@ -276,27 +277,27 @@ func ProjectHomepage(c *RequestContext) ResponseData {
),
)
case models.ProjectLifecycleApprovalRequired:
projectHomepageData.BaseData.AddImmediateNotice(
templateData.BaseData.AddImmediateNotice(
"unapproved",
"NOTICE: This project is awaiting approval. It is only visible to owners and site admins.",
)
case models.ProjectLifecycleHiatus:
projectHomepageData.BaseData.AddImmediateNotice(
templateData.BaseData.AddImmediateNotice(
"hiatus",
"NOTICE: This project is on hiatus and may not update for a while.",
)
case models.ProjectLifecycleDead:
projectHomepageData.BaseData.AddImmediateNotice(
templateData.BaseData.AddImmediateNotice(
"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.",
)
case models.ProjectLifecycleLTSRequired:
projectHomepageData.BaseData.AddImmediateNotice(
templateData.BaseData.AddImmediateNotice(
"lts-reqd",
"NOTICE: This project is awaiting approval for maintenance-mode status.",
)
case models.ProjectLifecycleLTS:
projectHomepageData.BaseData.AddImmediateNotice(
templateData.BaseData.AddImmediateNotice(
"lts",
"NOTICE: This project has reached a state of completion.",
)
@ -304,15 +305,15 @@ func ProjectHomepage(c *RequestContext) ResponseData {
}
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() {
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() {
projectHomepageData.RecentActivity = append(projectHomepageData.RecentActivity, PostToTimelineItem(
templateData.RecentActivity = append(templateData.RecentActivity, PostToTimelineItem(
c.UrlContext,
lineageBuilder,
&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
err = res.WriteTemplate("project_homepage.html", projectHomepageData, c.Perf)
err = res.WriteTemplate("project_homepage.html", templateData, c.Perf)
if err != nil {
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
}
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.StartBlock("SQL", "Fetch snippets")
defer perf.EndBlock()
it, err := db.Query(ctx, dbConn, models.Tag{},
var qb db.QueryBuilder
qb.Add(
`
SELECT $columns
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 {
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
}
func FetchTag(ctx context.Context, dbConn db.ConnOrTx, text string) (*models.Tag, error) {
tags, err := FetchTags(ctx, dbConn, []string{text})
func FetchTag(ctx context.Context, dbConn db.ConnOrTx, q TagQuery) (*models.Tag, error) {
tags, err := FetchTags(ctx, dbConn, q)
if err != nil {
return nil, err
}