2021-03-31 03:55:19 +00:00
|
|
|
package website
|
|
|
|
|
|
|
|
import (
|
2021-04-24 04:27:45 +00:00
|
|
|
"html/template"
|
2021-10-24 20:48:28 +00:00
|
|
|
"math"
|
2021-03-31 03:55:19 +00:00
|
|
|
"net/http"
|
|
|
|
|
2021-12-09 02:04:15 +00:00
|
|
|
"git.handmade.network/hmn/hmn/src/hmndata"
|
2021-05-11 22:53:23 +00:00
|
|
|
"git.handmade.network/hmn/hmn/src/hmnurl"
|
2021-03-31 03:55:19 +00:00
|
|
|
"git.handmade.network/hmn/hmn/src/models"
|
|
|
|
"git.handmade.network/hmn/hmn/src/oops"
|
|
|
|
"git.handmade.network/hmn/hmn/src/templates"
|
2021-10-24 20:48:28 +00:00
|
|
|
"git.handmade.network/hmn/hmn/src/utils"
|
2021-03-31 03:55:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type LandingTemplateData struct {
|
|
|
|
templates.BaseData
|
|
|
|
|
2021-10-24 20:48:28 +00:00
|
|
|
NewsPost *templates.TimelineItem
|
|
|
|
TimelineItems []templates.TimelineItem
|
|
|
|
Pagination templates.Pagination
|
2021-03-31 03:55:19 +00:00
|
|
|
ShowcaseTimelineJson string
|
2021-05-11 22:53:23 +00:00
|
|
|
|
2021-10-26 04:42:55 +00:00
|
|
|
ManifestoUrl string
|
2021-10-24 20:48:28 +00:00
|
|
|
FeedUrl string
|
|
|
|
PodcastUrl string
|
|
|
|
StreamsUrl string
|
|
|
|
ShowcaseUrl string
|
|
|
|
AtomFeedUrl string
|
|
|
|
MarkAllReadUrl string
|
2021-08-28 11:26:17 +00:00
|
|
|
|
2022-08-07 01:21:12 +00:00
|
|
|
JamUrl string
|
|
|
|
JamDaysUntilStart, JamDaysUntilEnd int
|
2021-03-31 03:55:19 +00:00
|
|
|
}
|
|
|
|
|
2021-04-06 05:06:19 +00:00
|
|
|
func Index(c *RequestContext) ResponseData {
|
2021-07-30 03:40:47 +00:00
|
|
|
c.Perf.StartBlock("SQL", "Fetch subforum tree")
|
2022-06-24 21:38:11 +00:00
|
|
|
subforumTree := models.GetFullSubforumTree(c, c.Conn)
|
2021-07-30 03:40:47 +00:00
|
|
|
lineageBuilder := models.MakeSubforumLineageBuilder(subforumTree)
|
2021-05-11 22:53:23 +00:00
|
|
|
c.Perf.EndBlock()
|
2021-04-28 03:29:13 +00:00
|
|
|
|
2021-10-24 20:48:28 +00:00
|
|
|
var timelineItems []templates.TimelineItem
|
2021-04-22 23:02:50 +00:00
|
|
|
|
2022-06-24 21:38:11 +00:00
|
|
|
numPosts, err := hmndata.CountPosts(c, c.Conn, c.CurrentUser, hmndata.PostsQuery{
|
2021-10-24 20:48:28 +00:00
|
|
|
ThreadTypes: feedThreadTypes,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return c.ErrorResponse(http.StatusInternalServerError, err)
|
2021-03-31 03:55:19 +00:00
|
|
|
}
|
|
|
|
|
2021-10-24 20:48:28 +00:00
|
|
|
numPages := int(math.Ceil(float64(numPosts) / feedPostsPerPage))
|
2021-04-23 04:07:44 +00:00
|
|
|
|
2021-10-24 20:48:28 +00:00
|
|
|
page, numPages, ok := getPageInfo("1", numPosts, feedPostsPerPage)
|
|
|
|
if !ok {
|
|
|
|
return c.Redirect(hmnurl.BuildFeed(), http.StatusSeeOther)
|
|
|
|
}
|
2021-04-23 04:07:44 +00:00
|
|
|
|
2021-10-24 20:48:28 +00:00
|
|
|
pagination := templates.Pagination{
|
|
|
|
Current: page,
|
|
|
|
Total: numPages,
|
2021-04-23 04:07:44 +00:00
|
|
|
|
2021-10-24 20:48:28 +00:00
|
|
|
FirstUrl: hmnurl.BuildFeed(),
|
|
|
|
LastUrl: hmnurl.BuildFeedWithPage(numPages),
|
|
|
|
NextUrl: hmnurl.BuildFeedWithPage(utils.IntClamp(1, page+1, numPages)),
|
|
|
|
PreviousUrl: hmnurl.BuildFeedWithPage(utils.IntClamp(1, page-1, numPages)),
|
|
|
|
}
|
2021-04-23 04:07:44 +00:00
|
|
|
|
2021-10-24 20:48:28 +00:00
|
|
|
// This is essentially an alternate for feed page 1.
|
2022-06-24 21:38:11 +00:00
|
|
|
posts, err := hmndata.FetchPosts(c, c.Conn, c.CurrentUser, hmndata.PostsQuery{
|
2021-10-24 20:48:28 +00:00
|
|
|
ThreadTypes: feedThreadTypes,
|
|
|
|
Limit: feedPostsPerPage,
|
|
|
|
SortDescending: true,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
c.Logger.Warn().Err(err).Msg("failed to fetch latest posts")
|
|
|
|
}
|
|
|
|
for _, p := range posts {
|
2021-12-09 02:04:15 +00:00
|
|
|
item := PostToTimelineItem(hmndata.UrlContextForProject(&p.Project), lineageBuilder, &p.Post, &p.Thread, p.Author, c.Theme)
|
2021-10-24 20:48:28 +00:00
|
|
|
if p.Thread.Type == models.ThreadTypeProjectBlogPost && p.Post.ID == p.Thread.FirstID {
|
|
|
|
// blog post
|
|
|
|
item.Description = template.HTML(p.CurrentVersion.TextParsed)
|
|
|
|
item.TruncateDescription = true
|
2021-04-23 04:07:44 +00:00
|
|
|
}
|
2021-10-24 20:48:28 +00:00
|
|
|
timelineItems = append(timelineItems, item)
|
2021-04-23 04:07:44 +00:00
|
|
|
}
|
|
|
|
|
2021-05-11 22:53:23 +00:00
|
|
|
c.Perf.StartBlock("SQL", "Get news")
|
2022-06-24 21:38:11 +00:00
|
|
|
newsThreads, err := hmndata.FetchThreads(c, c.Conn, c.CurrentUser, hmndata.ThreadsQuery{
|
2021-09-14 04:13:58 +00:00
|
|
|
ProjectIDs: []int{models.HMNProjectID},
|
|
|
|
ThreadTypes: []models.ThreadType{models.ThreadTypeProjectBlogPost},
|
|
|
|
Limit: 1,
|
|
|
|
})
|
2021-04-24 04:27:45 +00:00
|
|
|
if err != nil {
|
2021-08-28 12:21:03 +00:00
|
|
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch news post"))
|
2021-04-24 04:27:45 +00:00
|
|
|
}
|
2021-10-24 20:48:28 +00:00
|
|
|
var newsPostItem *templates.TimelineItem
|
2021-09-14 04:13:58 +00:00
|
|
|
if len(newsThreads) > 0 {
|
2021-10-24 20:48:28 +00:00
|
|
|
t := newsThreads[0]
|
2021-12-09 02:04:15 +00:00
|
|
|
item := PostToTimelineItem(hmndata.UrlContextForProject(&t.Project), lineageBuilder, &t.FirstPost, &t.Thread, t.FirstPostAuthor, c.Theme)
|
2021-10-25 14:07:14 +00:00
|
|
|
item.OwnerAvatarUrl = ""
|
|
|
|
item.Breadcrumbs = nil
|
2021-10-24 20:48:28 +00:00
|
|
|
item.TypeTitle = ""
|
2021-10-25 14:07:14 +00:00
|
|
|
item.AllowTitleWrap = true
|
2021-10-24 20:48:28 +00:00
|
|
|
item.Description = template.HTML(t.FirstPostCurrentVersion.TextParsed)
|
|
|
|
item.TruncateDescription = true
|
|
|
|
newsPostItem = &item
|
2021-09-14 04:13:58 +00:00
|
|
|
}
|
2021-05-11 22:53:23 +00:00
|
|
|
c.Perf.EndBlock()
|
2021-04-24 04:27:45 +00:00
|
|
|
|
2022-06-24 21:38:11 +00:00
|
|
|
snippets, err := hmndata.FetchSnippets(c, c.Conn, c.CurrentUser, hmndata.SnippetQuery{
|
2021-11-11 19:00:46 +00:00
|
|
|
Limit: 40,
|
|
|
|
})
|
2021-06-23 19:31:59 +00:00
|
|
|
if err != nil {
|
2021-08-28 12:21:03 +00:00
|
|
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets"))
|
2021-06-23 19:31:59 +00:00
|
|
|
}
|
2021-11-11 19:00:46 +00:00
|
|
|
showcaseItems := make([]templates.TimelineItem, 0, len(snippets))
|
|
|
|
for _, s := range snippets {
|
2022-08-05 04:03:45 +00:00
|
|
|
timelineItem := SnippetToTimelineItem(&s.Snippet, s.Asset, s.DiscordMessage, s.Projects, s.Owner, c.Theme, false)
|
2021-10-23 22:28:06 +00:00
|
|
|
if timelineItem.CanShowcase {
|
2021-06-23 19:31:59 +00:00
|
|
|
showcaseItems = append(showcaseItems, timelineItem)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
c.Perf.EndBlock()
|
|
|
|
|
|
|
|
c.Perf.StartBlock("SHOWCASE", "Convert to json")
|
|
|
|
showcaseJson := templates.TimelineItemsToJSON(showcaseItems)
|
|
|
|
c.Perf.EndBlock()
|
|
|
|
|
2021-09-01 18:25:09 +00:00
|
|
|
baseData := getBaseData(c, "", nil)
|
2021-03-31 03:55:19 +00:00
|
|
|
baseData.BodyClasses = append(baseData.BodyClasses, "hmdev", "landing") // TODO: Is "hmdev" necessary any more?
|
2021-09-09 02:51:43 +00:00
|
|
|
baseData.OpenGraphItems = append(baseData.OpenGraphItems, templates.OpenGraphItem{
|
|
|
|
Property: "og:description",
|
2021-09-09 03:00:28 +00:00
|
|
|
Value: "A community of programmers committed to producing quality software through deeper understanding.",
|
2021-09-09 02:51:43 +00:00
|
|
|
})
|
2021-03-31 03:55:19 +00:00
|
|
|
|
2021-04-06 03:30:11 +00:00
|
|
|
var res ResponseData
|
2021-04-28 03:29:13 +00:00
|
|
|
err = res.WriteTemplate("landing.html", LandingTemplateData{
|
2021-10-24 20:48:28 +00:00
|
|
|
BaseData: baseData,
|
|
|
|
|
|
|
|
NewsPost: newsPostItem,
|
|
|
|
TimelineItems: timelineItems,
|
|
|
|
Pagination: pagination,
|
2021-06-23 19:31:59 +00:00
|
|
|
ShowcaseTimelineJson: showcaseJson,
|
2021-08-28 11:26:17 +00:00
|
|
|
|
2021-10-26 04:42:55 +00:00
|
|
|
ManifestoUrl: hmnurl.BuildManifesto(),
|
2021-10-24 20:48:28 +00:00
|
|
|
FeedUrl: hmnurl.BuildFeed(),
|
2021-10-27 00:45:11 +00:00
|
|
|
PodcastUrl: hmnurl.BuildPodcast(),
|
2021-10-24 20:48:28 +00:00
|
|
|
StreamsUrl: hmnurl.BuildStreams(),
|
|
|
|
ShowcaseUrl: hmnurl.BuildShowcase(),
|
|
|
|
AtomFeedUrl: hmnurl.BuildAtomFeed(),
|
2021-11-10 04:11:39 +00:00
|
|
|
MarkAllReadUrl: hmnurl.HMNProjectContext.BuildForumMarkRead(0),
|
2021-10-24 20:48:28 +00:00
|
|
|
|
2022-08-07 01:21:12 +00:00
|
|
|
JamUrl: hmnurl.BuildJamIndex(),
|
|
|
|
JamDaysUntilStart: daysUntil(hmndata.WRJ2022.StartTime),
|
|
|
|
JamDaysUntilEnd: daysUntil(hmndata.WRJ2022.EndTime),
|
2021-04-26 06:56:49 +00:00
|
|
|
}, c.Perf)
|
2021-03-31 03:55:19 +00:00
|
|
|
if err != nil {
|
2021-08-28 12:21:03 +00:00
|
|
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render landing page template"))
|
2021-03-31 03:55:19 +00:00
|
|
|
}
|
2021-04-06 03:30:11 +00:00
|
|
|
|
|
|
|
return res
|
2021-03-31 03:55:19 +00:00
|
|
|
}
|