Use new UrlContext for project URLs
Wow that was a lot to change
This commit is contained in:
parent
73836c5e25
commit
cc9c3b3b60
|
@ -6,8 +6,9 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.handmade.network/hmn/hmn/src/config"
|
|
||||||
"git.handmade.network/hmn/hmn/src/models"
|
"git.handmade.network/hmn/hmn/src/models"
|
||||||
|
|
||||||
|
"git.handmade.network/hmn/hmn/src/config"
|
||||||
"git.handmade.network/hmn/hmn/src/oops"
|
"git.handmade.network/hmn/hmn/src/oops"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -62,34 +63,25 @@ func GetBaseHost() string {
|
||||||
return baseUrlParsed.Host
|
return baseUrlParsed.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UrlContext struct {
|
||||||
|
PersonalProject bool
|
||||||
|
ProjectID int
|
||||||
|
ProjectSlug string
|
||||||
|
ProjectName string
|
||||||
|
}
|
||||||
|
|
||||||
|
var HMNProjectContext = UrlContext{
|
||||||
|
PersonalProject: false,
|
||||||
|
ProjectID: models.HMNProjectID,
|
||||||
|
ProjectSlug: models.HMNProjectSlug,
|
||||||
|
}
|
||||||
|
|
||||||
func Url(path string, query []Q) string {
|
func Url(path string, query []Q) string {
|
||||||
return ProjectUrl(path, query, "")
|
return UrlWithFragment(path, query, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectUrl(path string, query []Q, slug string) string {
|
func UrlWithFragment(path string, query []Q, fragment string) string {
|
||||||
return ProjectUrlWithFragment(path, query, slug, "")
|
return HMNProjectContext.UrlWithFragment(path, query, fragment)
|
||||||
}
|
|
||||||
|
|
||||||
func ProjectUrlWithFragment(path string, query []Q, slug string, fragment string) string {
|
|
||||||
subdomain := slug
|
|
||||||
if slug == models.HMNProjectSlug {
|
|
||||||
subdomain = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
host := baseUrlParsed.Host
|
|
||||||
if len(subdomain) > 0 {
|
|
||||||
host = slug + "." + host
|
|
||||||
}
|
|
||||||
|
|
||||||
url := url.URL{
|
|
||||||
Scheme: baseUrlParsed.Scheme,
|
|
||||||
Host: host,
|
|
||||||
Path: trim(path),
|
|
||||||
RawQuery: encodeQuery(query),
|
|
||||||
Fragment: fragment,
|
|
||||||
}
|
|
||||||
|
|
||||||
return url.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func trim(path string) string {
|
func trim(path string) string {
|
||||||
|
|
|
@ -21,12 +21,11 @@ var RegexOldHome = regexp.MustCompile("^/home$")
|
||||||
var RegexHomepage = regexp.MustCompile("^/$")
|
var RegexHomepage = regexp.MustCompile("^/$")
|
||||||
|
|
||||||
func BuildHomepage() string {
|
func BuildHomepage() string {
|
||||||
return Url("/", nil)
|
return HMNProjectContext.BuildHomepage()
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildOfficialProjectHomepage(projectSlug string) string {
|
func (c *UrlContext) BuildHomepage() string {
|
||||||
defer CatchPanic()
|
return c.Url("/", nil)
|
||||||
return ProjectUrl("/", nil, projectSlug)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexShowcase = regexp.MustCompile("^/showcase$")
|
var RegexShowcase = regexp.MustCompile("^/showcase$")
|
||||||
|
@ -196,7 +195,7 @@ func BuildUserProfile(username string) string {
|
||||||
var RegexUserSettings = regexp.MustCompile(`^/settings$`)
|
var RegexUserSettings = regexp.MustCompile(`^/settings$`)
|
||||||
|
|
||||||
func BuildUserSettings(section string) string {
|
func BuildUserSettings(section string) string {
|
||||||
return ProjectUrlWithFragment("/settings", nil, "", section)
|
return UrlWithFragment("/settings", nil, section)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -302,10 +301,10 @@ func BuildPersonalProject(id int, slug string) string {
|
||||||
|
|
||||||
var RegexProjectEdit = regexp.MustCompile("^/edit$")
|
var RegexProjectEdit = regexp.MustCompile("^/edit$")
|
||||||
|
|
||||||
func BuildProjectEdit(slug string, section string) string {
|
func (c *UrlContext) BuildProjectEdit(section string) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
|
|
||||||
return ProjectUrlWithFragment(fmt.Sprintf("/p/%s/edit", slug), nil, "", section)
|
return c.UrlWithFragment("/edit", nil, section)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -367,7 +366,50 @@ func BuildPodcastEpisodeFile(filename string) string {
|
||||||
// Make sure to match Thread before Subforum in the router.
|
// Make sure to match Thread before Subforum in the router.
|
||||||
var RegexForum = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?(/(?P<page>\d+))?$`)
|
var RegexForum = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?(/(?P<page>\d+))?$`)
|
||||||
|
|
||||||
func BuildForum(projectSlug string, subforums []string, page int) string {
|
func (c *UrlContext) Url(path string, query []Q) string {
|
||||||
|
return c.UrlWithFragment(path, query, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UrlContext) UrlWithFragment(path string, query []Q, fragment string) string {
|
||||||
|
if c == nil {
|
||||||
|
logging.Warn().Stack().Msg("URL context was nil; defaulting to the HMN URL context")
|
||||||
|
c = &HMNProjectContext
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.PersonalProject {
|
||||||
|
url := url.URL{
|
||||||
|
Scheme: baseUrlParsed.Scheme,
|
||||||
|
Host: baseUrlParsed.Host,
|
||||||
|
Path: fmt.Sprintf("p/%d/%s/%s", c.ProjectID, models.GeneratePersonalProjectSlug(c.ProjectName), trim(path)),
|
||||||
|
RawQuery: encodeQuery(query),
|
||||||
|
Fragment: fragment,
|
||||||
|
}
|
||||||
|
|
||||||
|
return url.String()
|
||||||
|
} else {
|
||||||
|
subdomain := c.ProjectSlug
|
||||||
|
if c.ProjectSlug == models.HMNProjectSlug {
|
||||||
|
subdomain = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
host := baseUrlParsed.Host
|
||||||
|
if len(subdomain) > 0 {
|
||||||
|
host = c.ProjectSlug + "." + host
|
||||||
|
}
|
||||||
|
|
||||||
|
url := url.URL{
|
||||||
|
Scheme: baseUrlParsed.Scheme,
|
||||||
|
Host: host,
|
||||||
|
Path: trim(path),
|
||||||
|
RawQuery: encodeQuery(query),
|
||||||
|
Fragment: fragment,
|
||||||
|
}
|
||||||
|
|
||||||
|
return url.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *UrlContext) BuildForum(subforums []string, page int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
if page < 1 {
|
if page < 1 {
|
||||||
panic(oops.New(nil, "Invalid forum thread page (%d), must be >= 1", page))
|
panic(oops.New(nil, "Invalid forum thread page (%d), must be >= 1", page))
|
||||||
|
@ -380,13 +422,13 @@ func BuildForum(projectSlug string, subforums []string, page int) string {
|
||||||
builder.WriteString(strconv.Itoa(page))
|
builder.WriteString(strconv.Itoa(page))
|
||||||
}
|
}
|
||||||
|
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexForumNewThread = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/new$`)
|
var RegexForumNewThread = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/new$`)
|
||||||
var RegexForumNewThreadSubmit = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/new/submit$`)
|
var RegexForumNewThreadSubmit = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/new/submit$`)
|
||||||
|
|
||||||
func BuildForumNewThread(projectSlug string, subforums []string, submit bool) string {
|
func (c *UrlContext) BuildForumNewThread(subforums []string, submit bool) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildSubforumPath(subforums)
|
builder := buildSubforumPath(subforums)
|
||||||
builder.WriteString("/t/new")
|
builder.WriteString("/t/new")
|
||||||
|
@ -394,59 +436,59 @@ func BuildForumNewThread(projectSlug string, subforums []string, submit bool) st
|
||||||
builder.WriteString("/submit")
|
builder.WriteString("/submit")
|
||||||
}
|
}
|
||||||
|
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexForumThread = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)(-([^/]+))?(/(?P<page>\d+))?$`)
|
var RegexForumThread = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)(-([^/]+))?(/(?P<page>\d+))?$`)
|
||||||
|
|
||||||
func BuildForumThread(projectSlug string, subforums []string, threadId int, title string, page int) string {
|
func (c *UrlContext) BuildForumThread(subforums []string, threadId int, title string, page int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildForumThreadPath(subforums, threadId, title, page)
|
builder := buildForumThreadPath(subforums, threadId, title, page)
|
||||||
|
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildForumThreadWithPostHash(projectSlug string, subforums []string, threadId int, title string, page int, postId int) string {
|
func (c *UrlContext) BuildForumThreadWithPostHash(subforums []string, threadId int, title string, page int, postId int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildForumThreadPath(subforums, threadId, title, page)
|
builder := buildForumThreadPath(subforums, threadId, title, page)
|
||||||
|
|
||||||
return ProjectUrlWithFragment(builder.String(), nil, projectSlug, strconv.Itoa(postId))
|
return UrlWithFragment(builder.String(), nil, strconv.Itoa(postId))
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexForumPost = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)$`)
|
var RegexForumPost = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)$`)
|
||||||
|
|
||||||
func BuildForumPost(projectSlug string, subforums []string, threadId int, postId int) string {
|
func (c *UrlContext) BuildForumPost(subforums []string, threadId int, postId int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildForumPostPath(subforums, threadId, postId)
|
builder := buildForumPostPath(subforums, threadId, postId)
|
||||||
|
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexForumPostDelete = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)/delete$`)
|
var RegexForumPostDelete = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)/delete$`)
|
||||||
|
|
||||||
func BuildForumPostDelete(projectSlug string, subforums []string, threadId int, postId int) string {
|
func (c *UrlContext) BuildForumPostDelete(subforums []string, threadId int, postId int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildForumPostPath(subforums, threadId, postId)
|
builder := buildForumPostPath(subforums, threadId, postId)
|
||||||
builder.WriteString("/delete")
|
builder.WriteString("/delete")
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexForumPostEdit = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)/edit$`)
|
var RegexForumPostEdit = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)/edit$`)
|
||||||
|
|
||||||
func BuildForumPostEdit(projectSlug string, subforums []string, threadId int, postId int) string {
|
func (c *UrlContext) BuildForumPostEdit(subforums []string, threadId int, postId int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildForumPostPath(subforums, threadId, postId)
|
builder := buildForumPostPath(subforums, threadId, postId)
|
||||||
builder.WriteString("/edit")
|
builder.WriteString("/edit")
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexForumPostReply = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)/reply$`)
|
var RegexForumPostReply = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)/reply$`)
|
||||||
|
|
||||||
func BuildForumPostReply(projectSlug string, subforums []string, threadId int, postId int) string {
|
func (c *UrlContext) BuildForumPostReply(subforums []string, threadId int, postId int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildForumPostPath(subforums, threadId, postId)
|
builder := buildForumPostPath(subforums, threadId, postId)
|
||||||
builder.WriteString("/reply")
|
builder.WriteString("/reply")
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexWikiArticle = regexp.MustCompile(`^/wiki/(?P<threadid>\d+)(-([^/]+))?$`)
|
var RegexWikiArticle = regexp.MustCompile(`^/wiki/(?P<threadid>\d+)(-([^/]+))?$`)
|
||||||
|
@ -459,7 +501,7 @@ var RegexBlogsRedirect = regexp.MustCompile(`^/blogs(?P<remainder>.*)`)
|
||||||
|
|
||||||
var RegexBlog = regexp.MustCompile(`^/blog(/(?P<page>\d+))?$`)
|
var RegexBlog = regexp.MustCompile(`^/blog(/(?P<page>\d+))?$`)
|
||||||
|
|
||||||
func BuildBlog(projectSlug string, page int) string {
|
func (c *UrlContext) BuildBlog(page int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
if page < 1 {
|
if page < 1 {
|
||||||
panic(oops.New(nil, "Invalid blog page (%d), must be >= 1", page))
|
panic(oops.New(nil, "Invalid blog page (%d), must be >= 1", page))
|
||||||
|
@ -470,63 +512,63 @@ func BuildBlog(projectSlug string, page int) string {
|
||||||
path += "/" + strconv.Itoa(page)
|
path += "/" + strconv.Itoa(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ProjectUrl(path, nil, projectSlug)
|
return c.Url(path, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexBlogThread = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)(-([^/]+))?$`)
|
var RegexBlogThread = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)(-([^/]+))?$`)
|
||||||
|
|
||||||
func BuildBlogThread(projectSlug string, threadId int, title string) string {
|
func (c *UrlContext) BuildBlogThread(threadId int, title string) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildBlogThreadPath(threadId, title)
|
builder := buildBlogThreadPath(threadId, title)
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildBlogThreadWithPostHash(projectSlug string, threadId int, title string, postId int) string {
|
func (c *UrlContext) BuildBlogThreadWithPostHash(threadId int, title string, postId int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildBlogThreadPath(threadId, title)
|
builder := buildBlogThreadPath(threadId, title)
|
||||||
return ProjectUrlWithFragment(builder.String(), nil, projectSlug, strconv.Itoa(postId))
|
return c.UrlWithFragment(builder.String(), nil, strconv.Itoa(postId))
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexBlogNewThread = regexp.MustCompile(`^/blog/new$`)
|
var RegexBlogNewThread = regexp.MustCompile(`^/blog/new$`)
|
||||||
|
|
||||||
func BuildBlogNewThread(projectSlug string) string {
|
func (c *UrlContext) BuildBlogNewThread() string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
return ProjectUrl("/blog/new", nil, projectSlug)
|
return c.Url("/blog/new", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexBlogPost = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)$`)
|
var RegexBlogPost = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)$`)
|
||||||
|
|
||||||
func BuildBlogPost(projectSlug string, threadId int, postId int) string {
|
func (c *UrlContext) BuildBlogPost(threadId int, postId int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildBlogPostPath(threadId, postId)
|
builder := buildBlogPostPath(threadId, postId)
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexBlogPostDelete = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)/delete$`)
|
var RegexBlogPostDelete = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)/delete$`)
|
||||||
|
|
||||||
func BuildBlogPostDelete(projectSlug string, threadId int, postId int) string {
|
func (c *UrlContext) BuildBlogPostDelete(threadId int, postId int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildBlogPostPath(threadId, postId)
|
builder := buildBlogPostPath(threadId, postId)
|
||||||
builder.WriteString("/delete")
|
builder.WriteString("/delete")
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexBlogPostEdit = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)/edit$`)
|
var RegexBlogPostEdit = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)/edit$`)
|
||||||
|
|
||||||
func BuildBlogPostEdit(projectSlug string, threadId int, postId int) string {
|
func (c *UrlContext) BuildBlogPostEdit(threadId int, postId int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildBlogPostPath(threadId, postId)
|
builder := buildBlogPostPath(threadId, postId)
|
||||||
builder.WriteString("/edit")
|
builder.WriteString("/edit")
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexBlogPostReply = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)/reply$`)
|
var RegexBlogPostReply = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)/reply$`)
|
||||||
|
|
||||||
func BuildBlogPostReply(projectSlug string, threadId int, postId int) string {
|
func (c *UrlContext) BuildBlogPostReply(threadId int, postId int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
builder := buildBlogPostPath(threadId, postId)
|
builder := buildBlogPostPath(threadId, postId)
|
||||||
builder.WriteString("/reply")
|
builder.WriteString("/reply")
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -580,7 +622,7 @@ func BuildLibraryResource(resourceId int) string {
|
||||||
|
|
||||||
var RegexEpisodeList = regexp.MustCompile(`^/episode(/(?P<topic>[^/]+))?$`)
|
var RegexEpisodeList = regexp.MustCompile(`^/episode(/(?P<topic>[^/]+))?$`)
|
||||||
|
|
||||||
func BuildEpisodeList(projectSlug string, topic string) string {
|
func (c *UrlContext) BuildEpisodeList(topic string) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
|
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
@ -589,21 +631,21 @@ func BuildEpisodeList(projectSlug string, topic string) string {
|
||||||
builder.WriteString("/")
|
builder.WriteString("/")
|
||||||
builder.WriteString(topic)
|
builder.WriteString(topic)
|
||||||
}
|
}
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexEpisode = regexp.MustCompile(`^/episode/(?P<topic>[^/]+)/(?P<episode>[^/]+)$`)
|
var RegexEpisode = regexp.MustCompile(`^/episode/(?P<topic>[^/]+)/(?P<episode>[^/]+)$`)
|
||||||
|
|
||||||
func BuildEpisode(projectSlug string, topic string, episode string) string {
|
func (c *UrlContext) BuildEpisode(topic string, episode string) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
return ProjectUrl(fmt.Sprintf("/episode/%s/%s", topic, episode), nil, projectSlug)
|
return c.Url(fmt.Sprintf("/episode/%s/%s", topic, episode), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexCineraIndex = regexp.MustCompile(`^/(?P<topic>[^/]+).index$`)
|
var RegexCineraIndex = regexp.MustCompile(`^/(?P<topic>[^/]+).index$`)
|
||||||
|
|
||||||
func BuildCineraIndex(projectSlug string, topic string) string {
|
func (c *UrlContext) BuildCineraIndex(topic string) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
return ProjectUrl(fmt.Sprintf("/%s.index", topic), nil, projectSlug)
|
return c.Url(fmt.Sprintf("/%s.index", topic), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -635,8 +677,8 @@ func BuildDiscordShowcaseBacklog() string {
|
||||||
var RegexAssetUpload = regexp.MustCompile("^/upload_asset$")
|
var RegexAssetUpload = regexp.MustCompile("^/upload_asset$")
|
||||||
|
|
||||||
// NOTE(asaf): Providing the projectSlug avoids any CORS problems.
|
// NOTE(asaf): Providing the projectSlug avoids any CORS problems.
|
||||||
func BuildAssetUpload(projectSlug string) string {
|
func (c *UrlContext) BuildAssetUpload() string {
|
||||||
return ProjectUrl("/upload_asset", nil, projectSlug)
|
return c.Url("/upload_asset", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -715,7 +757,7 @@ func BuildUserFile(filepath string) string {
|
||||||
var RegexForumMarkRead = regexp.MustCompile(`^/markread/(?P<sfid>\d+)$`)
|
var RegexForumMarkRead = regexp.MustCompile(`^/markread/(?P<sfid>\d+)$`)
|
||||||
|
|
||||||
// NOTE(asaf): subforumId == 0 means ALL SUBFORUMS
|
// NOTE(asaf): subforumId == 0 means ALL SUBFORUMS
|
||||||
func BuildForumMarkRead(projectSlug string, subforumId int) string {
|
func (c *UrlContext) BuildForumMarkRead(subforumId int) string {
|
||||||
defer CatchPanic()
|
defer CatchPanic()
|
||||||
if subforumId < 0 {
|
if subforumId < 0 {
|
||||||
panic(oops.New(nil, "Invalid subforum ID (%d), must be >= 0", subforumId))
|
panic(oops.New(nil, "Invalid subforum ID (%d), must be >= 0", subforumId))
|
||||||
|
@ -725,7 +767,7 @@ func BuildForumMarkRead(projectSlug string, subforumId int) string {
|
||||||
builder.WriteString("/markread/")
|
builder.WriteString("/markread/")
|
||||||
builder.WriteString(strconv.Itoa(subforumId))
|
builder.WriteString(strconv.Itoa(subforumId))
|
||||||
|
|
||||||
return ProjectUrl(builder.String(), nil, projectSlug)
|
return c.Url(builder.String(), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
var RegexCatchAll = regexp.MustCompile("^")
|
var RegexCatchAll = regexp.MustCompile("^")
|
||||||
|
|
|
@ -59,22 +59,11 @@ var LifecycleBadgeStrings = map[models.ProjectLifecycle]string{
|
||||||
models.ProjectLifecycleLTS: "Complete",
|
models.ProjectLifecycleLTS: "Complete",
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProjectUrl(p *models.Project) string {
|
func ProjectToTemplate(p *models.Project, url string, theme string) Project {
|
||||||
var url string
|
|
||||||
if p.Personal {
|
|
||||||
url = hmnurl.BuildPersonalProject(p.ID, models.GeneratePersonalProjectSlug(p.Name))
|
|
||||||
} else {
|
|
||||||
url = hmnurl.BuildOfficialProjectHomepage(p.Slug)
|
|
||||||
}
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
|
|
||||||
func ProjectToTemplate(p *models.Project, theme string) Project {
|
|
||||||
logo := p.LogoLight
|
logo := p.LogoLight
|
||||||
if theme == "dark" {
|
if theme == "dark" {
|
||||||
logo = p.LogoDark
|
logo = p.LogoDark
|
||||||
}
|
}
|
||||||
url := ProjectUrl(p)
|
|
||||||
return Project{
|
return Project{
|
||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
Subdomain: p.Subdomain(),
|
Subdomain: p.Subdomain(),
|
||||||
|
@ -91,9 +80,8 @@ func ProjectToTemplate(p *models.Project, theme string) Project {
|
||||||
|
|
||||||
IsHMN: p.IsHMN(),
|
IsHMN: p.IsHMN(),
|
||||||
|
|
||||||
HasBlog: p.BlogEnabled,
|
HasBlog: p.BlogEnabled,
|
||||||
HasForum: p.ForumEnabled,
|
HasForum: p.ForumEnabled,
|
||||||
HasLibrary: false, // TODO: port the library lol
|
|
||||||
|
|
||||||
DateApproved: p.DateApproved,
|
DateApproved: p.DateApproved,
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,9 +126,8 @@ type Project struct {
|
||||||
|
|
||||||
IsHMN bool
|
IsHMN bool
|
||||||
|
|
||||||
HasBlog bool
|
HasBlog bool
|
||||||
HasForum bool
|
HasForum bool
|
||||||
HasLibrary bool
|
|
||||||
|
|
||||||
UUID string
|
UUID string
|
||||||
DateApproved time.Time
|
DateApproved time.Time
|
||||||
|
|
|
@ -137,7 +137,7 @@ func AdminApprovalQueue(c *RequestContext) ResponseData {
|
||||||
for _, p := range posts {
|
for _, p := range posts {
|
||||||
post := templates.PostToTemplate(&p.Post, &p.Author, c.Theme)
|
post := templates.PostToTemplate(&p.Post, &p.Author, c.Theme)
|
||||||
post.AddContentVersion(p.CurrentVersion, &p.Author) // NOTE(asaf): Don't care about editors here
|
post.AddContentVersion(p.CurrentVersion, &p.Author) // NOTE(asaf): Don't care about editors here
|
||||||
post.Url = UrlForGenericPost(&p.Thread, &p.Post, lineageBuilder, p.Project.Slug)
|
post.Url = UrlForGenericPost(UrlContextForProject(&p.Project), &p.Thread, &p.Post, lineageBuilder)
|
||||||
data.Posts = append(data.Posts, postWithTitle{
|
data.Posts = append(data.Posts, postWithTitle{
|
||||||
Post: post,
|
Post: post,
|
||||||
Title: p.Thread.Title,
|
Title: p.Thread.Title,
|
||||||
|
|
|
@ -26,7 +26,7 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc
|
||||||
notices := getNoticesFromCookie(c)
|
notices := getNoticesFromCookie(c)
|
||||||
|
|
||||||
if len(breadcrumbs) > 0 {
|
if len(breadcrumbs) > 0 {
|
||||||
projectUrl := UrlForProject(c.CurrentProject)
|
projectUrl := c.UrlContext.BuildHomepage()
|
||||||
if breadcrumbs[0].Url != projectUrl {
|
if breadcrumbs[0].Url != projectUrl {
|
||||||
rootBreadcrumb := templates.Breadcrumb{
|
rootBreadcrumb := templates.Breadcrumb{
|
||||||
Name: c.CurrentProject.Name,
|
Name: c.CurrentProject.Name,
|
||||||
|
@ -42,11 +42,11 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc
|
||||||
Breadcrumbs: breadcrumbs,
|
Breadcrumbs: breadcrumbs,
|
||||||
|
|
||||||
CurrentUrl: c.FullUrl(),
|
CurrentUrl: c.FullUrl(),
|
||||||
CurrentProjectUrl: UrlForProject(c.CurrentProject),
|
CurrentProjectUrl: c.UrlContext.BuildHomepage(),
|
||||||
LoginPageUrl: hmnurl.BuildLoginPage(c.FullUrl()),
|
LoginPageUrl: hmnurl.BuildLoginPage(c.FullUrl()),
|
||||||
ProjectCSSUrl: hmnurl.BuildProjectCSS(c.CurrentProject.Color1),
|
ProjectCSSUrl: hmnurl.BuildProjectCSS(c.CurrentProject.Color1),
|
||||||
|
|
||||||
Project: templates.ProjectToTemplate(c.CurrentProject, c.Theme),
|
Project: templates.ProjectToTemplate(c.CurrentProject, c.UrlContext.BuildHomepage(), c.Theme),
|
||||||
User: templateUser,
|
User: templateUser,
|
||||||
Session: templateSession,
|
Session: templateSession,
|
||||||
Notices: notices,
|
Notices: notices,
|
||||||
|
@ -67,7 +67,7 @@ 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(),
|
PodcastUrl: hmnurl.BuildPodcast(),
|
||||||
ForumsUrl: hmnurl.BuildForum(models.HMNProjectSlug, nil, 1),
|
ForumsUrl: hmnurl.HMNProjectContext.BuildForum(nil, 1),
|
||||||
LibraryUrl: hmnurl.BuildLibrary(),
|
LibraryUrl: hmnurl.BuildLibrary(),
|
||||||
},
|
},
|
||||||
Footer: templates.Footer{
|
Footer: templates.Footer{
|
||||||
|
@ -77,7 +77,7 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc
|
||||||
CodeOfConductUrl: hmnurl.BuildCodeOfConduct(),
|
CodeOfConductUrl: hmnurl.BuildCodeOfConduct(),
|
||||||
CommunicationGuidelinesUrl: hmnurl.BuildCommunicationGuidelines(),
|
CommunicationGuidelinesUrl: hmnurl.BuildCommunicationGuidelines(),
|
||||||
ProjectIndexUrl: hmnurl.BuildProjectIndex(1),
|
ProjectIndexUrl: hmnurl.BuildProjectIndex(1),
|
||||||
ForumsUrl: hmnurl.BuildForum(models.HMNProjectSlug, nil, 1),
|
ForumsUrl: hmnurl.HMNProjectContext.BuildForum(nil, 1),
|
||||||
ContactUrl: hmnurl.BuildContactPage(),
|
ContactUrl: hmnurl.BuildContactPage(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -90,15 +90,15 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc
|
||||||
episodeGuideUrl := ""
|
episodeGuideUrl := ""
|
||||||
defaultTopic, hasAnnotations := config.Config.EpisodeGuide.Projects[c.CurrentProject.Slug]
|
defaultTopic, hasAnnotations := config.Config.EpisodeGuide.Projects[c.CurrentProject.Slug]
|
||||||
if hasAnnotations {
|
if hasAnnotations {
|
||||||
episodeGuideUrl = hmnurl.BuildEpisodeList(c.CurrentProject.Slug, defaultTopic)
|
episodeGuideUrl = c.UrlContext.BuildEpisodeList(defaultTopic)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData.Header.Project = &templates.ProjectHeader{
|
baseData.Header.Project = &templates.ProjectHeader{
|
||||||
HasForums: c.CurrentProject.ForumEnabled,
|
HasForums: c.CurrentProject.ForumEnabled,
|
||||||
HasBlog: c.CurrentProject.BlogEnabled,
|
HasBlog: c.CurrentProject.BlogEnabled,
|
||||||
HasEpisodeGuide: hasAnnotations,
|
HasEpisodeGuide: hasAnnotations,
|
||||||
ForumsUrl: hmnurl.BuildForum(c.CurrentProject.Slug, nil, 1),
|
ForumsUrl: c.UrlContext.BuildForum(nil, 1),
|
||||||
BlogUrl: hmnurl.BuildBlog(c.CurrentProject.Slug, 1),
|
BlogUrl: c.UrlContext.BuildBlog(1),
|
||||||
EpisodeGuideUrl: episodeGuideUrl,
|
EpisodeGuideUrl: episodeGuideUrl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ func BlogIndex(c *RequestContext) ResponseData {
|
||||||
numPages := utils.NumPages(numPosts, postsPerPage)
|
numPages := utils.NumPages(numPosts, postsPerPage)
|
||||||
page, ok := ParsePageNumber(c, "page", numPages)
|
page, ok := ParsePageNumber(c, "page", numPages)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.Redirect(hmnurl.BuildBlog(c.CurrentProject.Slug, page), http.StatusSeeOther)
|
c.Redirect(c.UrlContext.BuildBlog(page), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
threads, err := FetchThreads(c.Context(), c.Conn, c.CurrentUser, ThreadsQuery{
|
threads, err := FetchThreads(c.Context(), c.Conn, c.CurrentUser, ThreadsQuery{
|
||||||
|
@ -63,14 +63,14 @@ func BlogIndex(c *RequestContext) ResponseData {
|
||||||
for _, thread := range threads {
|
for _, thread := range threads {
|
||||||
entries = append(entries, blogIndexEntry{
|
entries = append(entries, blogIndexEntry{
|
||||||
Title: thread.Thread.Title,
|
Title: thread.Thread.Title,
|
||||||
Url: hmnurl.BuildBlogThread(c.CurrentProject.Slug, thread.Thread.ID, thread.Thread.Title),
|
Url: c.UrlContext.BuildBlogThread(thread.Thread.ID, thread.Thread.Title),
|
||||||
Author: templates.UserToTemplate(thread.FirstPostAuthor, c.Theme),
|
Author: templates.UserToTemplate(thread.FirstPostAuthor, c.Theme),
|
||||||
Date: thread.FirstPost.PostDate,
|
Date: thread.FirstPost.PostDate,
|
||||||
Content: template.HTML(thread.FirstPostCurrentVersion.TextParsed),
|
Content: template.HTML(thread.FirstPostCurrentVersion.TextParsed),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c, fmt.Sprintf("%s Blog", c.CurrentProject.Name), []templates.Breadcrumb{BlogBreadcrumb(c.CurrentProject.Slug)})
|
baseData := getBaseData(c, fmt.Sprintf("%s Blog", c.CurrentProject.Name), []templates.Breadcrumb{BlogBreadcrumb(c.UrlContext)})
|
||||||
|
|
||||||
canCreate := false
|
canCreate := false
|
||||||
if c.CurrentUser != nil {
|
if c.CurrentUser != nil {
|
||||||
|
@ -97,14 +97,14 @@ func BlogIndex(c *RequestContext) ResponseData {
|
||||||
Current: page,
|
Current: page,
|
||||||
Total: numPages,
|
Total: numPages,
|
||||||
|
|
||||||
FirstUrl: hmnurl.BuildBlog(c.CurrentProject.Slug, 1),
|
FirstUrl: c.UrlContext.BuildBlog(1),
|
||||||
LastUrl: hmnurl.BuildBlog(c.CurrentProject.Slug, numPages),
|
LastUrl: c.UrlContext.BuildBlog(numPages),
|
||||||
PreviousUrl: hmnurl.BuildBlog(c.CurrentProject.Slug, utils.IntClamp(1, page-1, numPages)),
|
PreviousUrl: c.UrlContext.BuildBlog(utils.IntClamp(1, page-1, numPages)),
|
||||||
NextUrl: hmnurl.BuildBlog(c.CurrentProject.Slug, utils.IntClamp(1, page+1, numPages)),
|
NextUrl: c.UrlContext.BuildBlog(utils.IntClamp(1, page+1, numPages)),
|
||||||
},
|
},
|
||||||
|
|
||||||
CanCreatePost: canCreate,
|
CanCreatePost: canCreate,
|
||||||
NewPostUrl: hmnurl.BuildBlogNewThread(c.CurrentProject.Slug),
|
NewPostUrl: c.UrlContext.BuildBlogNewThread(),
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -138,11 +138,11 @@ func BlogThread(c *RequestContext) ResponseData {
|
||||||
for _, p := range posts {
|
for _, p := range posts {
|
||||||
post := templates.PostToTemplate(&p.Post, p.Author, c.Theme)
|
post := templates.PostToTemplate(&p.Post, p.Author, c.Theme)
|
||||||
post.AddContentVersion(p.CurrentVersion, p.Editor)
|
post.AddContentVersion(p.CurrentVersion, p.Editor)
|
||||||
addBlogUrlsToPost(&post, c.CurrentProject.Slug, &p.Thread, p.Post.ID)
|
addBlogUrlsToPost(c.UrlContext, &post, &p.Thread, p.Post.ID)
|
||||||
|
|
||||||
if p.ReplyPost != nil {
|
if p.ReplyPost != nil {
|
||||||
reply := templates.PostToTemplate(p.ReplyPost, p.ReplyAuthor, c.Theme)
|
reply := templates.PostToTemplate(p.ReplyPost, p.ReplyAuthor, c.Theme)
|
||||||
addBlogUrlsToPost(&reply, c.CurrentProject.Slug, &p.Thread, p.Post.ID)
|
addBlogUrlsToPost(c.UrlContext, &reply, &p.Thread, p.Post.ID)
|
||||||
post.ReplyPost = &reply
|
post.ReplyPost = &reply
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ func BlogThread(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c, thread.Title, []templates.Breadcrumb{BlogBreadcrumb(c.CurrentProject.Slug)})
|
baseData := getBaseData(c, thread.Title, []templates.Breadcrumb{BlogBreadcrumb(c.UrlContext)})
|
||||||
baseData.OpenGraphItems = append(baseData.OpenGraphItems, templates.OpenGraphItem{
|
baseData.OpenGraphItems = append(baseData.OpenGraphItems, templates.OpenGraphItem{
|
||||||
Property: "og:description",
|
Property: "og:description",
|
||||||
Value: posts[0].Post.Preview,
|
Value: posts[0].Post.Preview,
|
||||||
|
@ -180,7 +180,7 @@ func BlogThread(c *RequestContext) ResponseData {
|
||||||
Thread: templates.ThreadToTemplate(&thread),
|
Thread: templates.ThreadToTemplate(&thread),
|
||||||
MainPost: templatePosts[0],
|
MainPost: templatePosts[0],
|
||||||
Comments: templatePosts[1:],
|
Comments: templatePosts[1:],
|
||||||
ReplyLink: hmnurl.BuildBlogPostReply(c.CurrentProject.Slug, cd.ThreadID, posts[0].Post.ID),
|
ReplyLink: c.UrlContext.BuildBlogPostReply(cd.ThreadID, posts[0].Post.ID),
|
||||||
LoginLink: hmnurl.BuildLoginPage(c.FullUrl()),
|
LoginLink: hmnurl.BuildLoginPage(c.FullUrl()),
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
return res
|
return res
|
||||||
|
@ -202,7 +202,7 @@ func BlogPostRedirectToThread(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch thread for blog redirect"))
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch thread for blog redirect"))
|
||||||
}
|
}
|
||||||
|
|
||||||
threadUrl := hmnurl.BuildBlogThreadWithPostHash(c.CurrentProject.Slug, cd.ThreadID, thread.Thread.Title, cd.PostID)
|
threadUrl := c.UrlContext.BuildBlogThreadWithPostHash(cd.ThreadID, thread.Thread.Title, cd.PostID)
|
||||||
return c.Redirect(threadUrl, http.StatusFound)
|
return c.Redirect(threadUrl, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,11 +210,11 @@ func BlogNewThread(c *RequestContext) ResponseData {
|
||||||
baseData := getBaseData(
|
baseData := getBaseData(
|
||||||
c,
|
c,
|
||||||
fmt.Sprintf("Create New Post | %s", c.CurrentProject.Name),
|
fmt.Sprintf("Create New Post | %s", c.CurrentProject.Name),
|
||||||
[]templates.Breadcrumb{BlogBreadcrumb(c.CurrentProject.Slug)},
|
[]templates.Breadcrumb{BlogBreadcrumb(c.UrlContext)},
|
||||||
)
|
)
|
||||||
|
|
||||||
editData := getEditorDataForNew(c.CurrentUser, baseData, nil)
|
editData := getEditorDataForNew(c.UrlContext, c.CurrentUser, baseData, nil)
|
||||||
editData.SubmitUrl = hmnurl.BuildBlogNewThread(c.CurrentProject.Slug)
|
editData.SubmitUrl = c.UrlContext.BuildBlogNewThread()
|
||||||
editData.SubmitLabel = "Create Post"
|
editData.SubmitLabel = "Create Post"
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
|
@ -268,7 +268,7 @@ func BlogNewThreadSubmit(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new blog post"))
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new blog post"))
|
||||||
}
|
}
|
||||||
|
|
||||||
newThreadUrl := hmnurl.BuildBlogThread(c.CurrentProject.Slug, threadId, title)
|
newThreadUrl := c.UrlContext.BuildBlogThread(threadId, title)
|
||||||
return c.Redirect(newThreadUrl, http.StatusSeeOther)
|
return c.Redirect(newThreadUrl, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,11 +301,11 @@ func BlogPostEdit(c *RequestContext) ResponseData {
|
||||||
baseData := getBaseData(
|
baseData := getBaseData(
|
||||||
c,
|
c,
|
||||||
title,
|
title,
|
||||||
BlogThreadBreadcrumbs(c.CurrentProject.Slug, &post.Thread),
|
BlogThreadBreadcrumbs(c.UrlContext, &post.Thread),
|
||||||
)
|
)
|
||||||
|
|
||||||
editData := getEditorDataForEdit(c.CurrentUser, baseData, post)
|
editData := getEditorDataForEdit(c.UrlContext, c.CurrentUser, baseData, post)
|
||||||
editData.SubmitUrl = hmnurl.BuildBlogPostEdit(c.CurrentProject.Slug, cd.ThreadID, cd.PostID)
|
editData.SubmitUrl = c.UrlContext.BuildBlogPostEdit(cd.ThreadID, cd.PostID)
|
||||||
editData.SubmitLabel = "Submit Edited Post"
|
editData.SubmitLabel = "Submit Edited Post"
|
||||||
if post.Thread.FirstID != post.Post.ID {
|
if post.Thread.FirstID != post.Post.ID {
|
||||||
editData.SubmitLabel = "Submit Edited Comment"
|
editData.SubmitLabel = "Submit Edited Comment"
|
||||||
|
@ -373,7 +373,7 @@ func BlogPostEditSubmit(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to edit blog post"))
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to edit blog post"))
|
||||||
}
|
}
|
||||||
|
|
||||||
postUrl := hmnurl.BuildBlogThreadWithPostHash(c.CurrentProject.Slug, cd.ThreadID, post.Thread.Title, cd.PostID)
|
postUrl := c.UrlContext.BuildBlogThreadWithPostHash(cd.ThreadID, post.Thread.Title, cd.PostID)
|
||||||
return c.Redirect(postUrl, http.StatusSeeOther)
|
return c.Redirect(postUrl, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,14 +396,14 @@ func BlogPostReply(c *RequestContext) ResponseData {
|
||||||
baseData := getBaseData(
|
baseData := getBaseData(
|
||||||
c,
|
c,
|
||||||
fmt.Sprintf("Replying to comment in \"%s\" | %s", post.Thread.Title, c.CurrentProject.Name),
|
fmt.Sprintf("Replying to comment in \"%s\" | %s", post.Thread.Title, c.CurrentProject.Name),
|
||||||
BlogThreadBreadcrumbs(c.CurrentProject.Slug, &post.Thread),
|
BlogThreadBreadcrumbs(c.UrlContext, &post.Thread),
|
||||||
)
|
)
|
||||||
|
|
||||||
replyPost := templates.PostToTemplate(&post.Post, post.Author, c.Theme)
|
replyPost := templates.PostToTemplate(&post.Post, post.Author, c.Theme)
|
||||||
replyPost.AddContentVersion(post.CurrentVersion, post.Editor)
|
replyPost.AddContentVersion(post.CurrentVersion, post.Editor)
|
||||||
|
|
||||||
editData := getEditorDataForNew(c.CurrentUser, baseData, &replyPost)
|
editData := getEditorDataForNew(c.UrlContext, c.CurrentUser, baseData, &replyPost)
|
||||||
editData.SubmitUrl = hmnurl.BuildBlogPostReply(c.CurrentProject.Slug, cd.ThreadID, cd.PostID)
|
editData.SubmitUrl = c.UrlContext.BuildBlogPostReply(cd.ThreadID, cd.PostID)
|
||||||
editData.SubmitLabel = "Submit Reply"
|
editData.SubmitLabel = "Submit Reply"
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
|
@ -439,7 +439,7 @@ func BlogPostReplySubmit(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to reply to blog post"))
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to reply to blog post"))
|
||||||
}
|
}
|
||||||
|
|
||||||
newPostUrl := hmnurl.BuildBlogPost(c.CurrentProject.Slug, cd.ThreadID, newPostId)
|
newPostUrl := c.UrlContext.BuildBlogPost(cd.ThreadID, newPostId)
|
||||||
return c.Redirect(newPostUrl, http.StatusSeeOther)
|
return c.Redirect(newPostUrl, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,7 +472,7 @@ func BlogPostDelete(c *RequestContext) ResponseData {
|
||||||
baseData := getBaseData(
|
baseData := getBaseData(
|
||||||
c,
|
c,
|
||||||
title,
|
title,
|
||||||
BlogThreadBreadcrumbs(c.CurrentProject.Slug, &post.Thread),
|
BlogThreadBreadcrumbs(c.UrlContext, &post.Thread),
|
||||||
)
|
)
|
||||||
|
|
||||||
templatePost := templates.PostToTemplate(&post.Post, post.Author, c.Theme)
|
templatePost := templates.PostToTemplate(&post.Post, post.Author, c.Theme)
|
||||||
|
@ -487,7 +487,7 @@ func BlogPostDelete(c *RequestContext) ResponseData {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("blog_post_delete.html", blogPostDeleteData{
|
res.MustWriteTemplate("blog_post_delete.html", blogPostDeleteData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
SubmitUrl: hmnurl.BuildBlogPostDelete(c.CurrentProject.Slug, cd.ThreadID, cd.PostID),
|
SubmitUrl: c.UrlContext.BuildBlogPostDelete(cd.ThreadID, cd.PostID),
|
||||||
Post: templatePost,
|
Post: templatePost,
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
return res
|
return res
|
||||||
|
@ -517,8 +517,7 @@ func BlogPostDeleteSubmit(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
|
|
||||||
if threadDeleted {
|
if threadDeleted {
|
||||||
projectUrl := UrlForProject(c.CurrentProject)
|
return c.Redirect(c.UrlContext.BuildHomepage(), http.StatusSeeOther)
|
||||||
return c.Redirect(projectUrl, http.StatusSeeOther)
|
|
||||||
} else {
|
} else {
|
||||||
thread, err := FetchThread(c.Context(), c.Conn, c.CurrentUser, cd.ThreadID, ThreadsQuery{
|
thread, err := FetchThread(c.Context(), c.Conn, c.CurrentUser, cd.ThreadID, ThreadsQuery{
|
||||||
ProjectIDs: []int{c.CurrentProject.ID},
|
ProjectIDs: []int{c.CurrentProject.ID},
|
||||||
|
@ -529,7 +528,7 @@ func BlogPostDeleteSubmit(c *RequestContext) ResponseData {
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch thread after blog post delete"))
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch thread after blog post delete"))
|
||||||
}
|
}
|
||||||
threadUrl := hmnurl.BuildBlogThread(c.CurrentProject.Slug, thread.Thread.ID, thread.Thread.Title)
|
threadUrl := c.UrlContext.BuildBlogThread(thread.Thread.ID, thread.Thread.Title)
|
||||||
return c.Redirect(threadUrl, http.StatusSeeOther)
|
return c.Redirect(threadUrl, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -608,9 +607,9 @@ func getCommonBlogData(c *RequestContext) (commonBlogData, bool) {
|
||||||
return res, true
|
return res, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func addBlogUrlsToPost(p *templates.Post, projectSlug string, thread *models.Thread, postId int) {
|
func addBlogUrlsToPost(urlContext *hmnurl.UrlContext, p *templates.Post, thread *models.Thread, postId int) {
|
||||||
p.Url = hmnurl.BuildBlogThreadWithPostHash(projectSlug, thread.ID, thread.Title, postId)
|
p.Url = urlContext.BuildBlogThreadWithPostHash(thread.ID, thread.Title, postId)
|
||||||
p.DeleteUrl = hmnurl.BuildBlogPostDelete(projectSlug, thread.ID, postId)
|
p.DeleteUrl = urlContext.BuildBlogPostDelete(thread.ID, postId)
|
||||||
p.EditUrl = hmnurl.BuildBlogPostEdit(projectSlug, thread.ID, postId)
|
p.EditUrl = urlContext.BuildBlogPostEdit(thread.ID, postId)
|
||||||
p.ReplyUrl = hmnurl.BuildBlogPostReply(projectSlug, thread.ID, postId)
|
p.ReplyUrl = urlContext.BuildBlogPostReply(thread.ID, postId)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,58 +6,58 @@ import (
|
||||||
"git.handmade.network/hmn/hmn/src/templates"
|
"git.handmade.network/hmn/hmn/src/templates"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProjectBreadcrumb(project *models.Project) templates.Breadcrumb {
|
func ProjectBreadcrumb(projectUrlContext *hmnurl.UrlContext) templates.Breadcrumb {
|
||||||
return templates.Breadcrumb{
|
return templates.Breadcrumb{
|
||||||
Name: project.Name,
|
Name: projectUrlContext.ProjectName,
|
||||||
Url: UrlForProject(project),
|
Url: projectUrlContext.BuildHomepage(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ForumBreadcrumb(projectSlug string) templates.Breadcrumb {
|
func ForumBreadcrumb(projectUrlContext *hmnurl.UrlContext) templates.Breadcrumb {
|
||||||
return templates.Breadcrumb{
|
return templates.Breadcrumb{
|
||||||
Name: "Forums",
|
Name: "Forums",
|
||||||
Url: hmnurl.BuildForum(projectSlug, nil, 1),
|
Url: projectUrlContext.BuildForum(nil, 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SubforumBreadcrumbs(lineageBuilder *models.SubforumLineageBuilder, project *models.Project, subforumID int) []templates.Breadcrumb {
|
func SubforumBreadcrumbs(projectUrlContext *hmnurl.UrlContext, lineageBuilder *models.SubforumLineageBuilder, subforumID int) []templates.Breadcrumb {
|
||||||
var result []templates.Breadcrumb
|
var result []templates.Breadcrumb
|
||||||
result = []templates.Breadcrumb{
|
result = []templates.Breadcrumb{
|
||||||
ProjectBreadcrumb(project),
|
ProjectBreadcrumb(projectUrlContext),
|
||||||
ForumBreadcrumb(project.Slug),
|
ForumBreadcrumb(projectUrlContext),
|
||||||
}
|
}
|
||||||
subforums := lineageBuilder.GetSubforumLineage(subforumID)
|
subforums := lineageBuilder.GetSubforumLineage(subforumID)
|
||||||
slugs := lineageBuilder.GetSubforumLineageSlugs(subforumID)
|
slugs := lineageBuilder.GetSubforumLineageSlugs(subforumID)
|
||||||
for i, subforum := range subforums {
|
for i, subforum := range subforums {
|
||||||
result = append(result, templates.Breadcrumb{
|
result = append(result, templates.Breadcrumb{
|
||||||
Name: subforum.Name,
|
Name: subforum.Name,
|
||||||
Url: hmnurl.BuildForum(project.Slug, slugs[0:i+1], 1),
|
Url: projectUrlContext.BuildForum(slugs[0:i+1], 1),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func ForumThreadBreadcrumbs(lineageBuilder *models.SubforumLineageBuilder, project *models.Project, thread *models.Thread) []templates.Breadcrumb {
|
func ForumThreadBreadcrumbs(projectUrlContext *hmnurl.UrlContext, lineageBuilder *models.SubforumLineageBuilder, thread *models.Thread) []templates.Breadcrumb {
|
||||||
result := SubforumBreadcrumbs(lineageBuilder, project, *thread.SubforumID)
|
result := SubforumBreadcrumbs(projectUrlContext, lineageBuilder, *thread.SubforumID)
|
||||||
result = append(result, templates.Breadcrumb{
|
result = append(result, templates.Breadcrumb{
|
||||||
Name: thread.Title,
|
Name: thread.Title,
|
||||||
Url: hmnurl.BuildForumThread(project.Slug, lineageBuilder.GetSubforumLineageSlugs(*thread.SubforumID), thread.ID, thread.Title, 1),
|
Url: projectUrlContext.BuildForumThread(lineageBuilder.GetSubforumLineageSlugs(*thread.SubforumID), thread.ID, thread.Title, 1),
|
||||||
})
|
})
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func BlogBreadcrumb(projectSlug string) templates.Breadcrumb {
|
func BlogBreadcrumb(projectUrlContext *hmnurl.UrlContext) templates.Breadcrumb {
|
||||||
return templates.Breadcrumb{
|
return templates.Breadcrumb{
|
||||||
Name: "Blog",
|
Name: "Blog",
|
||||||
Url: hmnurl.BuildBlog(projectSlug, 1),
|
Url: projectUrlContext.BuildBlog(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BlogThreadBreadcrumbs(projectSlug string, thread *models.Thread) []templates.Breadcrumb {
|
func BlogThreadBreadcrumbs(projectUrlContext *hmnurl.UrlContext, thread *models.Thread) []templates.Breadcrumb {
|
||||||
result := []templates.Breadcrumb{
|
result := []templates.Breadcrumb{
|
||||||
BlogBreadcrumb(projectSlug),
|
BlogBreadcrumb(projectUrlContext),
|
||||||
{Name: thread.Title, Url: hmnurl.BuildBlogThread(projectSlug, thread.ID, thread.Title)},
|
{Name: thread.Title, Url: projectUrlContext.BuildBlogThread(thread.ID, thread.Title)},
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.handmade.network/hmn/hmn/src/config"
|
"git.handmade.network/hmn/hmn/src/config"
|
||||||
"git.handmade.network/hmn/hmn/src/hmnurl"
|
|
||||||
"git.handmade.network/hmn/hmn/src/templates"
|
"git.handmade.network/hmn/hmn/src/templates"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -53,11 +52,11 @@ func EpisodeList(c *RequestContext) ResponseData {
|
||||||
defaultTopic, hasEpisodeGuide := config.Config.EpisodeGuide.Projects[slug]
|
defaultTopic, hasEpisodeGuide := config.Config.EpisodeGuide.Projects[slug]
|
||||||
|
|
||||||
if !hasEpisodeGuide {
|
if !hasEpisodeGuide {
|
||||||
return c.Redirect(UrlForProject(c.CurrentProject), http.StatusSeeOther)
|
return c.Redirect(c.UrlContext.BuildHomepage(), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
if topic == "" {
|
if topic == "" {
|
||||||
return c.Redirect(hmnurl.BuildEpisodeList(slug, defaultTopic), http.StatusSeeOther)
|
return c.Redirect(c.UrlContext.BuildEpisodeList(defaultTopic), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
allTopics, foundTopic := topicsForProject(slug, topic)
|
allTopics, foundTopic := topicsForProject(slug, topic)
|
||||||
|
@ -82,7 +81,7 @@ func EpisodeList(c *RequestContext) ResponseData {
|
||||||
for _, t := range allTopics {
|
for _, t := range allTopics {
|
||||||
url := ""
|
url := ""
|
||||||
if t != foundTopic {
|
if t != foundTopic {
|
||||||
url = hmnurl.BuildEpisodeList(slug, t)
|
url = c.UrlContext.BuildEpisodeList(t)
|
||||||
}
|
}
|
||||||
topicLinks = append(topicLinks, templates.Link{LinkText: t, Url: url})
|
topicLinks = append(topicLinks, templates.Link{LinkText: t, Url: url})
|
||||||
}
|
}
|
||||||
|
@ -114,7 +113,7 @@ func Episode(c *RequestContext) ResponseData {
|
||||||
_, hasEpisodeGuide := config.Config.EpisodeGuide.Projects[slug]
|
_, hasEpisodeGuide := config.Config.EpisodeGuide.Projects[slug]
|
||||||
|
|
||||||
if !hasEpisodeGuide {
|
if !hasEpisodeGuide {
|
||||||
return c.Redirect(UrlForProject(c.CurrentProject), http.StatusSeeOther)
|
return c.Redirect(c.UrlContext.BuildHomepage(), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, foundTopic := topicsForProject(slug, topic)
|
_, foundTopic := topicsForProject(slug, topic)
|
||||||
|
@ -150,7 +149,7 @@ func Episode(c *RequestContext) ResponseData {
|
||||||
baseData := getBaseData(
|
baseData := getBaseData(
|
||||||
c,
|
c,
|
||||||
title,
|
title,
|
||||||
[]templates.Breadcrumb{{Name: "Episode Guide", Url: hmnurl.BuildEpisodeList(c.CurrentProject.Slug, foundTopic)}},
|
[]templates.Breadcrumb{{Name: "Episode Guide", Url: c.UrlContext.BuildEpisodeList(foundTopic)}},
|
||||||
)
|
)
|
||||||
res.MustWriteTemplate("episode.html", EpisodeData{
|
res.MustWriteTemplate("episode.html", EpisodeData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
|
|
|
@ -71,7 +71,7 @@ func Feed(c *RequestContext) ResponseData {
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
|
|
||||||
AtomFeedUrl: hmnurl.BuildAtomFeed(),
|
AtomFeedUrl: hmnurl.BuildAtomFeed(),
|
||||||
MarkAllReadUrl: hmnurl.BuildForumMarkRead(c.CurrentProject.Slug, 0),
|
MarkAllReadUrl: c.UrlContext.BuildForumMarkRead(0),
|
||||||
Posts: posts,
|
Posts: posts,
|
||||||
Pagination: pagination,
|
Pagination: pagination,
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
|
@ -181,7 +181,7 @@ func AtomFeed(c *RequestContext) ResponseData {
|
||||||
projectMap := make(map[int]int) // map[project id]index in slice
|
projectMap := make(map[int]int) // map[project id]index in slice
|
||||||
for _, p := range projects.ToSlice() {
|
for _, p := range projects.ToSlice() {
|
||||||
project := p.(*projectResult).Project
|
project := p.(*projectResult).Project
|
||||||
templateProject := templates.ProjectToTemplate(&project, c.Theme)
|
templateProject := templates.ProjectToTemplate(&project, UrlContextForProject(&project).BuildHomepage(), c.Theme)
|
||||||
templateProject.UUID = uuid.NewSHA1(uuid.NameSpaceURL, []byte(templateProject.Url)).URN()
|
templateProject.UUID = uuid.NewSHA1(uuid.NameSpaceURL, []byte(templateProject.Url)).URN()
|
||||||
|
|
||||||
projectIds = append(projectIds, project.ID)
|
projectIds = append(projectIds, project.ID)
|
||||||
|
|
|
@ -35,8 +35,6 @@ type forumSubforumData struct {
|
||||||
TotalThreads int
|
TotalThreads int
|
||||||
}
|
}
|
||||||
|
|
||||||
type editActionType string
|
|
||||||
|
|
||||||
type editorData struct {
|
type editorData struct {
|
||||||
templates.BaseData
|
templates.BaseData
|
||||||
SubmitUrl string
|
SubmitUrl string
|
||||||
|
@ -54,13 +52,13 @@ type editorData struct {
|
||||||
UploadUrl string
|
UploadUrl string
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEditorDataForNew(currentUser *models.User, baseData templates.BaseData, replyPost *templates.Post) editorData {
|
func getEditorDataForNew(urlContext *hmnurl.UrlContext, currentUser *models.User, baseData templates.BaseData, replyPost *templates.Post) editorData {
|
||||||
result := editorData{
|
result := editorData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
CanEditTitle: replyPost == nil,
|
CanEditTitle: replyPost == nil,
|
||||||
PostReplyingTo: replyPost,
|
PostReplyingTo: replyPost,
|
||||||
MaxFileSize: AssetMaxSize(currentUser),
|
MaxFileSize: AssetMaxSize(currentUser),
|
||||||
UploadUrl: hmnurl.BuildAssetUpload(baseData.Project.Subdomain),
|
UploadUrl: urlContext.BuildAssetUpload(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if replyPost != nil {
|
if replyPost != nil {
|
||||||
|
@ -70,7 +68,7 @@ func getEditorDataForNew(currentUser *models.User, baseData templates.BaseData,
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEditorDataForEdit(currentUser *models.User, baseData templates.BaseData, p PostAndStuff) editorData {
|
func getEditorDataForEdit(urlContext *hmnurl.UrlContext, currentUser *models.User, baseData templates.BaseData, p PostAndStuff) editorData {
|
||||||
return editorData{
|
return editorData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
Title: p.Thread.Title,
|
Title: p.Thread.Title,
|
||||||
|
@ -78,7 +76,7 @@ func getEditorDataForEdit(currentUser *models.User, baseData templates.BaseData,
|
||||||
IsEditing: true,
|
IsEditing: true,
|
||||||
EditInitialContents: p.CurrentVersion.TextRaw,
|
EditInitialContents: p.CurrentVersion.TextRaw,
|
||||||
MaxFileSize: AssetMaxSize(currentUser),
|
MaxFileSize: AssetMaxSize(currentUser),
|
||||||
UploadUrl: hmnurl.BuildAssetUpload(baseData.Project.Subdomain),
|
UploadUrl: urlContext.BuildAssetUpload(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +102,7 @@ func Forum(c *RequestContext) ResponseData {
|
||||||
numPages := utils.NumPages(numThreads, threadsPerPage)
|
numPages := utils.NumPages(numThreads, threadsPerPage)
|
||||||
page, ok := ParsePageNumber(c, "page", numPages)
|
page, ok := ParsePageNumber(c, "page", numPages)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.Redirect(hmnurl.BuildForum(c.CurrentProject.Slug, currentSubforumSlugs, page), http.StatusSeeOther)
|
c.Redirect(c.UrlContext.BuildForum(currentSubforumSlugs, page), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
howManyThreadsToSkip := (page - 1) * threadsPerPage
|
howManyThreadsToSkip := (page - 1) * threadsPerPage
|
||||||
|
|
||||||
|
@ -119,7 +117,7 @@ func Forum(c *RequestContext) ResponseData {
|
||||||
makeThreadListItem := func(row ThreadAndStuff) templates.ThreadListItem {
|
makeThreadListItem := func(row ThreadAndStuff) templates.ThreadListItem {
|
||||||
return templates.ThreadListItem{
|
return templates.ThreadListItem{
|
||||||
Title: row.Thread.Title,
|
Title: row.Thread.Title,
|
||||||
Url: hmnurl.BuildForumThread(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(*row.Thread.SubforumID), row.Thread.ID, row.Thread.Title, 1),
|
Url: c.UrlContext.BuildForumThread(cd.LineageBuilder.GetSubforumLineageSlugs(*row.Thread.SubforumID), row.Thread.ID, row.Thread.Title, 1),
|
||||||
FirstUser: templates.UserToTemplate(row.FirstPostAuthor, c.Theme),
|
FirstUser: templates.UserToTemplate(row.FirstPostAuthor, c.Theme),
|
||||||
FirstDate: row.FirstPost.PostDate,
|
FirstDate: row.FirstPost.PostDate,
|
||||||
LastUser: templates.UserToTemplate(row.LastPostAuthor, c.Theme),
|
LastUser: templates.UserToTemplate(row.LastPostAuthor, c.Theme),
|
||||||
|
@ -165,7 +163,7 @@ func Forum(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
subforums = append(subforums, forumSubforumData{
|
subforums = append(subforums, forumSubforumData{
|
||||||
Name: sfNode.Name,
|
Name: sfNode.Name,
|
||||||
Url: hmnurl.BuildForum(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(sfNode.ID), 1),
|
Url: c.UrlContext.BuildForum(cd.LineageBuilder.GetSubforumLineageSlugs(sfNode.ID), 1),
|
||||||
Threads: threads,
|
Threads: threads,
|
||||||
TotalThreads: numThreads,
|
TotalThreads: numThreads,
|
||||||
})
|
})
|
||||||
|
@ -179,23 +177,23 @@ func Forum(c *RequestContext) ResponseData {
|
||||||
baseData := getBaseData(
|
baseData := getBaseData(
|
||||||
c,
|
c,
|
||||||
fmt.Sprintf("%s Forums", c.CurrentProject.Name),
|
fmt.Sprintf("%s Forums", c.CurrentProject.Name),
|
||||||
SubforumBreadcrumbs(cd.LineageBuilder, c.CurrentProject, cd.SubforumID),
|
SubforumBreadcrumbs(c.UrlContext, cd.LineageBuilder, cd.SubforumID),
|
||||||
)
|
)
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("forum.html", forumData{
|
res.MustWriteTemplate("forum.html", forumData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
NewThreadUrl: hmnurl.BuildForumNewThread(c.CurrentProject.Slug, currentSubforumSlugs, false),
|
NewThreadUrl: c.UrlContext.BuildForumNewThread(currentSubforumSlugs, false),
|
||||||
MarkReadUrl: hmnurl.BuildForumMarkRead(c.CurrentProject.Slug, cd.SubforumID),
|
MarkReadUrl: c.UrlContext.BuildForumMarkRead(cd.SubforumID),
|
||||||
Threads: threads,
|
Threads: threads,
|
||||||
Pagination: templates.Pagination{
|
Pagination: templates.Pagination{
|
||||||
Current: page,
|
Current: page,
|
||||||
Total: numPages,
|
Total: numPages,
|
||||||
|
|
||||||
FirstUrl: hmnurl.BuildForum(c.CurrentProject.Slug, currentSubforumSlugs, 1),
|
FirstUrl: c.UrlContext.BuildForum(currentSubforumSlugs, 1),
|
||||||
LastUrl: hmnurl.BuildForum(c.CurrentProject.Slug, currentSubforumSlugs, numPages),
|
LastUrl: c.UrlContext.BuildForum(currentSubforumSlugs, numPages),
|
||||||
NextUrl: hmnurl.BuildForum(c.CurrentProject.Slug, currentSubforumSlugs, utils.IntClamp(1, page+1, numPages)),
|
NextUrl: c.UrlContext.BuildForum(currentSubforumSlugs, utils.IntClamp(1, page+1, numPages)),
|
||||||
PreviousUrl: hmnurl.BuildForum(c.CurrentProject.Slug, currentSubforumSlugs, utils.IntClamp(1, page-1, numPages)),
|
PreviousUrl: c.UrlContext.BuildForum(currentSubforumSlugs, utils.IntClamp(1, page-1, numPages)),
|
||||||
},
|
},
|
||||||
Subforums: subforums,
|
Subforums: subforums,
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
|
@ -308,7 +306,7 @@ func ForumMarkRead(c *RequestContext) ResponseData {
|
||||||
if sfId == 0 {
|
if sfId == 0 {
|
||||||
redirUrl = hmnurl.BuildFeed()
|
redirUrl = hmnurl.BuildFeed()
|
||||||
} else {
|
} else {
|
||||||
redirUrl = hmnurl.BuildForum(c.CurrentProject.Slug, lineageBuilder.GetSubforumLineageSlugs(sfId), 1)
|
redirUrl = c.UrlContext.BuildForum(lineageBuilder.GetSubforumLineageSlugs(sfId), 1)
|
||||||
}
|
}
|
||||||
return c.Redirect(redirUrl, http.StatusSeeOther)
|
return c.Redirect(redirUrl, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
@ -358,17 +356,17 @@ func ForumThread(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
page, numPages, ok := getPageInfo(c.PathParams["page"], numPosts, threadPostsPerPage)
|
page, numPages, ok := getPageInfo(c.PathParams["page"], numPosts, threadPostsPerPage)
|
||||||
if !ok {
|
if !ok {
|
||||||
urlNoPage := hmnurl.BuildForumThread(c.CurrentProject.Slug, currentSubforumSlugs, thread.ID, thread.Title, 1)
|
urlNoPage := c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, 1)
|
||||||
return c.Redirect(urlNoPage, http.StatusSeeOther)
|
return c.Redirect(urlNoPage, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
pagination := templates.Pagination{
|
pagination := templates.Pagination{
|
||||||
Current: page,
|
Current: page,
|
||||||
Total: numPages,
|
Total: numPages,
|
||||||
|
|
||||||
FirstUrl: hmnurl.BuildForumThread(c.CurrentProject.Slug, currentSubforumSlugs, thread.ID, thread.Title, 1),
|
FirstUrl: c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, 1),
|
||||||
LastUrl: hmnurl.BuildForumThread(c.CurrentProject.Slug, currentSubforumSlugs, thread.ID, thread.Title, numPages),
|
LastUrl: c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, numPages),
|
||||||
NextUrl: hmnurl.BuildForumThread(c.CurrentProject.Slug, currentSubforumSlugs, thread.ID, thread.Title, utils.IntClamp(1, page+1, numPages)),
|
NextUrl: c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, utils.IntClamp(1, page+1, numPages)),
|
||||||
PreviousUrl: hmnurl.BuildForumThread(c.CurrentProject.Slug, currentSubforumSlugs, thread.ID, thread.Title, utils.IntClamp(1, page-1, numPages)),
|
PreviousUrl: c.UrlContext.BuildForumThread(currentSubforumSlugs, thread.ID, thread.Title, utils.IntClamp(1, page-1, numPages)),
|
||||||
}
|
}
|
||||||
|
|
||||||
postsAndStuff, err := FetchPosts(c.Context(), c.Conn, c.CurrentUser, PostsQuery{
|
postsAndStuff, err := FetchPosts(c.Context(), c.Conn, c.CurrentUser, PostsQuery{
|
||||||
|
@ -385,11 +383,11 @@ func ForumThread(c *RequestContext) ResponseData {
|
||||||
for _, p := range postsAndStuff {
|
for _, p := range postsAndStuff {
|
||||||
post := templates.PostToTemplate(&p.Post, p.Author, c.Theme)
|
post := templates.PostToTemplate(&p.Post, p.Author, c.Theme)
|
||||||
post.AddContentVersion(p.CurrentVersion, p.Editor)
|
post.AddContentVersion(p.CurrentVersion, p.Editor)
|
||||||
addForumUrlsToPost(&post, c.CurrentProject.Slug, currentSubforumSlugs, thread.ID, post.ID)
|
addForumUrlsToPost(c.UrlContext, &post, currentSubforumSlugs, thread.ID, post.ID)
|
||||||
|
|
||||||
if p.ReplyPost != nil {
|
if p.ReplyPost != nil {
|
||||||
reply := templates.PostToTemplate(p.ReplyPost, p.ReplyAuthor, c.Theme)
|
reply := templates.PostToTemplate(p.ReplyPost, p.ReplyAuthor, c.Theme)
|
||||||
addForumUrlsToPost(&reply, c.CurrentProject.Slug, currentSubforumSlugs, thread.ID, reply.ID)
|
addForumUrlsToPost(c.UrlContext, &reply, currentSubforumSlugs, thread.ID, reply.ID)
|
||||||
post.ReplyPost = &reply
|
post.ReplyPost = &reply
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +416,7 @@ func ForumThread(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c, thread.Title, SubforumBreadcrumbs(cd.LineageBuilder, c.CurrentProject, cd.SubforumID))
|
baseData := getBaseData(c, thread.Title, SubforumBreadcrumbs(c.UrlContext, cd.LineageBuilder, cd.SubforumID))
|
||||||
baseData.OpenGraphItems = append(baseData.OpenGraphItems, templates.OpenGraphItem{
|
baseData.OpenGraphItems = append(baseData.OpenGraphItems, templates.OpenGraphItem{
|
||||||
Property: "og:description",
|
Property: "og:description",
|
||||||
Value: threadResult.FirstPost.Preview,
|
Value: threadResult.FirstPost.Preview,
|
||||||
|
@ -429,8 +427,8 @@ func ForumThread(c *RequestContext) ResponseData {
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
Thread: templates.ThreadToTemplate(&thread),
|
Thread: templates.ThreadToTemplate(&thread),
|
||||||
Posts: posts,
|
Posts: posts,
|
||||||
SubforumUrl: hmnurl.BuildForum(c.CurrentProject.Slug, currentSubforumSlugs, 1),
|
SubforumUrl: c.UrlContext.BuildForum(currentSubforumSlugs, 1),
|
||||||
ReplyUrl: hmnurl.BuildForumPostReply(c.CurrentProject.Slug, currentSubforumSlugs, thread.ID, thread.FirstID),
|
ReplyUrl: c.UrlContext.BuildForumPostReply(currentSubforumSlugs, thread.ID, thread.FirstID),
|
||||||
Pagination: pagination,
|
Pagination: pagination,
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
return res
|
return res
|
||||||
|
@ -466,8 +464,7 @@ func ForumPostRedirect(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
page := (postIdx / threadPostsPerPage) + 1
|
page := (postIdx / threadPostsPerPage) + 1
|
||||||
|
|
||||||
return c.Redirect(hmnurl.BuildForumThreadWithPostHash(
|
return c.Redirect(c.UrlContext.BuildForumThreadWithPostHash(
|
||||||
c.CurrentProject.Slug,
|
|
||||||
cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID),
|
cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID),
|
||||||
cd.ThreadID,
|
cd.ThreadID,
|
||||||
post.Thread.Title,
|
post.Thread.Title,
|
||||||
|
@ -482,9 +479,9 @@ func ForumNewThread(c *RequestContext) ResponseData {
|
||||||
return FourOhFour(c)
|
return FourOhFour(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseData := getBaseData(c, "Create New Thread", SubforumBreadcrumbs(cd.LineageBuilder, c.CurrentProject, cd.SubforumID))
|
baseData := getBaseData(c, "Create New Thread", SubforumBreadcrumbs(c.UrlContext, cd.LineageBuilder, cd.SubforumID))
|
||||||
editData := getEditorDataForNew(c.CurrentUser, baseData, nil)
|
editData := getEditorDataForNew(c.UrlContext, c.CurrentUser, baseData, nil)
|
||||||
editData.SubmitUrl = hmnurl.BuildForumNewThread(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), true)
|
editData.SubmitUrl = c.UrlContext.BuildForumNewThread(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), true)
|
||||||
editData.SubmitLabel = "Post New Thread"
|
editData.SubmitLabel = "Post New Thread"
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
|
@ -549,7 +546,7 @@ func ForumNewThreadSubmit(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new forum thread"))
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new forum thread"))
|
||||||
}
|
}
|
||||||
|
|
||||||
newThreadUrl := hmnurl.BuildForumThread(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), threadId, title, 1)
|
newThreadUrl := c.UrlContext.BuildForumThread(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), threadId, title, 1)
|
||||||
return c.Redirect(newThreadUrl, http.StatusSeeOther)
|
return c.Redirect(newThreadUrl, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,14 +569,14 @@ func ForumPostReply(c *RequestContext) ResponseData {
|
||||||
baseData := getBaseData(
|
baseData := getBaseData(
|
||||||
c,
|
c,
|
||||||
fmt.Sprintf("Replying to post | %s", cd.SubforumTree[cd.SubforumID].Name),
|
fmt.Sprintf("Replying to post | %s", cd.SubforumTree[cd.SubforumID].Name),
|
||||||
ForumThreadBreadcrumbs(cd.LineageBuilder, c.CurrentProject, &post.Thread),
|
ForumThreadBreadcrumbs(c.UrlContext, cd.LineageBuilder, &post.Thread),
|
||||||
)
|
)
|
||||||
|
|
||||||
replyPost := templates.PostToTemplate(&post.Post, post.Author, c.Theme)
|
replyPost := templates.PostToTemplate(&post.Post, post.Author, c.Theme)
|
||||||
replyPost.AddContentVersion(post.CurrentVersion, post.Editor)
|
replyPost.AddContentVersion(post.CurrentVersion, post.Editor)
|
||||||
|
|
||||||
editData := getEditorDataForNew(c.CurrentUser, baseData, &replyPost)
|
editData := getEditorDataForNew(c.UrlContext, c.CurrentUser, baseData, &replyPost)
|
||||||
editData.SubmitUrl = hmnurl.BuildForumPostReply(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID)
|
editData.SubmitUrl = c.UrlContext.BuildForumPostReply(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID)
|
||||||
editData.SubmitLabel = "Submit Reply"
|
editData.SubmitLabel = "Submit Reply"
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
|
@ -629,7 +626,7 @@ func ForumPostReplySubmit(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to reply to forum post"))
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to reply to forum post"))
|
||||||
}
|
}
|
||||||
|
|
||||||
newPostUrl := hmnurl.BuildForumPost(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, newPostId)
|
newPostUrl := c.UrlContext.BuildForumPost(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, newPostId)
|
||||||
return c.Redirect(newPostUrl, http.StatusSeeOther)
|
return c.Redirect(newPostUrl, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,10 +656,10 @@ func ForumPostEdit(c *RequestContext) ResponseData {
|
||||||
} else {
|
} else {
|
||||||
title = fmt.Sprintf("Editing Post | %s", cd.SubforumTree[cd.SubforumID].Name)
|
title = fmt.Sprintf("Editing Post | %s", cd.SubforumTree[cd.SubforumID].Name)
|
||||||
}
|
}
|
||||||
baseData := getBaseData(c, title, ForumThreadBreadcrumbs(cd.LineageBuilder, c.CurrentProject, &post.Thread))
|
baseData := getBaseData(c, title, ForumThreadBreadcrumbs(c.UrlContext, cd.LineageBuilder, &post.Thread))
|
||||||
|
|
||||||
editData := getEditorDataForEdit(c.CurrentUser, baseData, post)
|
editData := getEditorDataForEdit(c.UrlContext, c.CurrentUser, baseData, post)
|
||||||
editData.SubmitUrl = hmnurl.BuildForumPostEdit(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID)
|
editData.SubmitUrl = c.UrlContext.BuildForumPostEdit(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID)
|
||||||
editData.SubmitLabel = "Submit Edited Post"
|
editData.SubmitLabel = "Submit Edited Post"
|
||||||
|
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
|
@ -727,7 +724,7 @@ func ForumPostEditSubmit(c *RequestContext) ResponseData {
|
||||||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to edit forum post"))
|
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to edit forum post"))
|
||||||
}
|
}
|
||||||
|
|
||||||
postUrl := hmnurl.BuildForumPost(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID)
|
postUrl := c.UrlContext.BuildForumPost(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID)
|
||||||
return c.Redirect(postUrl, http.StatusSeeOther)
|
return c.Redirect(postUrl, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,7 +751,7 @@ func ForumPostDelete(c *RequestContext) ResponseData {
|
||||||
baseData := getBaseData(
|
baseData := getBaseData(
|
||||||
c,
|
c,
|
||||||
fmt.Sprintf("Deleting post in \"%s\" | %s", post.Thread.Title, cd.SubforumTree[cd.SubforumID].Name),
|
fmt.Sprintf("Deleting post in \"%s\" | %s", post.Thread.Title, cd.SubforumTree[cd.SubforumID].Name),
|
||||||
ForumThreadBreadcrumbs(cd.LineageBuilder, c.CurrentProject, &post.Thread),
|
ForumThreadBreadcrumbs(c.UrlContext, cd.LineageBuilder, &post.Thread),
|
||||||
)
|
)
|
||||||
|
|
||||||
templatePost := templates.PostToTemplate(&post.Post, post.Author, c.Theme)
|
templatePost := templates.PostToTemplate(&post.Post, post.Author, c.Theme)
|
||||||
|
@ -769,7 +766,7 @@ func ForumPostDelete(c *RequestContext) ResponseData {
|
||||||
var res ResponseData
|
var res ResponseData
|
||||||
res.MustWriteTemplate("forum_post_delete.html", forumPostDeleteData{
|
res.MustWriteTemplate("forum_post_delete.html", forumPostDeleteData{
|
||||||
BaseData: baseData,
|
BaseData: baseData,
|
||||||
SubmitUrl: hmnurl.BuildForumPostDelete(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID),
|
SubmitUrl: c.UrlContext.BuildForumPostDelete(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID),
|
||||||
Post: templatePost,
|
Post: templatePost,
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
return res
|
return res
|
||||||
|
@ -799,10 +796,10 @@ func ForumPostDeleteSubmit(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
|
|
||||||
if threadDeleted {
|
if threadDeleted {
|
||||||
forumUrl := hmnurl.BuildForum(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), 1)
|
forumUrl := c.UrlContext.BuildForum(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), 1)
|
||||||
return c.Redirect(forumUrl, http.StatusSeeOther)
|
return c.Redirect(forumUrl, http.StatusSeeOther)
|
||||||
} else {
|
} else {
|
||||||
threadUrl := hmnurl.BuildForumThread(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, "", 1) // TODO: Go to the last page of the thread? Or the post before the post we just deleted?
|
threadUrl := c.UrlContext.BuildForumThread(cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, "", 1) // TODO: Go to the last page of the thread? Or the post before the post we just deleted?
|
||||||
return c.Redirect(threadUrl, http.StatusSeeOther)
|
return c.Redirect(threadUrl, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -829,7 +826,7 @@ func WikiArticleRedirect(c *RequestContext) ResponseData {
|
||||||
lineageBuilder := models.MakeSubforumLineageBuilder(subforumTree)
|
lineageBuilder := models.MakeSubforumLineageBuilder(subforumTree)
|
||||||
c.Perf.EndBlock()
|
c.Perf.EndBlock()
|
||||||
|
|
||||||
dest := UrlForGenericThread(&thread.Thread, lineageBuilder, c.CurrentProject.Slug)
|
dest := UrlForGenericThread(c.UrlContext, &thread.Thread, lineageBuilder)
|
||||||
return c.Redirect(dest, http.StatusFound)
|
return c.Redirect(dest, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,11 +925,11 @@ func validateSubforums(lineageBuilder *models.SubforumLineageBuilder, project *m
|
||||||
return subforumId, valid
|
return subforumId, valid
|
||||||
}
|
}
|
||||||
|
|
||||||
func addForumUrlsToPost(p *templates.Post, projectSlug string, subforums []string, threadId int, postId int) {
|
func addForumUrlsToPost(urlContext *hmnurl.UrlContext, p *templates.Post, subforums []string, threadId int, postId int) {
|
||||||
p.Url = hmnurl.BuildForumPost(projectSlug, subforums, threadId, postId)
|
p.Url = urlContext.BuildForumPost(subforums, threadId, postId)
|
||||||
p.DeleteUrl = hmnurl.BuildForumPostDelete(projectSlug, subforums, threadId, postId)
|
p.DeleteUrl = urlContext.BuildForumPostDelete(subforums, threadId, postId)
|
||||||
p.EditUrl = hmnurl.BuildForumPostEdit(projectSlug, subforums, threadId, postId)
|
p.EditUrl = urlContext.BuildForumPostEdit(subforums, threadId, postId)
|
||||||
p.ReplyUrl = hmnurl.BuildForumPostReply(projectSlug, subforums, threadId, postId)
|
p.ReplyUrl = urlContext.BuildForumPostReply(subforums, threadId, postId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Takes a template post and adds information about how many posts the user has made
|
// Takes a template post and adds information about how many posts the user has made
|
||||||
|
|
|
@ -74,7 +74,7 @@ func Index(c *RequestContext) ResponseData {
|
||||||
c.Logger.Warn().Err(err).Msg("failed to fetch latest posts")
|
c.Logger.Warn().Err(err).Msg("failed to fetch latest posts")
|
||||||
}
|
}
|
||||||
for _, p := range posts {
|
for _, p := range posts {
|
||||||
item := PostToTimelineItem(lineageBuilder, &p.Post, &p.Thread, &p.Project, p.Author, c.Theme)
|
item := PostToTimelineItem(UrlContextForProject(&p.Project), lineageBuilder, &p.Post, &p.Thread, p.Author, c.Theme)
|
||||||
if p.Thread.Type == models.ThreadTypeProjectBlogPost && p.Post.ID == p.Thread.FirstID {
|
if p.Thread.Type == models.ThreadTypeProjectBlogPost && p.Post.ID == p.Thread.FirstID {
|
||||||
// blog post
|
// blog post
|
||||||
item.Description = template.HTML(p.CurrentVersion.TextParsed)
|
item.Description = template.HTML(p.CurrentVersion.TextParsed)
|
||||||
|
@ -95,7 +95,7 @@ func Index(c *RequestContext) ResponseData {
|
||||||
var newsPostItem *templates.TimelineItem
|
var newsPostItem *templates.TimelineItem
|
||||||
if len(newsThreads) > 0 {
|
if len(newsThreads) > 0 {
|
||||||
t := newsThreads[0]
|
t := newsThreads[0]
|
||||||
item := PostToTimelineItem(lineageBuilder, &t.FirstPost, &t.Thread, &t.Project, t.FirstPostAuthor, c.Theme)
|
item := PostToTimelineItem(UrlContextForProject(&t.Project), lineageBuilder, &t.FirstPost, &t.Thread, t.FirstPostAuthor, c.Theme)
|
||||||
item.OwnerAvatarUrl = ""
|
item.OwnerAvatarUrl = ""
|
||||||
item.Breadcrumbs = nil
|
item.Breadcrumbs = nil
|
||||||
item.TypeTitle = ""
|
item.TypeTitle = ""
|
||||||
|
@ -167,7 +167,7 @@ func Index(c *RequestContext) ResponseData {
|
||||||
StreamsUrl: hmnurl.BuildStreams(),
|
StreamsUrl: hmnurl.BuildStreams(),
|
||||||
ShowcaseUrl: hmnurl.BuildShowcase(),
|
ShowcaseUrl: hmnurl.BuildShowcase(),
|
||||||
AtomFeedUrl: hmnurl.BuildAtomFeed(),
|
AtomFeedUrl: hmnurl.BuildAtomFeed(),
|
||||||
MarkAllReadUrl: hmnurl.BuildForumMarkRead(models.HMNProjectSlug, 0),
|
MarkAllReadUrl: hmnurl.HMNProjectContext.BuildForumMarkRead(0),
|
||||||
|
|
||||||
WheelJamUrl: hmnurl.BuildJamIndex(),
|
WheelJamUrl: hmnurl.BuildJamIndex(),
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
|
|
|
@ -7,26 +7,26 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NOTE(asaf): Please don't use these if you already know the kind of the thread beforehand. Just call the appropriate build function.
|
// NOTE(asaf): Please don't use these if you already know the kind of the thread beforehand. Just call the appropriate build function.
|
||||||
func UrlForGenericThread(thread *models.Thread, lineageBuilder *models.SubforumLineageBuilder, projectSlug string) string {
|
func UrlForGenericThread(urlContext *hmnurl.UrlContext, thread *models.Thread, lineageBuilder *models.SubforumLineageBuilder) string {
|
||||||
switch thread.Type {
|
switch thread.Type {
|
||||||
case models.ThreadTypeProjectBlogPost:
|
case models.ThreadTypeProjectBlogPost:
|
||||||
return hmnurl.BuildBlogThread(projectSlug, thread.ID, thread.Title)
|
return urlContext.BuildBlogThread(thread.ID, thread.Title)
|
||||||
case models.ThreadTypeForumPost:
|
case models.ThreadTypeForumPost:
|
||||||
return hmnurl.BuildForumThread(projectSlug, lineageBuilder.GetSubforumLineageSlugs(*thread.SubforumID), thread.ID, thread.Title, 1)
|
return urlContext.BuildForumThread(lineageBuilder.GetSubforumLineageSlugs(*thread.SubforumID), thread.ID, thread.Title, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return hmnurl.BuildOfficialProjectHomepage(projectSlug) // TODO: both official and personal projects
|
return urlContext.BuildHomepage()
|
||||||
}
|
}
|
||||||
|
|
||||||
func UrlForGenericPost(thread *models.Thread, post *models.Post, lineageBuilder *models.SubforumLineageBuilder, projectSlug string) string {
|
func UrlForGenericPost(urlContext *hmnurl.UrlContext, thread *models.Thread, post *models.Post, lineageBuilder *models.SubforumLineageBuilder) string {
|
||||||
switch post.ThreadType {
|
switch post.ThreadType {
|
||||||
case models.ThreadTypeProjectBlogPost:
|
case models.ThreadTypeProjectBlogPost:
|
||||||
return hmnurl.BuildBlogThreadWithPostHash(projectSlug, post.ThreadID, thread.Title, post.ID)
|
return urlContext.BuildBlogThreadWithPostHash(post.ThreadID, thread.Title, post.ID)
|
||||||
case models.ThreadTypeForumPost:
|
case models.ThreadTypeForumPost:
|
||||||
return hmnurl.BuildForumPost(projectSlug, lineageBuilder.GetSubforumLineageSlugs(*thread.SubforumID), post.ThreadID, post.ID)
|
return urlContext.BuildForumPost(lineageBuilder.GetSubforumLineageSlugs(*thread.SubforumID), post.ThreadID, post.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return hmnurl.BuildOfficialProjectHomepage(projectSlug) // TODO: both official and personal projects
|
return urlContext.BuildHomepage()
|
||||||
}
|
}
|
||||||
|
|
||||||
var PostTypeMap = map[models.ThreadType][]templates.PostType{
|
var PostTypeMap = map[models.ThreadType][]templates.PostType{
|
||||||
|
@ -47,33 +47,33 @@ var ThreadTypeDisplayNames = map[models.ThreadType]string{
|
||||||
models.ThreadTypeForumPost: "Forums",
|
models.ThreadTypeForumPost: "Forums",
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenericThreadBreadcrumbs(lineageBuilder *models.SubforumLineageBuilder, project *models.Project, thread *models.Thread) []templates.Breadcrumb {
|
func GenericThreadBreadcrumbs(urlContext *hmnurl.UrlContext, lineageBuilder *models.SubforumLineageBuilder, thread *models.Thread) []templates.Breadcrumb {
|
||||||
var result []templates.Breadcrumb
|
var result []templates.Breadcrumb
|
||||||
if thread.Type == models.ThreadTypeForumPost {
|
if thread.Type == models.ThreadTypeForumPost {
|
||||||
result = SubforumBreadcrumbs(lineageBuilder, project, *thread.SubforumID)
|
result = SubforumBreadcrumbs(urlContext, lineageBuilder, *thread.SubforumID)
|
||||||
} else {
|
} else {
|
||||||
result = []templates.Breadcrumb{
|
result = []templates.Breadcrumb{
|
||||||
{
|
{
|
||||||
Name: project.Name,
|
Name: urlContext.ProjectName,
|
||||||
Url: UrlForProject(project),
|
Url: urlContext.BuildHomepage(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: ThreadTypeDisplayNames[thread.Type],
|
Name: ThreadTypeDisplayNames[thread.Type],
|
||||||
Url: BuildProjectRootResourceUrl(project.Slug, thread.Type),
|
Url: BuildProjectRootResourceUrl(urlContext, thread.Type),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func BuildProjectRootResourceUrl(projectSlug string, kind models.ThreadType) string {
|
func BuildProjectRootResourceUrl(urlContext *hmnurl.UrlContext, kind models.ThreadType) string {
|
||||||
switch kind {
|
switch kind {
|
||||||
case models.ThreadTypeProjectBlogPost:
|
case models.ThreadTypeProjectBlogPost:
|
||||||
return hmnurl.BuildBlog(projectSlug, 1)
|
return urlContext.BuildBlog(1)
|
||||||
case models.ThreadTypeForumPost:
|
case models.ThreadTypeForumPost:
|
||||||
return hmnurl.BuildForum(projectSlug, nil, 1)
|
return urlContext.BuildForum(nil, 1)
|
||||||
}
|
}
|
||||||
return hmnurl.BuildOfficialProjectHomepage(projectSlug) // TODO: both official and personal projects
|
return urlContext.BuildHomepage()
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakePostListItem(
|
func MakePostListItem(
|
||||||
|
@ -88,11 +88,13 @@ func MakePostListItem(
|
||||||
) templates.PostListItem {
|
) templates.PostListItem {
|
||||||
var result templates.PostListItem
|
var result templates.PostListItem
|
||||||
|
|
||||||
|
urlContext := UrlContextForProject(project)
|
||||||
|
|
||||||
result.Title = thread.Title
|
result.Title = thread.Title
|
||||||
result.User = templates.UserToTemplate(user, currentTheme)
|
result.User = templates.UserToTemplate(user, currentTheme)
|
||||||
result.Date = post.PostDate
|
result.Date = post.PostDate
|
||||||
result.Unread = unread
|
result.Unread = unread
|
||||||
result.Url = UrlForGenericPost(thread, post, lineageBuilder, project.Slug)
|
result.Url = UrlForGenericPost(urlContext, thread, post, lineageBuilder)
|
||||||
result.Preview = post.Preview
|
result.Preview = post.Preview
|
||||||
|
|
||||||
postType := templates.PostTypeUnknown
|
postType := templates.PostTypeUnknown
|
||||||
|
@ -108,7 +110,7 @@ func MakePostListItem(
|
||||||
result.PostTypePrefix = PostTypePrefix[result.PostType]
|
result.PostTypePrefix = PostTypePrefix[result.PostType]
|
||||||
|
|
||||||
if includeBreadcrumbs {
|
if includeBreadcrumbs {
|
||||||
result.Breadcrumbs = GenericThreadBreadcrumbs(lineageBuilder, project, thread)
|
result.Breadcrumbs = GenericThreadBreadcrumbs(urlContext, lineageBuilder, thread)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -3,8 +3,9 @@ package website
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.handmade.network/hmn/hmn/src/db"
|
|
||||||
"git.handmade.network/hmn/hmn/src/hmnurl"
|
"git.handmade.network/hmn/hmn/src/hmnurl"
|
||||||
|
|
||||||
|
"git.handmade.network/hmn/hmn/src/db"
|
||||||
"git.handmade.network/hmn/hmn/src/models"
|
"git.handmade.network/hmn/hmn/src/models"
|
||||||
"git.handmade.network/hmn/hmn/src/oops"
|
"git.handmade.network/hmn/hmn/src/oops"
|
||||||
)
|
)
|
||||||
|
@ -388,10 +389,11 @@ func FetchProjectOwners(
|
||||||
return projectOwners[0].Owners, nil
|
return projectOwners[0].Owners, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UrlForProject(p *models.Project) string {
|
func UrlContextForProject(p *models.Project) *hmnurl.UrlContext {
|
||||||
if p.Personal {
|
return &hmnurl.UrlContext{
|
||||||
return hmnurl.BuildPersonalProject(p.ID, models.GeneratePersonalProjectSlug(p.Name))
|
PersonalProject: p.Personal,
|
||||||
} else {
|
ProjectID: p.ID,
|
||||||
return hmnurl.BuildOfficialProjectHomepage(p.Slug)
|
ProjectSlug: p.Slug,
|
||||||
|
ProjectName: p.Name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ func ProjectIndex(c *RequestContext) ResponseData {
|
||||||
var restProjects []templates.Project
|
var restProjects []templates.Project
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
for _, p := range officialProjects {
|
for _, p := range officialProjects {
|
||||||
templateProject := templates.ProjectToTemplate(&p.Project, c.Theme)
|
templateProject := templates.ProjectToTemplate(&p.Project, UrlContextForProject(&p.Project).BuildHomepage(), c.Theme)
|
||||||
if p.Project.Slug == "hero" {
|
if p.Project.Slug == "hero" {
|
||||||
// NOTE(asaf): Handmade Hero gets special treatment. Must always be first in the list.
|
// NOTE(asaf): Handmade Hero gets special treatment. Must always be first in the list.
|
||||||
handmadeHero = &templateProject
|
handmadeHero = &templateProject
|
||||||
|
@ -121,7 +121,11 @@ func ProjectIndex(c *RequestContext) ResponseData {
|
||||||
if i >= maxPersonalProjects {
|
if i >= maxPersonalProjects {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
personalProjects = append(personalProjects, templates.ProjectToTemplate(&p.Project, c.Theme))
|
personalProjects = append(personalProjects, templates.ProjectToTemplate(
|
||||||
|
&p.Project,
|
||||||
|
UrlContextForProject(&p.Project).BuildHomepage(),
|
||||||
|
c.Theme,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +140,7 @@ func ProjectIndex(c *RequestContext) ResponseData {
|
||||||
PersonalProjects: personalProjects,
|
PersonalProjects: personalProjects,
|
||||||
|
|
||||||
ProjectAtomFeedUrl: hmnurl.BuildAtomFeedForProjects(),
|
ProjectAtomFeedUrl: hmnurl.BuildAtomFeedForProjects(),
|
||||||
WIPForumUrl: hmnurl.BuildForum(models.HMNProjectSlug, []string{"wip"}, 1),
|
WIPForumUrl: hmnurl.HMNProjectContext.BuildForum([]string{"wip"}, 1),
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -249,7 +253,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
|
||||||
Value: c.CurrentProject.Blurb,
|
Value: c.CurrentProject.Blurb,
|
||||||
})
|
})
|
||||||
|
|
||||||
projectHomepageData.Project = templates.ProjectToTemplate(c.CurrentProject, c.Theme)
|
projectHomepageData.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))
|
projectHomepageData.Owners = append(projectHomepageData.Owners, templates.UserToTemplate(owner, c.Theme))
|
||||||
}
|
}
|
||||||
|
@ -268,7 +272,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
|
||||||
"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.",
|
||||||
hmnurl.BuildProjectEdit(c.CurrentProject.Slug, "submit"),
|
c.UrlContext.BuildProjectEdit("submit"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
case models.ProjectLifecycleApprovalRequired:
|
case models.ProjectLifecycleApprovalRequired:
|
||||||
|
@ -309,10 +313,10 @@ func ProjectHomepage(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
for _, post := range postQueryResult.ToSlice() {
|
for _, post := range postQueryResult.ToSlice() {
|
||||||
projectHomepageData.RecentActivity = append(projectHomepageData.RecentActivity, PostToTimelineItem(
|
projectHomepageData.RecentActivity = append(projectHomepageData.RecentActivity, PostToTimelineItem(
|
||||||
|
c.UrlContext,
|
||||||
lineageBuilder,
|
lineageBuilder,
|
||||||
&post.(*postQuery).Post,
|
&post.(*postQuery).Post,
|
||||||
&post.(*postQuery).Thread,
|
&post.(*postQuery).Thread,
|
||||||
c.CurrentProject,
|
|
||||||
&post.(*postQuery).Author,
|
&post.(*postQuery).Author,
|
||||||
c.Theme,
|
c.Theme,
|
||||||
))
|
))
|
||||||
|
|
|
@ -156,6 +156,7 @@ type RequestContext struct {
|
||||||
CurrentUser *models.User
|
CurrentUser *models.User
|
||||||
CurrentSession *models.Session
|
CurrentSession *models.Session
|
||||||
Theme string
|
Theme string
|
||||||
|
UrlContext *hmnurl.UrlContext
|
||||||
|
|
||||||
Perf *perf.RequestPerf
|
Perf *perf.RequestPerf
|
||||||
|
|
||||||
|
|
|
@ -251,9 +251,8 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
|
||||||
rb.GET(hmnurl.RegexBlogPostDelete, authMiddleware(BlogPostDelete))
|
rb.GET(hmnurl.RegexBlogPostDelete, authMiddleware(BlogPostDelete))
|
||||||
rb.POST(hmnurl.RegexBlogPostDelete, authMiddleware(csrfMiddleware(BlogPostDeleteSubmit)))
|
rb.POST(hmnurl.RegexBlogPostDelete, authMiddleware(csrfMiddleware(BlogPostDeleteSubmit)))
|
||||||
rb.GET(hmnurl.RegexBlogsRedirect, func(c *RequestContext) ResponseData {
|
rb.GET(hmnurl.RegexBlogsRedirect, func(c *RequestContext) ResponseData {
|
||||||
return c.Redirect(hmnurl.ProjectUrl(
|
return c.Redirect(c.UrlContext.Url(
|
||||||
fmt.Sprintf("blog%s", c.PathParams["remainder"]), nil,
|
fmt.Sprintf("blog%s", c.PathParams["remainder"]), nil,
|
||||||
c.CurrentProject.Slug,
|
|
||||||
), http.StatusMovedPermanently)
|
), http.StatusMovedPermanently)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -281,7 +280,7 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
|
||||||
|
|
||||||
if !p.Project.Personal {
|
if !p.Project.Personal {
|
||||||
// TODO: Redirect to the same page on the other prefix
|
// TODO: Redirect to the same page on the other prefix
|
||||||
return c.Redirect(hmnurl.BuildOfficialProjectHomepage(p.Project.Slug), http.StatusSeeOther)
|
return c.Redirect(UrlContextForProject(&p.Project).BuildHomepage(), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.PathParams["slug"] != models.GeneratePersonalProjectSlug(p.Project.Name) {
|
if c.PathParams["slug"] != models.GeneratePersonalProjectSlug(p.Project.Name) {
|
||||||
|
@ -290,6 +289,7 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
|
||||||
}
|
}
|
||||||
|
|
||||||
c.CurrentProject = &p.Project
|
c.CurrentProject = &p.Project
|
||||||
|
c.UrlContext = UrlContextForProject(c.CurrentProject)
|
||||||
|
|
||||||
return h(c)
|
return h(c)
|
||||||
})
|
})
|
||||||
|
@ -458,15 +458,15 @@ func LoadCommonWebsiteData(c *RequestContext) (bool, ResponseData) {
|
||||||
if c.CurrentProject == nil {
|
if c.CurrentProject == nil {
|
||||||
panic("failed to load project data")
|
panic("failed to load project data")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.UrlContext = UrlContextForProject(c.CurrentProject)
|
||||||
}
|
}
|
||||||
|
|
||||||
theme := "light"
|
c.Theme = "light"
|
||||||
if c.CurrentUser != nil && c.CurrentUser.DarkTheme {
|
if c.CurrentUser != nil && c.CurrentUser.DarkTheme {
|
||||||
theme = "dark"
|
c.Theme = "dark"
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Theme = theme
|
|
||||||
|
|
||||||
return true, ResponseData{}
|
return true, ResponseData{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,18 +24,18 @@ var TimelineTypeTitleMap = map[models.ThreadType]TimelineTypeTitles{
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostToTimelineItem(
|
func PostToTimelineItem(
|
||||||
|
urlContext *hmnurl.UrlContext,
|
||||||
lineageBuilder *models.SubforumLineageBuilder,
|
lineageBuilder *models.SubforumLineageBuilder,
|
||||||
post *models.Post,
|
post *models.Post,
|
||||||
thread *models.Thread,
|
thread *models.Thread,
|
||||||
project *models.Project,
|
|
||||||
owner *models.User,
|
owner *models.User,
|
||||||
currentTheme string,
|
currentTheme string,
|
||||||
) templates.TimelineItem {
|
) templates.TimelineItem {
|
||||||
item := templates.TimelineItem{
|
item := templates.TimelineItem{
|
||||||
Date: post.PostDate,
|
Date: post.PostDate,
|
||||||
Title: thread.Title,
|
Title: thread.Title,
|
||||||
Breadcrumbs: GenericThreadBreadcrumbs(lineageBuilder, project, thread),
|
Breadcrumbs: GenericThreadBreadcrumbs(urlContext, lineageBuilder, thread),
|
||||||
Url: UrlForGenericPost(thread, post, lineageBuilder, project.Slug),
|
Url: UrlForGenericPost(urlContext, thread, post, lineageBuilder),
|
||||||
|
|
||||||
OwnerAvatarUrl: templates.UserAvatarUrl(owner, currentTheme),
|
OwnerAvatarUrl: templates.UserAvatarUrl(owner, currentTheme),
|
||||||
OwnerName: owner.BestName(),
|
OwnerName: owner.BestName(),
|
||||||
|
|
|
@ -121,7 +121,11 @@ func UserProfile(c *RequestContext) ResponseData {
|
||||||
templateProjects := make([]templates.Project, 0, len(projectQuerySlice))
|
templateProjects := make([]templates.Project, 0, len(projectQuerySlice))
|
||||||
for _, projectRow := range projectQuerySlice {
|
for _, projectRow := range projectQuerySlice {
|
||||||
projectData := projectRow.(*projectQuery)
|
projectData := projectRow.(*projectQuery)
|
||||||
templateProjects = append(templateProjects, templates.ProjectToTemplate(&projectData.Project, c.Theme))
|
templateProjects = append(templateProjects, templates.ProjectToTemplate(
|
||||||
|
&projectData.Project,
|
||||||
|
UrlContextForProject(&projectData.Project).BuildHomepage(),
|
||||||
|
c.Theme,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
c.Perf.EndBlock()
|
c.Perf.EndBlock()
|
||||||
|
|
||||||
|
@ -166,10 +170,10 @@ func UserProfile(c *RequestContext) ResponseData {
|
||||||
|
|
||||||
for _, post := range posts {
|
for _, post := range posts {
|
||||||
timelineItems = append(timelineItems, PostToTimelineItem(
|
timelineItems = append(timelineItems, PostToTimelineItem(
|
||||||
|
UrlContextForProject(&post.Project),
|
||||||
lineageBuilder,
|
lineageBuilder,
|
||||||
&post.Post,
|
&post.Post,
|
||||||
&post.Thread,
|
&post.Thread,
|
||||||
&post.Project,
|
|
||||||
profileUser,
|
profileUser,
|
||||||
c.Theme,
|
c.Theme,
|
||||||
))
|
))
|
||||||
|
|
Loading…
Reference in New Issue