Add all the rest of the blog post operations
Still need to add UI for the blog index, and fix some aesthetic issues: - Wide posts can break the editor UI - Blog comments don't show the fancy reply UI - The post hash stuff on blog threads doesn't jump you to the correct post Probably other stuff, I dunno.
This commit is contained in:
parent
9945ab061d
commit
1f4dd335c5
|
@ -428,6 +428,13 @@ func BuildBlogThreadWithPostHash(projectSlug string, threadId int, title string,
|
||||||
return ProjectUrlWithFragment(builder.String(), nil, projectSlug, strconv.Itoa(postId))
|
return ProjectUrlWithFragment(builder.String(), nil, projectSlug, strconv.Itoa(postId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var RegexBlogNewThread = regexp.MustCompile(`^/blog/new$`)
|
||||||
|
|
||||||
|
func BuildBlogNewThread(projectSlug string) string {
|
||||||
|
defer CatchPanic()
|
||||||
|
return ProjectUrl("/blog/new", nil, projectSlug)
|
||||||
|
}
|
||||||
|
|
||||||
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 BuildBlogPost(projectSlug string, threadId int, postId int) string {
|
||||||
|
|
|
@ -3,13 +3,13 @@ package models
|
||||||
type ThreadType int
|
type ThreadType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ThreadTypeProjectArticle ThreadType = iota + 1
|
ThreadTypeProjectBlogPost ThreadType = iota + 1
|
||||||
ThreadTypeForumPost
|
ThreadTypeForumPost
|
||||||
_ // formerly occupied by static pages, RIP
|
_ // formerly occupied by static pages, RIP
|
||||||
_ // formerly occupied by who the hell knows what, RIP
|
_ // formerly occupied by who the hell knows what, RIP
|
||||||
_ // formerly occupied by the wiki, RIP
|
_ // formerly occupied by the wiki, RIP
|
||||||
_ // formerly occupied by library discussions, RIP
|
_ // formerly occupied by library discussions, RIP
|
||||||
ThreadTypePersonalArticle
|
ThreadTypePersonalBlogPost
|
||||||
)
|
)
|
||||||
|
|
||||||
type Thread struct {
|
type Thread struct {
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
{{ template "base.html" . }}
|
||||||
|
|
||||||
|
{{ define "content" }}
|
||||||
|
<div class="mw7 margin-center">
|
||||||
|
<h3 class="mb3">Are you sure you want to delete this post?</h3>
|
||||||
|
{{ template "forum_post_standalone.html" .Post }}
|
||||||
|
<form action="{{ .SubmitUrl }}" method="POST" class="pv3 flex justify-end">
|
||||||
|
{{ csrftoken .Session }}
|
||||||
|
<input type="submit" value="Delete Post">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{{ end }}
|
|
@ -58,6 +58,8 @@ 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),
|
||||||
|
LoginLink: hmnurl.BuildLoginPage(c.FullUrl()),
|
||||||
}, c.Perf)
|
}, c.Perf)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -74,6 +76,71 @@ func BlogPostRedirectToThread(c *RequestContext) ResponseData {
|
||||||
return c.Redirect(threadUrl, http.StatusFound)
|
return c.Redirect(threadUrl, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BlogNewThread(c *RequestContext) ResponseData {
|
||||||
|
baseData := getBaseData(c)
|
||||||
|
baseData.Title = fmt.Sprintf("Create New Post | %s", c.CurrentProject.Name)
|
||||||
|
baseData.MathjaxEnabled = true
|
||||||
|
// TODO(ben): Set breadcrumbs
|
||||||
|
|
||||||
|
editData := getEditorDataForNew(baseData, nil)
|
||||||
|
editData.SubmitUrl = hmnurl.BuildBlogNewThread(c.CurrentProject.Slug)
|
||||||
|
editData.SubmitLabel = "Create Post"
|
||||||
|
|
||||||
|
var res ResponseData
|
||||||
|
res.MustWriteTemplate("editor.html", editData, c.Perf)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func BlogNewThreadSubmit(c *RequestContext) ResponseData {
|
||||||
|
tx, err := c.Conn.Begin(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer tx.Rollback(c.Context())
|
||||||
|
|
||||||
|
err = c.Req.ParseForm()
|
||||||
|
if err != nil {
|
||||||
|
return ErrorResponse(http.StatusBadRequest, oops.New(err, "the form data was invalid"))
|
||||||
|
}
|
||||||
|
title := c.Req.Form.Get("title")
|
||||||
|
unparsed := c.Req.Form.Get("body")
|
||||||
|
if title == "" {
|
||||||
|
return RejectRequest(c, "You must provide a title for your post.")
|
||||||
|
}
|
||||||
|
if unparsed == "" {
|
||||||
|
return RejectRequest(c, "You must provide a body for your post.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create thread
|
||||||
|
var threadId int
|
||||||
|
err = tx.QueryRow(c.Context(),
|
||||||
|
`
|
||||||
|
INSERT INTO handmade_thread (title, type, project_id, first_id, last_id)
|
||||||
|
VALUES ($1, $2, $3, $4, $5)
|
||||||
|
RETURNING id
|
||||||
|
`,
|
||||||
|
title,
|
||||||
|
models.ThreadTypeProjectBlogPost,
|
||||||
|
c.CurrentProject.ID,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
).Scan(&threadId)
|
||||||
|
if err != nil {
|
||||||
|
panic(oops.New(err, "failed to create thread"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create everything else
|
||||||
|
CreateNewPost(c.Context(), tx, c.CurrentProject.ID, threadId, models.ThreadTypeProjectBlogPost, c.CurrentUser.ID, nil, unparsed, c.Req.Host)
|
||||||
|
|
||||||
|
err = tx.Commit(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new blog post"))
|
||||||
|
}
|
||||||
|
|
||||||
|
newThreadUrl := hmnurl.BuildBlogThread(c.CurrentProject.Slug, threadId, title)
|
||||||
|
return c.Redirect(newThreadUrl, http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
||||||
func BlogPostEdit(c *RequestContext) ResponseData {
|
func BlogPostEdit(c *RequestContext) ResponseData {
|
||||||
cd, ok := getCommonBlogData(c)
|
cd, ok := getCommonBlogData(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -147,6 +214,135 @@ func BlogPostEditSubmit(c *RequestContext) ResponseData {
|
||||||
return c.Redirect(postUrl, http.StatusSeeOther)
|
return c.Redirect(postUrl, http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BlogPostReply(c *RequestContext) ResponseData {
|
||||||
|
cd, ok := getCommonBlogData(c)
|
||||||
|
if !ok {
|
||||||
|
return FourOhFour(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
||||||
|
|
||||||
|
baseData := getBaseData(c)
|
||||||
|
baseData.Title = fmt.Sprintf("Replying to comment in \"%s\" | %s", postData.Thread.Title, c.CurrentProject.Name)
|
||||||
|
baseData.MathjaxEnabled = true
|
||||||
|
// TODO(ben): Set breadcrumbs
|
||||||
|
|
||||||
|
replyPost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
||||||
|
replyPost.AddContentVersion(postData.CurrentVersion, postData.Editor)
|
||||||
|
|
||||||
|
editData := getEditorDataForNew(baseData, &replyPost)
|
||||||
|
editData.SubmitUrl = hmnurl.BuildBlogPostReply(c.CurrentProject.Slug, cd.ThreadID, cd.PostID)
|
||||||
|
editData.SubmitLabel = "Submit Reply"
|
||||||
|
|
||||||
|
var res ResponseData
|
||||||
|
res.MustWriteTemplate("editor.html", editData, c.Perf)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func BlogPostReplySubmit(c *RequestContext) ResponseData {
|
||||||
|
cd, ok := getCommonBlogData(c)
|
||||||
|
if !ok {
|
||||||
|
return FourOhFour(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := c.Conn.Begin(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer tx.Rollback(c.Context())
|
||||||
|
|
||||||
|
err = c.Req.ParseForm()
|
||||||
|
if err != nil {
|
||||||
|
return ErrorResponse(http.StatusBadRequest, oops.New(nil, "the form data was invalid"))
|
||||||
|
}
|
||||||
|
unparsed := c.Req.Form.Get("body")
|
||||||
|
if unparsed == "" {
|
||||||
|
return RejectRequest(c, "Your reply cannot be empty.")
|
||||||
|
}
|
||||||
|
|
||||||
|
newPostId, _ := CreateNewPost(c.Context(), tx, c.CurrentProject.ID, cd.ThreadID, models.ThreadTypeProjectBlogPost, c.CurrentUser.ID, &cd.PostID, unparsed, c.Req.Host)
|
||||||
|
|
||||||
|
err = tx.Commit(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to reply to blog post"))
|
||||||
|
}
|
||||||
|
|
||||||
|
newPostUrl := hmnurl.BuildBlogPost(c.CurrentProject.Slug, cd.ThreadID, newPostId)
|
||||||
|
return c.Redirect(newPostUrl, http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BlogPostDelete(c *RequestContext) ResponseData {
|
||||||
|
cd, ok := getCommonBlogData(c)
|
||||||
|
if !ok {
|
||||||
|
return FourOhFour(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !UserCanEditPost(c.Context(), c.Conn, *c.CurrentUser, cd.PostID) {
|
||||||
|
return FourOhFour(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
||||||
|
|
||||||
|
baseData := getBaseData(c)
|
||||||
|
if postData.Thread.FirstID == postData.Post.ID {
|
||||||
|
baseData.Title = fmt.Sprintf("Deleting \"%s\" | %s", postData.Thread.Title, c.CurrentProject.Name)
|
||||||
|
} else {
|
||||||
|
baseData.Title = fmt.Sprintf("Deleting comment in \"%s\" | %s", postData.Thread.Title, c.CurrentProject.Name)
|
||||||
|
}
|
||||||
|
baseData.MathjaxEnabled = true
|
||||||
|
// TODO(ben): Set breadcrumbs
|
||||||
|
|
||||||
|
templatePost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
||||||
|
templatePost.AddContentVersion(postData.CurrentVersion, postData.Editor)
|
||||||
|
|
||||||
|
type blogPostDeleteData struct {
|
||||||
|
templates.BaseData
|
||||||
|
Post templates.Post
|
||||||
|
SubmitUrl string
|
||||||
|
}
|
||||||
|
|
||||||
|
var res ResponseData
|
||||||
|
res.MustWriteTemplate("blog_post_delete.html", blogPostDeleteData{
|
||||||
|
BaseData: baseData,
|
||||||
|
SubmitUrl: hmnurl.BuildBlogPostDelete(c.CurrentProject.Slug, cd.ThreadID, cd.PostID),
|
||||||
|
Post: templatePost,
|
||||||
|
}, c.Perf)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func BlogPostDeleteSubmit(c *RequestContext) ResponseData {
|
||||||
|
cd, ok := getCommonBlogData(c)
|
||||||
|
if !ok {
|
||||||
|
return FourOhFour(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !UserCanEditPost(c.Context(), c.Conn, *c.CurrentUser, cd.PostID) {
|
||||||
|
return FourOhFour(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := c.Conn.Begin(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer tx.Rollback(c.Context())
|
||||||
|
|
||||||
|
threadDeleted := DeletePost(c.Context(), tx, cd.ThreadID, cd.PostID)
|
||||||
|
|
||||||
|
err = tx.Commit(c.Context())
|
||||||
|
if err != nil {
|
||||||
|
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete post"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if threadDeleted {
|
||||||
|
projectUrl := hmnurl.BuildProjectHomepage(c.CurrentProject.Slug)
|
||||||
|
return c.Redirect(projectUrl, http.StatusSeeOther)
|
||||||
|
} else {
|
||||||
|
thread := FetchThread(c.Context(), c.Conn, cd.ThreadID)
|
||||||
|
threadUrl := hmnurl.BuildBlogThread(c.CurrentProject.Slug, thread.ID, thread.Title)
|
||||||
|
return c.Redirect(threadUrl, http.StatusSeeOther)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type commonBlogData struct {
|
type commonBlogData struct {
|
||||||
c *RequestContext
|
c *RequestContext
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ func Feed(c *RequestContext) ResponseData {
|
||||||
AND deleted = FALSE
|
AND deleted = FALSE
|
||||||
AND post.thread_id IS NOT NULL
|
AND post.thread_id IS NOT NULL
|
||||||
`,
|
`,
|
||||||
[]models.ThreadType{models.ThreadTypeForumPost, models.ThreadTypeProjectArticle},
|
[]models.ThreadType{models.ThreadTypeForumPost, models.ThreadTypeProjectBlogPost},
|
||||||
)
|
)
|
||||||
c.Perf.EndBlock()
|
c.Perf.EndBlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -339,7 +339,7 @@ func fetchAllPosts(c *RequestContext, lineageBuilder *models.SubforumLineageBuil
|
||||||
LIMIT $3 OFFSET $4
|
LIMIT $3 OFFSET $4
|
||||||
`,
|
`,
|
||||||
currentUserID,
|
currentUserID,
|
||||||
[]models.ThreadType{models.ThreadTypeForumPost, models.ThreadTypeProjectArticle},
|
[]models.ThreadType{models.ThreadTypeForumPost, models.ThreadTypeProjectBlogPost},
|
||||||
limit,
|
limit,
|
||||||
offset,
|
offset,
|
||||||
)
|
)
|
||||||
|
|
|
@ -634,16 +634,22 @@ func ForumNewThreadSubmit(c *RequestContext) ResponseData {
|
||||||
return FourOhFour(c)
|
return FourOhFour(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Req.ParseForm()
|
err = c.Req.ParseForm()
|
||||||
|
if err != nil {
|
||||||
|
return ErrorResponse(http.StatusBadRequest, oops.New(err, "the form data was invalid"))
|
||||||
|
}
|
||||||
title := c.Req.Form.Get("title")
|
title := c.Req.Form.Get("title")
|
||||||
unparsed := c.Req.Form.Get("body")
|
unparsed := c.Req.Form.Get("body")
|
||||||
sticky := false
|
sticky := false
|
||||||
if c.CurrentUser.IsStaff && c.Req.Form.Get("sticky") != "" {
|
if c.CurrentUser.IsStaff && c.Req.Form.Get("sticky") != "" {
|
||||||
sticky = true
|
sticky = true
|
||||||
}
|
}
|
||||||
|
if title == "" {
|
||||||
// TODO(ben): Validation (and error handling if ParseForm fails? might not need it since you'll get empty values)
|
return RejectRequest(c, "You must provide a title for your post.")
|
||||||
|
}
|
||||||
|
if unparsed == "" {
|
||||||
|
return RejectRequest(c, "You must provide a body for your post.")
|
||||||
|
}
|
||||||
|
|
||||||
// Create thread
|
// Create thread
|
||||||
var threadId int
|
var threadId int
|
||||||
|
@ -686,14 +692,14 @@ func ForumPostReply(c *RequestContext) ResponseData {
|
||||||
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
postData := FetchPostAndStuff(c.Context(), c.Conn, cd.ThreadID, cd.PostID)
|
||||||
|
|
||||||
baseData := getBaseData(c)
|
baseData := getBaseData(c)
|
||||||
baseData.Title = fmt.Sprintf("Replying to \"%s\" | %s", postData.Thread.Title, cd.SubforumTree[cd.SubforumID].Name)
|
baseData.Title = fmt.Sprintf("Replying to post | %s", cd.SubforumTree[cd.SubforumID].Name)
|
||||||
baseData.MathjaxEnabled = true
|
baseData.MathjaxEnabled = true
|
||||||
// TODO(ben): Set breadcrumbs
|
// TODO(ben): Set breadcrumbs
|
||||||
|
|
||||||
templatePost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
replyPost := templates.PostToTemplate(&postData.Post, postData.Author, c.Theme)
|
||||||
templatePost.AddContentVersion(postData.CurrentVersion, postData.Editor)
|
replyPost.AddContentVersion(postData.CurrentVersion, postData.Editor)
|
||||||
|
|
||||||
editData := getEditorDataForNew(baseData, &templatePost)
|
editData := getEditorDataForNew(baseData, &replyPost)
|
||||||
editData.SubmitUrl = hmnurl.BuildForumPostReply(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID)
|
editData.SubmitUrl = hmnurl.BuildForumPostReply(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID)
|
||||||
editData.SubmitLabel = "Submit Reply"
|
editData.SubmitLabel = "Submit Reply"
|
||||||
|
|
||||||
|
@ -714,9 +720,14 @@ func ForumPostReplySubmit(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
defer tx.Rollback(c.Context())
|
defer tx.Rollback(c.Context())
|
||||||
|
|
||||||
c.Req.ParseForm()
|
err = c.Req.ParseForm()
|
||||||
// TODO(ben): Validation
|
if err != nil {
|
||||||
|
return ErrorResponse(http.StatusBadRequest, oops.New(nil, "the form data was invalid"))
|
||||||
|
}
|
||||||
unparsed := c.Req.Form.Get("body")
|
unparsed := c.Req.Form.Get("body")
|
||||||
|
if unparsed == "" {
|
||||||
|
return RejectRequest(c, "Your reply cannot be empty.")
|
||||||
|
}
|
||||||
|
|
||||||
newPostId, _ := CreateNewPost(c.Context(), tx, c.CurrentProject.ID, cd.ThreadID, models.ThreadTypeForumPost, c.CurrentUser.ID, &cd.PostID, unparsed, c.Req.Host)
|
newPostId, _ := CreateNewPost(c.Context(), tx, c.CurrentProject.ID, cd.ThreadID, models.ThreadTypeForumPost, c.CurrentUser.ID, &cd.PostID, unparsed, c.Req.Host)
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ func Index(c *RequestContext) ResponseData {
|
||||||
`,
|
`,
|
||||||
currentUserId,
|
currentUserId,
|
||||||
proj.ID,
|
proj.ID,
|
||||||
[]models.ThreadType{models.ThreadTypeProjectArticle, models.ThreadTypeForumPost},
|
[]models.ThreadType{models.ThreadTypeProjectBlogPost, models.ThreadTypeForumPost},
|
||||||
maxPosts,
|
maxPosts,
|
||||||
)
|
)
|
||||||
c.Perf.EndBlock()
|
c.Perf.EndBlock()
|
||||||
|
@ -155,7 +155,7 @@ func Index(c *RequestContext) ResponseData {
|
||||||
}
|
}
|
||||||
|
|
||||||
featurable := (!proj.IsHMN() &&
|
featurable := (!proj.IsHMN() &&
|
||||||
projectPost.Post.ThreadType == models.ThreadTypeProjectArticle &&
|
projectPost.Post.ThreadType == models.ThreadTypeProjectBlogPost &&
|
||||||
projectPost.Thread.FirstID == projectPost.Post.ID &&
|
projectPost.Thread.FirstID == projectPost.Post.ID &&
|
||||||
landingPageProject.FeaturedPost == nil)
|
landingPageProject.FeaturedPost == nil)
|
||||||
|
|
||||||
|
@ -269,7 +269,7 @@ func Index(c *RequestContext) ResponseData {
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
`,
|
`,
|
||||||
models.HMNProjectID,
|
models.HMNProjectID,
|
||||||
models.ThreadTypeProjectArticle,
|
models.ThreadTypeProjectBlogPost,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch news post"))
|
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch news post"))
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
// NOTE(asaf): Please don't use this if you already know the kind of the post beforehand. Just call the appropriate build function.
|
// NOTE(asaf): Please don't use this if you already know the kind of the post beforehand. Just call the appropriate build function.
|
||||||
func UrlForGenericPost(thread *models.Thread, post *models.Post, lineageBuilder *models.SubforumLineageBuilder, projectSlug string) string {
|
func UrlForGenericPost(thread *models.Thread, post *models.Post, lineageBuilder *models.SubforumLineageBuilder, projectSlug string) string {
|
||||||
switch post.ThreadType {
|
switch post.ThreadType {
|
||||||
case models.ThreadTypeProjectArticle:
|
case models.ThreadTypeProjectBlogPost:
|
||||||
return hmnurl.BuildBlogThreadWithPostHash(projectSlug, post.ThreadID, thread.Title, post.ID)
|
return hmnurl.BuildBlogThreadWithPostHash(projectSlug, 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 hmnurl.BuildForumPost(projectSlug, lineageBuilder.GetSubforumLineageSlugs(*thread.SubforumID), post.ThreadID, post.ID)
|
||||||
|
@ -20,7 +20,7 @@ func UrlForGenericPost(thread *models.Thread, post *models.Post, lineageBuilder
|
||||||
|
|
||||||
var PostTypeMap = map[models.ThreadType][]templates.PostType{
|
var PostTypeMap = map[models.ThreadType][]templates.PostType{
|
||||||
// { First post , Subsequent post }
|
// { First post , Subsequent post }
|
||||||
models.ThreadTypeProjectArticle: {templates.PostTypeBlogPost, templates.PostTypeBlogComment},
|
models.ThreadTypeProjectBlogPost: {templates.PostTypeBlogPost, templates.PostTypeBlogComment},
|
||||||
models.ThreadTypeForumPost: {templates.PostTypeForumThread, templates.PostTypeForumReply},
|
models.ThreadTypeForumPost: {templates.PostTypeForumThread, templates.PostTypeForumReply},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,10 +166,16 @@ func NewWebsiteRoutes(conn *pgxpool.Pool, perfCollector *perf.PerfCollector) htt
|
||||||
mainRoutes.GET(hmnurl.RegexForumPostDelete, authMiddleware(ForumPostDelete))
|
mainRoutes.GET(hmnurl.RegexForumPostDelete, authMiddleware(ForumPostDelete))
|
||||||
mainRoutes.POST(hmnurl.RegexForumPostDelete, authMiddleware(csrfMiddleware(ForumPostDeleteSubmit)))
|
mainRoutes.POST(hmnurl.RegexForumPostDelete, authMiddleware(csrfMiddleware(ForumPostDeleteSubmit)))
|
||||||
|
|
||||||
|
mainRoutes.GET(hmnurl.RegexBlogNewThread, authMiddleware(BlogNewThread))
|
||||||
|
mainRoutes.POST(hmnurl.RegexBlogNewThread, authMiddleware(csrfMiddleware(BlogNewThreadSubmit)))
|
||||||
mainRoutes.GET(hmnurl.RegexBlogThread, BlogThread)
|
mainRoutes.GET(hmnurl.RegexBlogThread, BlogThread)
|
||||||
mainRoutes.GET(hmnurl.RegexBlogPost, BlogPostRedirectToThread)
|
mainRoutes.GET(hmnurl.RegexBlogPost, BlogPostRedirectToThread)
|
||||||
mainRoutes.GET(hmnurl.RegexBlogPostEdit, BlogPostEdit)
|
mainRoutes.GET(hmnurl.RegexBlogPostReply, authMiddleware(BlogPostReply))
|
||||||
mainRoutes.POST(hmnurl.RegexBlogPostEdit, BlogPostEditSubmit)
|
mainRoutes.POST(hmnurl.RegexBlogPostReply, authMiddleware(csrfMiddleware(BlogPostReplySubmit)))
|
||||||
|
mainRoutes.GET(hmnurl.RegexBlogPostEdit, authMiddleware(BlogPostEdit))
|
||||||
|
mainRoutes.POST(hmnurl.RegexBlogPostEdit, authMiddleware(csrfMiddleware(BlogPostEditSubmit)))
|
||||||
|
mainRoutes.GET(hmnurl.RegexBlogPostDelete, authMiddleware(BlogPostDelete))
|
||||||
|
mainRoutes.POST(hmnurl.RegexBlogPostDelete, authMiddleware(csrfMiddleware(BlogPostDeleteSubmit)))
|
||||||
|
|
||||||
mainRoutes.GET(hmnurl.RegexPodcast, PodcastIndex)
|
mainRoutes.GET(hmnurl.RegexPodcast, PodcastIndex)
|
||||||
mainRoutes.GET(hmnurl.RegexPodcastEdit, PodcastEdit)
|
mainRoutes.GET(hmnurl.RegexPodcastEdit, PodcastEdit)
|
||||||
|
|
|
@ -5,6 +5,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var ThreadTypeDisplayNames = map[models.ThreadType]string{
|
var ThreadTypeDisplayNames = map[models.ThreadType]string{
|
||||||
models.ThreadTypeProjectArticle: "Blog",
|
models.ThreadTypeProjectBlogPost: "Blog",
|
||||||
models.ThreadTypeForumPost: "Forums",
|
models.ThreadTypeForumPost: "Forums",
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,7 +241,7 @@ func CreateNewPost(
|
||||||
`,
|
`,
|
||||||
time.Now(),
|
time.Now(),
|
||||||
threadId,
|
threadId,
|
||||||
models.ThreadTypeForumPost,
|
threadType,
|
||||||
-1,
|
-1,
|
||||||
userId,
|
userId,
|
||||||
projectId,
|
projectId,
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
var TimelineTypeMap = map[models.ThreadType][]templates.TimelineType{
|
var TimelineTypeMap = map[models.ThreadType][]templates.TimelineType{
|
||||||
// { First post , Subsequent post }
|
// { First post , Subsequent post }
|
||||||
models.ThreadTypeProjectArticle: {templates.TimelineTypeBlogPost, templates.TimelineTypeBlogComment},
|
models.ThreadTypeProjectBlogPost: {templates.TimelineTypeBlogPost, templates.TimelineTypeBlogComment},
|
||||||
models.ThreadTypeForumPost: {templates.TimelineTypeForumThread, templates.TimelineTypeForumReply},
|
models.ThreadTypeForumPost: {templates.TimelineTypeForumThread, templates.TimelineTypeForumReply},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
func BuildProjectRootResourceUrl(projectSlug string, kind models.ThreadType) string {
|
func BuildProjectRootResourceUrl(projectSlug string, kind models.ThreadType) string {
|
||||||
switch kind {
|
switch kind {
|
||||||
case models.ThreadTypeProjectArticle:
|
case models.ThreadTypeProjectBlogPost:
|
||||||
return hmnurl.BuildBlog(projectSlug, 1)
|
return hmnurl.BuildBlog(projectSlug, 1)
|
||||||
case models.ThreadTypeForumPost:
|
case models.ThreadTypeForumPost:
|
||||||
return hmnurl.BuildForum(projectSlug, nil, 1)
|
return hmnurl.BuildForum(projectSlug, nil, 1)
|
||||||
|
|
Loading…
Reference in New Issue