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) {
AssertRegexMatch(t, BuildPodcast(""), RegexPodcast, nil)
AssertSubdomain(t, BuildPodcast(""), "")
AssertSubdomain(t, BuildPodcast("hmn"), "")
AssertSubdomain(t, BuildPodcast("hero"), "hero")
AssertRegexMatch(t, BuildPodcast(), RegexPodcast, nil)
}
func TestPodcastEdit(t *testing.T) {
AssertRegexMatch(t, BuildPodcastEdit(""), RegexPodcastEdit, nil)
AssertRegexMatch(t, BuildPodcastEdit(), RegexPodcastEdit, nil)
}
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) {
AssertRegexMatch(t, BuildPodcastEpisodeNew(""), RegexPodcastEpisodeNew, nil)
AssertRegexMatch(t, BuildPodcastEpisodeNew(), RegexPodcastEpisodeNew, nil)
}
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) {
AssertRegexMatch(t, BuildPodcastRSS(""), RegexPodcastRSS, nil)
AssertRegexMatch(t, BuildPodcastRSS(), RegexPodcastRSS, nil)
}
func TestForum(t *testing.T) {
@ -265,23 +262,19 @@ func TestBlogPostReply(t *testing.T) {
}
func TestLibrary(t *testing.T) {
AssertRegexMatch(t, BuildLibrary(""), RegexLibrary, nil)
AssertSubdomain(t, BuildLibrary("hero"), "hero")
AssertRegexMatch(t, BuildLibrary(), RegexLibrary, nil)
}
func TestLibraryAll(t *testing.T) {
AssertRegexMatch(t, BuildLibraryAll(""), RegexLibraryAll, nil)
AssertSubdomain(t, BuildLibraryAll("hero"), "hero")
AssertRegexMatch(t, BuildLibraryAll(), RegexLibraryAll, nil)
}
func TestLibraryTopic(t *testing.T) {
AssertRegexMatch(t, BuildLibraryTopic("", 1), RegexLibraryTopic, map[string]string{"topicid": "1"})
AssertSubdomain(t, BuildLibraryTopic("hero", 1), "hero")
AssertRegexMatch(t, BuildLibraryTopic(1), RegexLibraryTopic, map[string]string{"topicid": "1"})
}
func TestLibraryResource(t *testing.T) {
AssertRegexMatch(t, BuildLibraryResource("", 1), RegexLibraryResource, map[string]string{"resourceid": "1"})
AssertSubdomain(t, BuildLibraryResource("hero", 1), "hero")
AssertRegexMatch(t, BuildLibraryResource(1), RegexLibraryResource, map[string]string{"resourceid": "1"})
}
func TestEpisodeGuide(t *testing.T) {
@ -429,5 +422,5 @@ func AssertRegexNoMatch(t *testing.T, fullUrl string, regex *regexp.Regexp) {
func TestThingsThatDontNeedCoverage(t *testing.T) {
// look the other way ಠ_ಠ
BuildPodcastEpisodeFile("foo", "bar")
BuildPodcastEpisodeFile("foo")
}

View File

@ -8,6 +8,7 @@ import (
"strings"
"git.handmade.network/hmn/hmn/src/logging"
"git.handmade.network/hmn/hmn/src/models"
"git.handmade.network/hmn/hmn/src/oops"
)
@ -316,49 +317,49 @@ func BuildProjectEdit(slug string, section string) string {
var RegexPodcast = regexp.MustCompile(`^/podcast$`)
func BuildPodcast(projectSlug string) string {
func BuildPodcast() string {
defer CatchPanic()
return ProjectUrl("/podcast", nil, projectSlug)
return Url("/podcast", nil)
}
var RegexPodcastEdit = regexp.MustCompile(`^/podcast/edit$`)
func BuildPodcastEdit(projectSlug string) string {
func BuildPodcastEdit() string {
defer CatchPanic()
return ProjectUrl("/podcast/edit", nil, projectSlug)
return Url("/podcast/edit", nil)
}
var RegexPodcastEpisode = regexp.MustCompile(`^/podcast/ep/(?P<episodeid>[^/]+)$`)
func BuildPodcastEpisode(projectSlug string, episodeGUID string) string {
func BuildPodcastEpisode(episodeGUID string) string {
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$`)
func BuildPodcastEpisodeNew(projectSlug string) string {
func BuildPodcastEpisodeNew() string {
defer CatchPanic()
return ProjectUrl("/podcast/ep/new", nil, projectSlug)
return Url("/podcast/ep/new", nil)
}
var RegexPodcastEpisodeEdit = regexp.MustCompile(`^/podcast/ep/(?P<episodeid>[^/]+)/edit$`)
func BuildPodcastEpisodeEdit(projectSlug string, episodeGUID string) string {
func BuildPodcastEpisodeEdit(episodeGUID string) string {
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$`)
func BuildPodcastRSS(projectSlug string) string {
func BuildPodcastRSS() string {
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()
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$`)
func BuildLibrary(projectSlug string) string {
func BuildLibrary() string {
defer CatchPanic()
return ProjectUrl("/library", nil, projectSlug)
return Url("/library", nil)
}
var RegexLibraryAll = regexp.MustCompile(`^/library/all$`)
func BuildLibraryAll(projectSlug string) string {
func BuildLibraryAll() string {
defer CatchPanic()
return ProjectUrl("/library/all", nil, projectSlug)
return Url("/library/all", nil)
}
var RegexLibraryTopic = regexp.MustCompile(`^/library/topic/(?P<topicid>\d+)$`)
func BuildLibraryTopic(projectSlug string, topicId int) string {
func BuildLibraryTopic(topicId int) string {
defer CatchPanic()
if topicId < 1 {
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(strconv.Itoa(topicId))
return ProjectUrl(builder.String(), nil, projectSlug)
return Url(builder.String(), nil)
}
var RegexLibraryResource = regexp.MustCompile(`^/library/resource/(?P<resourceid>\d+)$`)
func BuildLibraryResource(projectSlug string, resourceId int) string {
func BuildLibraryResource(resourceId int) string {
defer CatchPanic()
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()
}
func PodcastToTemplate(projectSlug string, podcast *models.Podcast, imageFilename string) Podcast {
func PodcastToTemplate(podcast *models.Podcast, imageFilename string) Podcast {
imageUrl := ""
if imageFilename != "" {
imageUrl = hmnurl.BuildUserFile(imageFilename)
@ -337,9 +337,9 @@ func PodcastToTemplate(projectSlug string, podcast *models.Podcast, imageFilenam
Description: podcast.Description,
Language: podcast.Language,
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
AppleUrl: "https://podcasts.apple.com/us/podcast/the-handmade-network-podcast/id1507790631",
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 := ""
if imageFilename != "" {
imageUrl = hmnurl.BuildUserFile(imageFilename)
@ -358,9 +358,9 @@ func PodcastEpisodeToTemplate(projectSlug string, episode *models.PodcastEpisode
Description: episode.Description,
DescriptionHtml: template.HTML(episode.DescriptionHtml),
EpisodeNumber: episode.EpisodeNumber,
Url: hmnurl.BuildPodcastEpisode(projectSlug, episode.GUID.String()),
Url: hmnurl.BuildPodcastEpisode(episode.GUID.String()),
ImageUrl: imageUrl,
FileUrl: hmnurl.BuildPodcastEpisodeFile(projectSlug, episode.AudioFile),
FileUrl: hmnurl.BuildPodcastEpisodeFile(episode.AudioFile),
FileSize: audioFileSize,
PublicationDate: episode.PublicationDate,
Duration: episode.Duration,

View File

@ -25,7 +25,7 @@
</div>
{{ end }}
</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">
<a href="{{ .Header.HMNHomepageUrl }}" class="hmn-logo bg-theme-dark">
Handmade
@ -52,6 +52,10 @@
</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>
</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(),
FeedUrl: hmnurl.BuildFeed(),
PodcastUrl: hmnurl.BuildPodcast(models.HMNProjectSlug),
PodcastUrl: hmnurl.BuildPodcast(),
StreamsUrl: hmnurl.BuildStreams(),
IRCUrl: hmnurl.BuildBlogThread(models.HMNProjectSlug, 1138, "[Tutorial] Handmade Network IRC"),
DiscordUrl: "https://discord.gg/hxWxDee",

View File

@ -48,16 +48,16 @@ func PodcastIndex(c *RequestContext) ResponseData {
podcastIndexData := PodcastIndexData{
BaseData: baseData,
Podcast: templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, podcastResult.ImageFile),
Podcast: templates.PodcastToTemplate(podcastResult.Podcast, podcastResult.ImageFile),
}
if canEdit {
podcastIndexData.EditUrl = hmnurl.BuildPodcastEdit(c.CurrentProject.Slug)
podcastIndexData.NewEpisodeUrl = hmnurl.BuildPodcastEpisodeNew(c.CurrentProject.Slug)
podcastIndexData.EditUrl = hmnurl.BuildPodcastEdit()
podcastIndexData.NewEpisodeUrl = hmnurl.BuildPodcastEpisodeNew()
}
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
err = res.WriteTemplate("podcast_index.html", podcastIndexData, c.Perf)
@ -87,7 +87,7 @@ func PodcastEdit(c *RequestContext) ResponseData {
return FourOhFour(c)
}
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, podcastResult.ImageFile)
podcast := templates.PodcastToTemplate(podcastResult.Podcast, podcastResult.ImageFile)
baseData := getBaseData(
c,
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"))
}
res := c.Redirect(hmnurl.BuildPodcastEdit(c.CurrentProject.Slug), http.StatusSeeOther)
res := c.Redirect(hmnurl.BuildPodcastEdit(), http.StatusSeeOther)
res.AddFutureNotice("success", "Podcast updated successfully.")
return res
}
@ -226,11 +226,11 @@ func PodcastEpisode(c *RequestContext) ResponseData {
editUrl := ""
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)
episode := templates.PodcastEpisodeToTemplate(c.CurrentProject.Slug, podcastResult.Episodes[0], 0, podcastResult.ImageFile)
podcast := templates.PodcastToTemplate(podcastResult.Podcast, podcastResult.ImageFile)
episode := templates.PodcastEpisodeToTemplate(podcastResult.Episodes[0], 0, podcastResult.ImageFile)
baseData := getBaseData(
c,
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"))
}
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, "")
podcast := templates.PodcastToTemplate(podcastResult.Podcast, "")
var res ResponseData
baseData := getBaseData(
c,
@ -326,8 +326,8 @@ func PodcastEpisodeEdit(c *RequestContext) ResponseData {
}
episode := podcastResult.Episodes[0]
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, "")
podcastEpisode := templates.PodcastEpisodeToTemplate(c.CurrentProject.Slug, episode, 0, "")
podcast := templates.PodcastToTemplate(podcastResult.Podcast, "")
podcastEpisode := templates.PodcastEpisodeToTemplate(episode, 0, "")
baseData := getBaseData(
c,
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.")
return res
}
@ -519,7 +519,7 @@ func PodcastRSS(c *RequestContext) ResponseData {
}
podcastRSSData := PodcastRSSData{
Podcast: templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, podcastResult.ImageFile),
Podcast: templates.PodcastToTemplate(podcastResult.Podcast, podcastResult.ImageFile),
}
for _, episode := range podcastResult.Episodes {
@ -530,7 +530,7 @@ func PodcastRSS(c *RequestContext) ResponseData {
} else {
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

View File

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