Tweak routing middleware, add socials to banner

Instead of doing project nav, which I am actively avoiding
This commit is contained in:
Ben Visness 2021-10-26 19:45:11 -05:00
parent a9d3387295
commit 5eff3c38b4
9 changed files with 165 additions and 155 deletions

View File

@ -140,30 +140,27 @@ func TestProjectEdit(t *testing.T) {
} }
func TestPodcast(t *testing.T) { func TestPodcast(t *testing.T) {
AssertRegexMatch(t, BuildPodcast(""), RegexPodcast, nil) AssertRegexMatch(t, BuildPodcast(), RegexPodcast, nil)
AssertSubdomain(t, BuildPodcast(""), "")
AssertSubdomain(t, BuildPodcast("hmn"), "")
AssertSubdomain(t, BuildPodcast("hero"), "hero")
} }
func TestPodcastEdit(t *testing.T) { func TestPodcastEdit(t *testing.T) {
AssertRegexMatch(t, BuildPodcastEdit(""), RegexPodcastEdit, nil) AssertRegexMatch(t, BuildPodcastEdit(), RegexPodcastEdit, nil)
} }
func TestPodcastEpisode(t *testing.T) { func TestPodcastEpisode(t *testing.T) {
AssertRegexMatch(t, BuildPodcastEpisode("", "test"), RegexPodcastEpisode, map[string]string{"episodeid": "test"}) AssertRegexMatch(t, BuildPodcastEpisode("test"), RegexPodcastEpisode, map[string]string{"episodeid": "test"})
} }
func TestPodcastEpisodeNew(t *testing.T) { func TestPodcastEpisodeNew(t *testing.T) {
AssertRegexMatch(t, BuildPodcastEpisodeNew(""), RegexPodcastEpisodeNew, nil) AssertRegexMatch(t, BuildPodcastEpisodeNew(), RegexPodcastEpisodeNew, nil)
} }
func TestPodcastEpisodeEdit(t *testing.T) { func TestPodcastEpisodeEdit(t *testing.T) {
AssertRegexMatch(t, BuildPodcastEpisodeEdit("", "test"), RegexPodcastEpisodeEdit, map[string]string{"episodeid": "test"}) AssertRegexMatch(t, BuildPodcastEpisodeEdit("test"), RegexPodcastEpisodeEdit, map[string]string{"episodeid": "test"})
} }
func TestPodcastRSS(t *testing.T) { func TestPodcastRSS(t *testing.T) {
AssertRegexMatch(t, BuildPodcastRSS(""), RegexPodcastRSS, nil) AssertRegexMatch(t, BuildPodcastRSS(), RegexPodcastRSS, nil)
} }
func TestForum(t *testing.T) { func TestForum(t *testing.T) {
@ -265,23 +262,19 @@ func TestBlogPostReply(t *testing.T) {
} }
func TestLibrary(t *testing.T) { func TestLibrary(t *testing.T) {
AssertRegexMatch(t, BuildLibrary(""), RegexLibrary, nil) AssertRegexMatch(t, BuildLibrary(), RegexLibrary, nil)
AssertSubdomain(t, BuildLibrary("hero"), "hero")
} }
func TestLibraryAll(t *testing.T) { func TestLibraryAll(t *testing.T) {
AssertRegexMatch(t, BuildLibraryAll(""), RegexLibraryAll, nil) AssertRegexMatch(t, BuildLibraryAll(), RegexLibraryAll, nil)
AssertSubdomain(t, BuildLibraryAll("hero"), "hero")
} }
func TestLibraryTopic(t *testing.T) { func TestLibraryTopic(t *testing.T) {
AssertRegexMatch(t, BuildLibraryTopic("", 1), RegexLibraryTopic, map[string]string{"topicid": "1"}) AssertRegexMatch(t, BuildLibraryTopic(1), RegexLibraryTopic, map[string]string{"topicid": "1"})
AssertSubdomain(t, BuildLibraryTopic("hero", 1), "hero")
} }
func TestLibraryResource(t *testing.T) { func TestLibraryResource(t *testing.T) {
AssertRegexMatch(t, BuildLibraryResource("", 1), RegexLibraryResource, map[string]string{"resourceid": "1"}) AssertRegexMatch(t, BuildLibraryResource(1), RegexLibraryResource, map[string]string{"resourceid": "1"})
AssertSubdomain(t, BuildLibraryResource("hero", 1), "hero")
} }
func TestEpisodeGuide(t *testing.T) { func TestEpisodeGuide(t *testing.T) {
@ -429,5 +422,5 @@ func AssertRegexNoMatch(t *testing.T, fullUrl string, regex *regexp.Regexp) {
func TestThingsThatDontNeedCoverage(t *testing.T) { func TestThingsThatDontNeedCoverage(t *testing.T) {
// look the other way ಠ_ಠ // look the other way ಠ_ಠ
BuildPodcastEpisodeFile("foo", "bar") BuildPodcastEpisodeFile("foo")
} }

View File

@ -8,6 +8,7 @@ import (
"strings" "strings"
"git.handmade.network/hmn/hmn/src/logging" "git.handmade.network/hmn/hmn/src/logging"
"git.handmade.network/hmn/hmn/src/models"
"git.handmade.network/hmn/hmn/src/oops" "git.handmade.network/hmn/hmn/src/oops"
) )
@ -316,49 +317,49 @@ func BuildProjectEdit(slug string, section string) string {
var RegexPodcast = regexp.MustCompile(`^/podcast$`) var RegexPodcast = regexp.MustCompile(`^/podcast$`)
func BuildPodcast(projectSlug string) string { func BuildPodcast() string {
defer CatchPanic() defer CatchPanic()
return ProjectUrl("/podcast", nil, projectSlug) return Url("/podcast", nil)
} }
var RegexPodcastEdit = regexp.MustCompile(`^/podcast/edit$`) var RegexPodcastEdit = regexp.MustCompile(`^/podcast/edit$`)
func BuildPodcastEdit(projectSlug string) string { func BuildPodcastEdit() string {
defer CatchPanic() defer CatchPanic()
return ProjectUrl("/podcast/edit", nil, projectSlug) return Url("/podcast/edit", nil)
} }
var RegexPodcastEpisode = regexp.MustCompile(`^/podcast/ep/(?P<episodeid>[^/]+)$`) var RegexPodcastEpisode = regexp.MustCompile(`^/podcast/ep/(?P<episodeid>[^/]+)$`)
func BuildPodcastEpisode(projectSlug string, episodeGUID string) string { func BuildPodcastEpisode(episodeGUID string) string {
defer CatchPanic() defer CatchPanic()
return ProjectUrl(fmt.Sprintf("/podcast/ep/%s", episodeGUID), nil, projectSlug) return Url(fmt.Sprintf("/podcast/ep/%s", episodeGUID), nil)
} }
var RegexPodcastEpisodeNew = regexp.MustCompile(`^/podcast/ep/new$`) var RegexPodcastEpisodeNew = regexp.MustCompile(`^/podcast/ep/new$`)
func BuildPodcastEpisodeNew(projectSlug string) string { func BuildPodcastEpisodeNew() string {
defer CatchPanic() defer CatchPanic()
return ProjectUrl("/podcast/ep/new", nil, projectSlug) return Url("/podcast/ep/new", nil)
} }
var RegexPodcastEpisodeEdit = regexp.MustCompile(`^/podcast/ep/(?P<episodeid>[^/]+)/edit$`) var RegexPodcastEpisodeEdit = regexp.MustCompile(`^/podcast/ep/(?P<episodeid>[^/]+)/edit$`)
func BuildPodcastEpisodeEdit(projectSlug string, episodeGUID string) string { func BuildPodcastEpisodeEdit(episodeGUID string) string {
defer CatchPanic() defer CatchPanic()
return ProjectUrl(fmt.Sprintf("/podcast/ep/%s/edit", episodeGUID), nil, projectSlug) return Url(fmt.Sprintf("/podcast/ep/%s/edit", episodeGUID), nil)
} }
var RegexPodcastRSS = regexp.MustCompile(`^/podcast/podcast.xml$`) var RegexPodcastRSS = regexp.MustCompile(`^/podcast/podcast.xml$`)
func BuildPodcastRSS(projectSlug string) string { func BuildPodcastRSS() string {
defer CatchPanic() defer CatchPanic()
return ProjectUrl("/podcast/podcast.xml", nil, projectSlug) return Url("/podcast/podcast.xml", nil)
} }
func BuildPodcastEpisodeFile(projectSlug string, filename string) string { func BuildPodcastEpisodeFile(filename string) string {
defer CatchPanic() defer CatchPanic()
return BuildUserFile(fmt.Sprintf("podcast/%s/%s", projectSlug, filename)) return BuildUserFile(fmt.Sprintf("podcast/%s/%s", models.HMNProjectSlug, filename))
} }
/* /*
@ -540,21 +541,21 @@ var RegexLibraryAny = regexp.MustCompile(`^/library`)
var RegexLibrary = regexp.MustCompile(`^/library$`) var RegexLibrary = regexp.MustCompile(`^/library$`)
func BuildLibrary(projectSlug string) string { func BuildLibrary() string {
defer CatchPanic() defer CatchPanic()
return ProjectUrl("/library", nil, projectSlug) return Url("/library", nil)
} }
var RegexLibraryAll = regexp.MustCompile(`^/library/all$`) var RegexLibraryAll = regexp.MustCompile(`^/library/all$`)
func BuildLibraryAll(projectSlug string) string { func BuildLibraryAll() string {
defer CatchPanic() defer CatchPanic()
return ProjectUrl("/library/all", nil, projectSlug) return Url("/library/all", nil)
} }
var RegexLibraryTopic = regexp.MustCompile(`^/library/topic/(?P<topicid>\d+)$`) var RegexLibraryTopic = regexp.MustCompile(`^/library/topic/(?P<topicid>\d+)$`)
func BuildLibraryTopic(projectSlug string, topicId int) string { func BuildLibraryTopic(topicId int) string {
defer CatchPanic() defer CatchPanic()
if topicId < 1 { if topicId < 1 {
panic(oops.New(nil, "Invalid library topic ID (%d), must be >= 1", topicId)) panic(oops.New(nil, "Invalid library topic ID (%d), must be >= 1", topicId))
@ -564,16 +565,16 @@ func BuildLibraryTopic(projectSlug string, topicId int) string {
builder.WriteString("/library/topic/") builder.WriteString("/library/topic/")
builder.WriteString(strconv.Itoa(topicId)) builder.WriteString(strconv.Itoa(topicId))
return ProjectUrl(builder.String(), nil, projectSlug) return Url(builder.String(), nil)
} }
var RegexLibraryResource = regexp.MustCompile(`^/library/resource/(?P<resourceid>\d+)$`) var RegexLibraryResource = regexp.MustCompile(`^/library/resource/(?P<resourceid>\d+)$`)
func BuildLibraryResource(projectSlug string, resourceId int) string { func BuildLibraryResource(resourceId int) string {
defer CatchPanic() defer CatchPanic()
builder := buildLibraryResourcePath(resourceId) builder := buildLibraryResourcePath(resourceId)
return ProjectUrl(builder.String(), nil, projectSlug) return Url(builder.String(), nil)
} }
/* /*

View File

@ -327,7 +327,7 @@ func TimelineItemsToJSON(items []TimelineItem) string {
return builder.String() return builder.String()
} }
func PodcastToTemplate(projectSlug string, podcast *models.Podcast, imageFilename string) Podcast { func PodcastToTemplate(podcast *models.Podcast, imageFilename string) Podcast {
imageUrl := "" imageUrl := ""
if imageFilename != "" { if imageFilename != "" {
imageUrl = hmnurl.BuildUserFile(imageFilename) imageUrl = hmnurl.BuildUserFile(imageFilename)
@ -337,9 +337,9 @@ func PodcastToTemplate(projectSlug string, podcast *models.Podcast, imageFilenam
Description: podcast.Description, Description: podcast.Description,
Language: podcast.Language, Language: podcast.Language,
ImageUrl: imageUrl, ImageUrl: imageUrl,
Url: hmnurl.BuildPodcast(projectSlug), Url: hmnurl.BuildPodcast(),
RSSUrl: hmnurl.BuildPodcastRSS(projectSlug), RSSUrl: hmnurl.BuildPodcastRSS(),
// TODO(asaf): Move this to the db if we want to support user podcasts // TODO(asaf): Move this to the db if we want to support user podcasts
AppleUrl: "https://podcasts.apple.com/us/podcast/the-handmade-network-podcast/id1507790631", AppleUrl: "https://podcasts.apple.com/us/podcast/the-handmade-network-podcast/id1507790631",
GoogleUrl: "https://www.google.com/podcasts?feed=aHR0cHM6Ly9oYW5kbWFkZS5uZXR3b3JrL3BvZGNhc3QvcG9kY2FzdC54bWw%3D", GoogleUrl: "https://www.google.com/podcasts?feed=aHR0cHM6Ly9oYW5kbWFkZS5uZXR3b3JrL3BvZGNhc3QvcG9kY2FzdC54bWw%3D",
@ -347,7 +347,7 @@ func PodcastToTemplate(projectSlug string, podcast *models.Podcast, imageFilenam
} }
} }
func PodcastEpisodeToTemplate(projectSlug string, episode *models.PodcastEpisode, audioFileSize int64, imageFilename string) PodcastEpisode { func PodcastEpisodeToTemplate(episode *models.PodcastEpisode, audioFileSize int64, imageFilename string) PodcastEpisode {
imageUrl := "" imageUrl := ""
if imageFilename != "" { if imageFilename != "" {
imageUrl = hmnurl.BuildUserFile(imageFilename) imageUrl = hmnurl.BuildUserFile(imageFilename)
@ -358,9 +358,9 @@ func PodcastEpisodeToTemplate(projectSlug string, episode *models.PodcastEpisode
Description: episode.Description, Description: episode.Description,
DescriptionHtml: template.HTML(episode.DescriptionHtml), DescriptionHtml: template.HTML(episode.DescriptionHtml),
EpisodeNumber: episode.EpisodeNumber, EpisodeNumber: episode.EpisodeNumber,
Url: hmnurl.BuildPodcastEpisode(projectSlug, episode.GUID.String()), Url: hmnurl.BuildPodcastEpisode(episode.GUID.String()),
ImageUrl: imageUrl, ImageUrl: imageUrl,
FileUrl: hmnurl.BuildPodcastEpisodeFile(projectSlug, episode.AudioFile), FileUrl: hmnurl.BuildPodcastEpisodeFile(episode.AudioFile),
FileSize: audioFileSize, FileSize: audioFileSize,
PublicationDate: episode.PublicationDate, PublicationDate: episode.PublicationDate,
Duration: episode.Duration, Duration: episode.Duration,

View File

@ -25,7 +25,7 @@
</div> </div>
{{ end }} {{ end }}
</div> </div>
<div class="menu-bar flex flex-column flex-row-l justify-between {{ if .IsProjectPage }}project{{ end }}"> <div class="menu-bar flex flex-column flex-row-ns justify-between {{ if .IsProjectPage }}project{{ end }}">
<div class="flex flex-column flex-row-ns"> <div class="flex flex-column flex-row-ns">
<a href="{{ .Header.HMNHomepageUrl }}" class="hmn-logo bg-theme-dark"> <a href="{{ .Header.HMNHomepageUrl }}" class="hmn-logo bg-theme-dark">
Handmade Handmade
@ -52,6 +52,10 @@
</div> </div>
</div> </div>
</div> </div>
<div class="dn flex-ns items-center f3">
<a class="svgicon" href="https://twitter.com/handmade_net/" target="_blank">{{ svg "twitter" }}</a>
<a class="svgicon ml2" href="{{ .DiscordUrl }}" target="_blank">{{ svg "discord" }}</a>
</div>
</div> </div>
</header> </header>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1.04336,0,0,1.04336,-3.61729e-09,-1.34534)">
<path d="M26.002,6.953C24.002,6.038 21.879,5.372 19.662,5C19.383,5.48 19.073,6.131 18.856,6.643C16.499,6.302 14.159,6.302 11.834,6.643C11.617,6.131 11.291,5.48 11.028,5C8.796,5.372 6.672,6.038 4.687,6.953C0.673,12.874 -0.412,18.655 0.13,24.359C2.796,26.296 5.369,27.474 7.897,28.249C8.517,27.412 9.075,26.513 9.555,25.568C8.641,25.227 7.773,24.808 6.936,24.312C7.153,24.157 7.37,23.987 7.571,23.816C12.624,26.126 18.097,26.126 23.088,23.816C23.305,23.987 23.506,24.157 23.723,24.312C22.886,24.808 22.018,25.227 21.104,25.568C21.584,26.513 22.142,27.412 22.762,28.249C25.289,27.474 27.877,26.296 30.529,24.359C31.195,17.756 29.473,12.021 26.002,6.953ZM10.253,20.84C8.734,20.84 7.494,19.461 7.494,17.771C7.494,16.082 8.703,14.703 10.253,14.703C11.787,14.703 13.043,16.082 13.012,17.771C13.012,19.461 11.787,20.84 10.253,20.84ZM20.437,20.84C18.918,20.84 17.677,19.461 17.677,17.771C17.677,16.082 18.887,14.703 20.437,14.703C21.972,14.703 23.227,16.082 23.196,17.771C23.196,19.461 21.987,20.84 20.437,20.84Z" style="fill-rule:nonzero;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,5 @@
<!-- Generated by IcoMoon.io -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<title>twitter</title>
<path d="M32 7.075c-1.175 0.525-2.444 0.875-3.769 1.031 1.356-0.813 2.394-2.1 2.887-3.631-1.269 0.75-2.675 1.3-4.169 1.594-1.2-1.275-2.906-2.069-4.794-2.069-3.625 0-6.563 2.938-6.563 6.563 0 0.512 0.056 1.012 0.169 1.494-5.456-0.275-10.294-2.888-13.531-6.862-0.563 0.969-0.887 2.1-0.887 3.3 0 2.275 1.156 4.287 2.919 5.463-1.075-0.031-2.087-0.331-2.975-0.819 0 0.025 0 0.056 0 0.081 0 3.181 2.263 5.838 5.269 6.437-0.55 0.15-1.131 0.231-1.731 0.231-0.425 0-0.831-0.044-1.237-0.119 0.838 2.606 3.263 4.506 6.131 4.563-2.25 1.762-5.075 2.813-8.156 2.813-0.531 0-1.050-0.031-1.569-0.094 2.913 1.869 6.362 2.95 10.069 2.95 12.075 0 18.681-10.006 18.681-18.681 0-0.287-0.006-0.569-0.019-0.85 1.281-0.919 2.394-2.075 3.275-3.394z"></path>
</svg>

After

Width:  |  Height:  |  Size: 894 B

View File

@ -166,7 +166,7 @@ func Index(c *RequestContext) ResponseData {
ManifestoUrl: hmnurl.BuildManifesto(), ManifestoUrl: hmnurl.BuildManifesto(),
FeedUrl: hmnurl.BuildFeed(), FeedUrl: hmnurl.BuildFeed(),
PodcastUrl: hmnurl.BuildPodcast(models.HMNProjectSlug), PodcastUrl: hmnurl.BuildPodcast(),
StreamsUrl: hmnurl.BuildStreams(), StreamsUrl: hmnurl.BuildStreams(),
IRCUrl: hmnurl.BuildBlogThread(models.HMNProjectSlug, 1138, "[Tutorial] Handmade Network IRC"), IRCUrl: hmnurl.BuildBlogThread(models.HMNProjectSlug, 1138, "[Tutorial] Handmade Network IRC"),
DiscordUrl: "https://discord.gg/hxWxDee", DiscordUrl: "https://discord.gg/hxWxDee",

View File

@ -48,16 +48,16 @@ func PodcastIndex(c *RequestContext) ResponseData {
podcastIndexData := PodcastIndexData{ podcastIndexData := PodcastIndexData{
BaseData: baseData, BaseData: baseData,
Podcast: templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, podcastResult.ImageFile), Podcast: templates.PodcastToTemplate(podcastResult.Podcast, podcastResult.ImageFile),
} }
if canEdit { if canEdit {
podcastIndexData.EditUrl = hmnurl.BuildPodcastEdit(c.CurrentProject.Slug) podcastIndexData.EditUrl = hmnurl.BuildPodcastEdit()
podcastIndexData.NewEpisodeUrl = hmnurl.BuildPodcastEpisodeNew(c.CurrentProject.Slug) podcastIndexData.NewEpisodeUrl = hmnurl.BuildPodcastEpisodeNew()
} }
for _, episode := range podcastResult.Episodes { for _, episode := range podcastResult.Episodes {
podcastIndexData.Episodes = append(podcastIndexData.Episodes, templates.PodcastEpisodeToTemplate(c.CurrentProject.Slug, episode, 0, podcastResult.ImageFile)) podcastIndexData.Episodes = append(podcastIndexData.Episodes, templates.PodcastEpisodeToTemplate(episode, 0, podcastResult.ImageFile))
} }
var res ResponseData var res ResponseData
err = res.WriteTemplate("podcast_index.html", podcastIndexData, c.Perf) err = res.WriteTemplate("podcast_index.html", podcastIndexData, c.Perf)
@ -87,7 +87,7 @@ func PodcastEdit(c *RequestContext) ResponseData {
return FourOhFour(c) return FourOhFour(c)
} }
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, podcastResult.ImageFile) podcast := templates.PodcastToTemplate(podcastResult.Podcast, podcastResult.ImageFile)
baseData := getBaseData( baseData := getBaseData(
c, c,
fmt.Sprintf("Edit %s", podcast.Title), fmt.Sprintf("Edit %s", podcast.Title),
@ -194,7 +194,7 @@ func PodcastEditSubmit(c *RequestContext) ResponseData {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to commit db transaction")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to commit db transaction"))
} }
res := c.Redirect(hmnurl.BuildPodcastEdit(c.CurrentProject.Slug), http.StatusSeeOther) res := c.Redirect(hmnurl.BuildPodcastEdit(), http.StatusSeeOther)
res.AddFutureNotice("success", "Podcast updated successfully.") res.AddFutureNotice("success", "Podcast updated successfully.")
return res return res
} }
@ -226,11 +226,11 @@ func PodcastEpisode(c *RequestContext) ResponseData {
editUrl := "" editUrl := ""
if canEdit { if canEdit {
editUrl = hmnurl.BuildPodcastEpisodeEdit(c.CurrentProject.Slug, podcastResult.Episodes[0].GUID.String()) editUrl = hmnurl.BuildPodcastEpisodeEdit(podcastResult.Episodes[0].GUID.String())
} }
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, podcastResult.ImageFile) podcast := templates.PodcastToTemplate(podcastResult.Podcast, podcastResult.ImageFile)
episode := templates.PodcastEpisodeToTemplate(c.CurrentProject.Slug, podcastResult.Episodes[0], 0, podcastResult.ImageFile) episode := templates.PodcastEpisodeToTemplate(podcastResult.Episodes[0], 0, podcastResult.ImageFile)
baseData := getBaseData( baseData := getBaseData(
c, c,
fmt.Sprintf("%s | %s", episode.Title, podcast.Title), fmt.Sprintf("%s | %s", episode.Title, podcast.Title),
@ -282,7 +282,7 @@ func PodcastEpisodeNew(c *RequestContext) ResponseData {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to fetch podcast episode file list")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to fetch podcast episode file list"))
} }
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, "") podcast := templates.PodcastToTemplate(podcastResult.Podcast, "")
var res ResponseData var res ResponseData
baseData := getBaseData( baseData := getBaseData(
c, c,
@ -326,8 +326,8 @@ func PodcastEpisodeEdit(c *RequestContext) ResponseData {
} }
episode := podcastResult.Episodes[0] episode := podcastResult.Episodes[0]
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, "") podcast := templates.PodcastToTemplate(podcastResult.Podcast, "")
podcastEpisode := templates.PodcastEpisodeToTemplate(c.CurrentProject.Slug, episode, 0, "") podcastEpisode := templates.PodcastEpisodeToTemplate(episode, 0, "")
baseData := getBaseData( baseData := getBaseData(
c, c,
fmt.Sprintf("Edit episode %s | %s", podcastEpisode.Title, podcast.Title), fmt.Sprintf("Edit episode %s | %s", podcastEpisode.Title, podcast.Title),
@ -491,7 +491,7 @@ func PodcastEpisodeSubmit(c *RequestContext) ResponseData {
} }
} }
res := c.Redirect(hmnurl.BuildPodcastEpisodeEdit(c.CurrentProject.Slug, guidStr), http.StatusSeeOther) res := c.Redirect(hmnurl.BuildPodcastEpisodeEdit(guidStr), http.StatusSeeOther)
res.AddFutureNotice("success", "Podcast episode updated successfully.") res.AddFutureNotice("success", "Podcast episode updated successfully.")
return res return res
} }
@ -519,7 +519,7 @@ func PodcastRSS(c *RequestContext) ResponseData {
} }
podcastRSSData := PodcastRSSData{ podcastRSSData := PodcastRSSData{
Podcast: templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, podcastResult.ImageFile), Podcast: templates.PodcastToTemplate(podcastResult.Podcast, podcastResult.ImageFile),
} }
for _, episode := range podcastResult.Episodes { for _, episode := range podcastResult.Episodes {
@ -530,7 +530,7 @@ func PodcastRSS(c *RequestContext) ResponseData {
} else { } else {
filesize = stat.Size() filesize = stat.Size()
} }
podcastRSSData.Episodes = append(podcastRSSData.Episodes, templates.PodcastEpisodeToTemplate(c.CurrentProject.Slug, episode, filesize, podcastResult.ImageFile)) podcastRSSData.Episodes = append(podcastRSSData.Episodes, templates.PodcastEpisodeToTemplate(episode, filesize, podcastResult.ImageFile))
} }
var res ResponseData var res ResponseData

View File

@ -45,8 +45,8 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
}, },
} }
mainRoutes := routes anyProject := routes
mainRoutes.Middleware = func(h Handler) Handler { anyProject.Middleware = func(h Handler) Handler {
return func(c *RequestContext) (res ResponseData) { return func(c *RequestContext) (res ResponseData) {
c.Conn = conn c.Conn = conn
@ -67,8 +67,8 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
} }
} }
staticPages := routes hmnOnly := routes
staticPages.Middleware = func(h Handler) Handler { hmnOnly.Middleware = func(h Handler) Handler {
return func(c *RequestContext) (res ResponseData) { return func(c *RequestContext) (res ResponseData) {
c.Conn = conn c.Conn = conn
@ -154,125 +154,125 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
return res return res
}) })
mainRoutes.GET(hmnurl.RegexHomepage, func(c *RequestContext) ResponseData { anyProject.GET(hmnurl.RegexHomepage, func(c *RequestContext) ResponseData {
if c.CurrentProject.IsHMN() { if c.CurrentProject.IsHMN() {
return Index(c) return Index(c)
} else { } else {
return ProjectHomepage(c) return ProjectHomepage(c)
} }
}) })
staticPages.GET(hmnurl.RegexManifesto, Manifesto)
staticPages.GET(hmnurl.RegexAbout, About)
staticPages.GET(hmnurl.RegexCodeOfConduct, CodeOfConduct)
staticPages.GET(hmnurl.RegexCommunicationGuidelines, CommunicationGuidelines)
staticPages.GET(hmnurl.RegexContactPage, ContactPage)
staticPages.GET(hmnurl.RegexMonthlyUpdatePolicy, MonthlyUpdatePolicy)
staticPages.GET(hmnurl.RegexProjectSubmissionGuidelines, ProjectSubmissionGuidelines)
staticPages.GET(hmnurl.RegexWhenIsIt, WhenIsIt)
staticPages.GET(hmnurl.RegexJamIndex, JamIndex)
// TODO(asaf): Have separate middleware for HMN-only routes and any-project routes
// NOTE(asaf): HMN-only routes: // NOTE(asaf): HMN-only routes:
mainRoutes.GET(hmnurl.RegexOldHome, Index) hmnOnly.GET(hmnurl.RegexManifesto, Manifesto)
hmnOnly.GET(hmnurl.RegexAbout, About)
hmnOnly.GET(hmnurl.RegexCodeOfConduct, CodeOfConduct)
hmnOnly.GET(hmnurl.RegexCommunicationGuidelines, CommunicationGuidelines)
hmnOnly.GET(hmnurl.RegexContactPage, ContactPage)
hmnOnly.GET(hmnurl.RegexMonthlyUpdatePolicy, MonthlyUpdatePolicy)
hmnOnly.GET(hmnurl.RegexProjectSubmissionGuidelines, ProjectSubmissionGuidelines)
hmnOnly.GET(hmnurl.RegexWhenIsIt, WhenIsIt)
hmnOnly.GET(hmnurl.RegexJamIndex, JamIndex)
mainRoutes.POST(hmnurl.RegexLoginAction, securityTimerMiddleware(time.Millisecond*100, Login)) // TODO(asaf): Adjust this after launch hmnOnly.GET(hmnurl.RegexOldHome, Index)
mainRoutes.GET(hmnurl.RegexLogoutAction, Logout)
mainRoutes.GET(hmnurl.RegexLoginPage, LoginPage)
mainRoutes.GET(hmnurl.RegexRegister, RegisterNewUser) hmnOnly.POST(hmnurl.RegexLoginAction, securityTimerMiddleware(time.Millisecond*100, Login)) // TODO(asaf): Adjust this after launch
mainRoutes.POST(hmnurl.RegexRegister, securityTimerMiddleware(email.ExpectedEmailSendDuration, RegisterNewUserSubmit)) hmnOnly.GET(hmnurl.RegexLogoutAction, Logout)
mainRoutes.GET(hmnurl.RegexRegistrationSuccess, RegisterNewUserSuccess) hmnOnly.GET(hmnurl.RegexLoginPage, LoginPage)
mainRoutes.GET(hmnurl.RegexOldEmailConfirmation, EmailConfirmation) // TODO(asaf): Delete this a bit after launch
mainRoutes.GET(hmnurl.RegexEmailConfirmation, EmailConfirmation)
mainRoutes.POST(hmnurl.RegexEmailConfirmation, EmailConfirmationSubmit)
mainRoutes.GET(hmnurl.RegexRequestPasswordReset, RequestPasswordReset) hmnOnly.GET(hmnurl.RegexRegister, RegisterNewUser)
mainRoutes.POST(hmnurl.RegexRequestPasswordReset, securityTimerMiddleware(email.ExpectedEmailSendDuration, RequestPasswordResetSubmit)) hmnOnly.POST(hmnurl.RegexRegister, securityTimerMiddleware(email.ExpectedEmailSendDuration, RegisterNewUserSubmit))
mainRoutes.GET(hmnurl.RegexPasswordResetSent, PasswordResetSent) hmnOnly.GET(hmnurl.RegexRegistrationSuccess, RegisterNewUserSuccess)
mainRoutes.GET(hmnurl.RegexOldDoPasswordReset, DoPasswordReset) hmnOnly.GET(hmnurl.RegexOldEmailConfirmation, EmailConfirmation) // TODO(asaf): Delete this a bit after launch
mainRoutes.GET(hmnurl.RegexDoPasswordReset, DoPasswordReset) hmnOnly.GET(hmnurl.RegexEmailConfirmation, EmailConfirmation)
mainRoutes.POST(hmnurl.RegexDoPasswordReset, DoPasswordResetSubmit) hmnOnly.POST(hmnurl.RegexEmailConfirmation, EmailConfirmationSubmit)
mainRoutes.GET(hmnurl.RegexAdminAtomFeed, AdminAtomFeed) hmnOnly.GET(hmnurl.RegexRequestPasswordReset, RequestPasswordReset)
mainRoutes.GET(hmnurl.RegexAdminApprovalQueue, adminMiddleware(AdminApprovalQueue)) hmnOnly.POST(hmnurl.RegexRequestPasswordReset, securityTimerMiddleware(email.ExpectedEmailSendDuration, RequestPasswordResetSubmit))
mainRoutes.POST(hmnurl.RegexAdminApprovalQueue, adminMiddleware(csrfMiddleware(AdminApprovalQueueSubmit))) hmnOnly.GET(hmnurl.RegexPasswordResetSent, PasswordResetSent)
hmnOnly.GET(hmnurl.RegexOldDoPasswordReset, DoPasswordReset)
hmnOnly.GET(hmnurl.RegexDoPasswordReset, DoPasswordReset)
hmnOnly.POST(hmnurl.RegexDoPasswordReset, DoPasswordResetSubmit)
mainRoutes.GET(hmnurl.RegexFeed, Feed) hmnOnly.GET(hmnurl.RegexAdminAtomFeed, AdminAtomFeed)
mainRoutes.GET(hmnurl.RegexAtomFeed, AtomFeed) hmnOnly.GET(hmnurl.RegexAdminApprovalQueue, adminMiddleware(AdminApprovalQueue))
mainRoutes.GET(hmnurl.RegexShowcase, Showcase) hmnOnly.POST(hmnurl.RegexAdminApprovalQueue, adminMiddleware(csrfMiddleware(AdminApprovalQueueSubmit)))
mainRoutes.GET(hmnurl.RegexSnippet, Snippet)
mainRoutes.GET(hmnurl.RegexProjectIndex, ProjectIndex)
mainRoutes.GET(hmnurl.RegexProjectNotApproved, ProjectHomepage)
mainRoutes.GET(hmnurl.RegexDiscordOAuthCallback, authMiddleware(DiscordOAuthCallback)) hmnOnly.GET(hmnurl.RegexFeed, Feed)
mainRoutes.POST(hmnurl.RegexDiscordUnlink, authMiddleware(csrfMiddleware(DiscordUnlink))) hmnOnly.GET(hmnurl.RegexAtomFeed, AtomFeed)
mainRoutes.POST(hmnurl.RegexDiscordShowcaseBacklog, authMiddleware(csrfMiddleware(DiscordShowcaseBacklog))) hmnOnly.GET(hmnurl.RegexShowcase, Showcase)
hmnOnly.GET(hmnurl.RegexSnippet, Snippet)
hmnOnly.GET(hmnurl.RegexProjectIndex, ProjectIndex)
hmnOnly.GET(hmnurl.RegexProjectNotApproved, ProjectHomepage)
mainRoutes.GET(hmnurl.RegexUserProfile, UserProfile) hmnOnly.GET(hmnurl.RegexDiscordOAuthCallback, authMiddleware(DiscordOAuthCallback))
mainRoutes.GET(hmnurl.RegexUserSettings, authMiddleware(UserSettings)) hmnOnly.POST(hmnurl.RegexDiscordUnlink, authMiddleware(csrfMiddleware(DiscordUnlink)))
mainRoutes.POST(hmnurl.RegexUserSettings, authMiddleware(csrfMiddleware(UserSettingsSave))) hmnOnly.POST(hmnurl.RegexDiscordShowcaseBacklog, authMiddleware(csrfMiddleware(DiscordShowcaseBacklog)))
hmnOnly.GET(hmnurl.RegexUserProfile, UserProfile)
hmnOnly.GET(hmnurl.RegexUserSettings, authMiddleware(UserSettings))
hmnOnly.POST(hmnurl.RegexUserSettings, authMiddleware(csrfMiddleware(UserSettingsSave)))
hmnOnly.GET(hmnurl.RegexPodcast, PodcastIndex)
hmnOnly.GET(hmnurl.RegexPodcastEdit, PodcastEdit)
hmnOnly.POST(hmnurl.RegexPodcastEdit, PodcastEditSubmit)
hmnOnly.GET(hmnurl.RegexPodcastEpisodeNew, PodcastEpisodeNew)
hmnOnly.POST(hmnurl.RegexPodcastEpisodeNew, PodcastEpisodeSubmit)
hmnOnly.GET(hmnurl.RegexPodcastEpisodeEdit, PodcastEpisodeEdit)
hmnOnly.POST(hmnurl.RegexPodcastEpisodeEdit, PodcastEpisodeSubmit)
hmnOnly.GET(hmnurl.RegexPodcastEpisode, PodcastEpisode)
hmnOnly.GET(hmnurl.RegexPodcastRSS, PodcastRSS)
hmnOnly.GET(hmnurl.RegexLibraryAny, LibraryNotPortedYet)
// NOTE(asaf): Any-project routes: // NOTE(asaf): Any-project routes:
mainRoutes.GET(hmnurl.RegexForumNewThread, authMiddleware(ForumNewThread)) anyProject.GET(hmnurl.RegexForumNewThread, authMiddleware(ForumNewThread))
mainRoutes.POST(hmnurl.RegexForumNewThreadSubmit, authMiddleware(csrfMiddleware(ForumNewThreadSubmit))) anyProject.POST(hmnurl.RegexForumNewThreadSubmit, authMiddleware(csrfMiddleware(ForumNewThreadSubmit)))
mainRoutes.GET(hmnurl.RegexForumThread, ForumThread) anyProject.GET(hmnurl.RegexForumThread, ForumThread)
mainRoutes.GET(hmnurl.RegexForum, Forum) anyProject.GET(hmnurl.RegexForum, Forum)
mainRoutes.POST(hmnurl.RegexForumMarkRead, authMiddleware(csrfMiddleware(ForumMarkRead))) anyProject.POST(hmnurl.RegexForumMarkRead, authMiddleware(csrfMiddleware(ForumMarkRead)))
mainRoutes.GET(hmnurl.RegexForumPost, ForumPostRedirect) anyProject.GET(hmnurl.RegexForumPost, ForumPostRedirect)
mainRoutes.GET(hmnurl.RegexForumPostReply, authMiddleware(ForumPostReply)) anyProject.GET(hmnurl.RegexForumPostReply, authMiddleware(ForumPostReply))
mainRoutes.POST(hmnurl.RegexForumPostReply, authMiddleware(csrfMiddleware(ForumPostReplySubmit))) anyProject.POST(hmnurl.RegexForumPostReply, authMiddleware(csrfMiddleware(ForumPostReplySubmit)))
mainRoutes.GET(hmnurl.RegexForumPostEdit, authMiddleware(ForumPostEdit)) anyProject.GET(hmnurl.RegexForumPostEdit, authMiddleware(ForumPostEdit))
mainRoutes.POST(hmnurl.RegexForumPostEdit, authMiddleware(csrfMiddleware(ForumPostEditSubmit))) anyProject.POST(hmnurl.RegexForumPostEdit, authMiddleware(csrfMiddleware(ForumPostEditSubmit)))
mainRoutes.GET(hmnurl.RegexForumPostDelete, authMiddleware(ForumPostDelete)) anyProject.GET(hmnurl.RegexForumPostDelete, authMiddleware(ForumPostDelete))
mainRoutes.POST(hmnurl.RegexForumPostDelete, authMiddleware(csrfMiddleware(ForumPostDeleteSubmit))) anyProject.POST(hmnurl.RegexForumPostDelete, authMiddleware(csrfMiddleware(ForumPostDeleteSubmit)))
mainRoutes.GET(hmnurl.RegexWikiArticle, WikiArticleRedirect) anyProject.GET(hmnurl.RegexWikiArticle, WikiArticleRedirect)
mainRoutes.GET(hmnurl.RegexBlog, BlogIndex) anyProject.GET(hmnurl.RegexBlog, BlogIndex)
mainRoutes.GET(hmnurl.RegexBlogNewThread, authMiddleware(BlogNewThread)) anyProject.GET(hmnurl.RegexBlogNewThread, authMiddleware(BlogNewThread))
mainRoutes.POST(hmnurl.RegexBlogNewThread, authMiddleware(csrfMiddleware(BlogNewThreadSubmit))) anyProject.POST(hmnurl.RegexBlogNewThread, authMiddleware(csrfMiddleware(BlogNewThreadSubmit)))
mainRoutes.GET(hmnurl.RegexBlogThread, BlogThread) anyProject.GET(hmnurl.RegexBlogThread, BlogThread)
mainRoutes.GET(hmnurl.RegexBlogPost, BlogPostRedirectToThread) anyProject.GET(hmnurl.RegexBlogPost, BlogPostRedirectToThread)
mainRoutes.GET(hmnurl.RegexBlogPostReply, authMiddleware(BlogPostReply)) anyProject.GET(hmnurl.RegexBlogPostReply, authMiddleware(BlogPostReply))
mainRoutes.POST(hmnurl.RegexBlogPostReply, authMiddleware(csrfMiddleware(BlogPostReplySubmit))) anyProject.POST(hmnurl.RegexBlogPostReply, authMiddleware(csrfMiddleware(BlogPostReplySubmit)))
mainRoutes.GET(hmnurl.RegexBlogPostEdit, authMiddleware(BlogPostEdit)) anyProject.GET(hmnurl.RegexBlogPostEdit, authMiddleware(BlogPostEdit))
mainRoutes.POST(hmnurl.RegexBlogPostEdit, authMiddleware(csrfMiddleware(BlogPostEditSubmit))) anyProject.POST(hmnurl.RegexBlogPostEdit, authMiddleware(csrfMiddleware(BlogPostEditSubmit)))
mainRoutes.GET(hmnurl.RegexBlogPostDelete, authMiddleware(BlogPostDelete)) anyProject.GET(hmnurl.RegexBlogPostDelete, authMiddleware(BlogPostDelete))
mainRoutes.POST(hmnurl.RegexBlogPostDelete, authMiddleware(csrfMiddleware(BlogPostDeleteSubmit))) anyProject.POST(hmnurl.RegexBlogPostDelete, authMiddleware(csrfMiddleware(BlogPostDeleteSubmit)))
mainRoutes.GET(hmnurl.RegexBlogsRedirect, func(c *RequestContext) ResponseData { anyProject.GET(hmnurl.RegexBlogsRedirect, func(c *RequestContext) ResponseData {
return c.Redirect(hmnurl.ProjectUrl( return c.Redirect(hmnurl.ProjectUrl(
fmt.Sprintf("blog%s", c.PathParams["remainder"]), nil, fmt.Sprintf("blog%s", c.PathParams["remainder"]), nil,
c.CurrentProject.Slug, c.CurrentProject.Slug,
), http.StatusMovedPermanently) ), http.StatusMovedPermanently)
}) })
mainRoutes.POST(hmnurl.RegexAssetUpload, AssetUpload) anyProject.POST(hmnurl.RegexAssetUpload, AssetUpload)
mainRoutes.GET(hmnurl.RegexPodcast, PodcastIndex) anyProject.GET(hmnurl.RegexEpisodeList, EpisodeList)
mainRoutes.GET(hmnurl.RegexPodcastEdit, PodcastEdit) anyProject.GET(hmnurl.RegexEpisode, Episode)
mainRoutes.POST(hmnurl.RegexPodcastEdit, PodcastEditSubmit) anyProject.GET(hmnurl.RegexCineraIndex, CineraIndex)
mainRoutes.GET(hmnurl.RegexPodcastEpisodeNew, PodcastEpisodeNew)
mainRoutes.POST(hmnurl.RegexPodcastEpisodeNew, PodcastEpisodeSubmit)
mainRoutes.GET(hmnurl.RegexPodcastEpisodeEdit, PodcastEpisodeEdit)
mainRoutes.POST(hmnurl.RegexPodcastEpisodeEdit, PodcastEpisodeSubmit)
mainRoutes.GET(hmnurl.RegexPodcastEpisode, PodcastEpisode)
mainRoutes.GET(hmnurl.RegexPodcastRSS, PodcastRSS)
mainRoutes.GET(hmnurl.RegexEpisodeList, EpisodeList) anyProject.GET(hmnurl.RegexProjectCSS, ProjectCSS)
mainRoutes.GET(hmnurl.RegexEpisode, Episode) anyProject.GET(hmnurl.RegexEditorPreviewsJS, func(c *RequestContext) ResponseData {
mainRoutes.GET(hmnurl.RegexCineraIndex, CineraIndex)
mainRoutes.GET(hmnurl.RegexProjectCSS, ProjectCSS)
mainRoutes.GET(hmnurl.RegexEditorPreviewsJS, func(c *RequestContext) ResponseData {
var res ResponseData var res ResponseData
res.MustWriteTemplate("editorpreviews.js", nil, c.Perf) res.MustWriteTemplate("editorpreviews.js", nil, c.Perf)
res.Header().Add("Content-Type", "application/javascript") res.Header().Add("Content-Type", "application/javascript")
return res return res
}) })
mainRoutes.GET(hmnurl.RegexLibraryAny, LibraryNotPortedYet)
// Other // Other
mainRoutes.AnyMethod(hmnurl.RegexCatchAll, FourOhFour) anyProject.AnyMethod(hmnurl.RegexCatchAll, FourOhFour)
return router return router
} }
@ -342,9 +342,9 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc
HMNHomepageUrl: hmnurl.BuildHomepage(), HMNHomepageUrl: hmnurl.BuildHomepage(),
ProjectIndexUrl: hmnurl.BuildProjectIndex(1), ProjectIndexUrl: hmnurl.BuildProjectIndex(1),
PodcastUrl: hmnurl.BuildPodcast(c.CurrentProject.Slug), PodcastUrl: hmnurl.BuildPodcast(),
ForumsUrl: hmnurl.BuildForum(c.CurrentProject.Slug, nil, 1), ForumsUrl: hmnurl.BuildForum(c.CurrentProject.Slug, nil, 1),
LibraryUrl: hmnurl.BuildLibrary(c.CurrentProject.Slug), LibraryUrl: hmnurl.BuildLibrary(),
}, },
Footer: templates.Footer{ Footer: templates.Footer{
HomepageUrl: hmnurl.BuildHomepage(), HomepageUrl: hmnurl.BuildHomepage(),