Disable forum/blog actions for projects that don't have them enabled
I implemented this for personal projects, but I think it was actually affecting official projects too that didn't have forums or blogs enabled.
This commit is contained in:
parent
702036eac3
commit
c6387e2885
|
@ -67,7 +67,7 @@ type Project struct {
|
|||
|
||||
ForumEnabled bool `db:"forum_enabled"`
|
||||
BlogEnabled bool `db:"blog_enabled"`
|
||||
LibraryEnabled bool `db:"library_enabled"`
|
||||
LibraryEnabled bool `db:"library_enabled"` // TODO: Delete this field from the db
|
||||
}
|
||||
|
||||
func (p *Project) IsHMN() bool {
|
||||
|
@ -82,6 +82,19 @@ func (p *Project) Subdomain() string {
|
|||
return p.Slug
|
||||
}
|
||||
|
||||
// Checks whether the project has forums enabled. This should restrict the creation of new forum
|
||||
// content, but it should NOT prevent the viewing of existing forum content. (Projects may at one
|
||||
// point have forums enabled, write some stuff, and then later disable forums, and we want that
|
||||
// content to stay accessible.) Hiding the navigation is ok.
|
||||
func (p *Project) HasForums() bool {
|
||||
return !p.Personal && p.ForumEnabled
|
||||
}
|
||||
|
||||
// Same as HasForums, but for blogs.
|
||||
func (p *Project) HasBlog() bool {
|
||||
return !p.Personal && p.BlogEnabled
|
||||
}
|
||||
|
||||
var slugUnsafeChars = regexp.MustCompile(`[^a-zA-Z0-9-]`)
|
||||
var slugHyphenRun = regexp.MustCompile(`-+`)
|
||||
|
||||
|
|
|
@ -80,8 +80,8 @@ func ProjectToTemplate(p *models.Project, url string, theme string) Project {
|
|||
|
||||
IsHMN: p.IsHMN(),
|
||||
|
||||
HasBlog: p.BlogEnabled,
|
||||
HasForum: p.ForumEnabled,
|
||||
HasBlog: p.HasBlog(),
|
||||
HasForum: p.HasForums(),
|
||||
|
||||
DateApproved: p.DateApproved,
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{ if $.User }}
|
||||
{{ if and $.User $.Project.HasBlog }}
|
||||
<div class="flex">
|
||||
{{ if or (eq .Author.ID $.User.ID) $.User.IsStaff }}
|
||||
<a class="delete action button" href="{{ .DeleteUrl }}" title="Delete">✖</a>
|
||||
|
@ -81,7 +81,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{{ if $.User }}
|
||||
{{ if and $.User $.Project.HasBlog }}
|
||||
<div class="flex">
|
||||
{{ if or (eq .Author.ID $.User.ID) $.User.IsStaff }}
|
||||
<a class="delete action button" href="{{ .DeleteUrl }}" title="Delete">✖</a>
|
||||
|
@ -111,11 +111,13 @@
|
|||
|
||||
<div class="optionbar bottom">
|
||||
<div class="options">
|
||||
{{ if .Project.HasBlog }}
|
||||
{{ if $.User }}
|
||||
<a class="button" href="{{ .ReplyLink }}"><span class="big pr1">+</span> Add Comment</a>
|
||||
{{ else }}
|
||||
<a class="button" href="{{ .LoginLink }}">Log in to comment</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -34,14 +34,18 @@
|
|||
|
||||
{{ define "subforum_options" }}
|
||||
<div class="options">
|
||||
{{ if .Project.HasForum }}
|
||||
{{ if .User }}
|
||||
<a class="button new-thread" href="{{ .NewThreadUrl }}"><span class="big pr1">+</span> New Thread</a>
|
||||
{{ else }}
|
||||
<a class="button" href="{{ .LoginPageUrl }}">Log in to post a new thread</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if .User }}
|
||||
<form method="POST" action="{{ .MarkReadUrl }}">
|
||||
{{ csrftoken .Session }}
|
||||
<button type="submit"><span class="big pr1">✓</span> Mark threads here as read</button>
|
||||
</form>
|
||||
{{ else }}
|
||||
<a class="button" href="{{ .LoginPageUrl }}">Log in to post a new thread</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="options">
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
<div class="postid">
|
||||
<a name="{{ .ID }}" href="{{ .Url }}">#{{ .ID }}</a>
|
||||
</div>
|
||||
{{ if $.User }}
|
||||
{{ if and $.User $.Project.HasForum }}
|
||||
<div class="flex pr3">
|
||||
{{ if or (eq .Author.ID $.User.ID) $.User.IsStaff }}
|
||||
<a class="delete action button" href="{{ .DeleteUrl }}" title="Delete">✖</a>
|
||||
|
@ -120,11 +120,13 @@
|
|||
<a class="button" href="{{ .SubforumUrl }}">← Back to index</a>
|
||||
{{ if .Thread.Locked }}
|
||||
<span>Thread is locked.</span>
|
||||
{{ else if .User }}
|
||||
{{ else if .Project.HasForum }}
|
||||
{{ if .User }}
|
||||
<a class="button" href="{{ .ReplyUrl }}">⤷ Reply to Thread</a>
|
||||
{{ else }}
|
||||
<span class="pa2"><a href="{{ .LoginPageUrl }}">Log in</a> to reply</span>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="options order-0 order-last-ns">
|
||||
{{ template "pagination.html" .Pagination }}
|
||||
|
|
|
@ -94,8 +94,8 @@ func getBaseData(c *RequestContext, title string, breadcrumbs []templates.Breadc
|
|||
}
|
||||
|
||||
baseData.Header.Project = &templates.ProjectHeader{
|
||||
HasForums: c.CurrentProject.ForumEnabled,
|
||||
HasBlog: c.CurrentProject.BlogEnabled,
|
||||
HasForums: c.CurrentProject.HasForums(),
|
||||
HasBlog: c.CurrentProject.HasBlog(),
|
||||
HasEpisodeGuide: hasAnnotations,
|
||||
ForumsUrl: c.UrlContext.BuildForum(nil, 1),
|
||||
BlogUrl: c.UrlContext.BuildBlog(1),
|
||||
|
|
|
@ -35,7 +35,7 @@ func BlogIndex(c *RequestContext) ResponseData {
|
|||
|
||||
const postsPerPage = 5
|
||||
|
||||
numPosts, err := CountPosts(c.Context(), c.Conn, c.CurrentUser, PostsQuery{
|
||||
numThreads, err := CountThreads(c.Context(), c.Conn, c.CurrentUser, ThreadsQuery{
|
||||
ProjectIDs: []int{c.CurrentProject.ID},
|
||||
ThreadTypes: []models.ThreadType{models.ThreadTypeProjectBlogPost},
|
||||
})
|
||||
|
@ -43,7 +43,7 @@ func BlogIndex(c *RequestContext) ResponseData {
|
|||
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch total number of blog posts"))
|
||||
}
|
||||
|
||||
numPages := utils.NumPages(numPosts, postsPerPage)
|
||||
numPages := utils.NumPages(numThreads, postsPerPage)
|
||||
page, ok := ParsePageNumber(c, "page", numPages)
|
||||
if !ok {
|
||||
c.Redirect(c.UrlContext.BuildBlog(page), http.StatusSeeOther)
|
||||
|
@ -73,7 +73,7 @@ func BlogIndex(c *RequestContext) ResponseData {
|
|||
baseData := getBaseData(c, fmt.Sprintf("%s Blog", c.CurrentProject.Name), []templates.Breadcrumb{BlogBreadcrumb(c.UrlContext)})
|
||||
|
||||
canCreate := false
|
||||
if c.CurrentUser != nil {
|
||||
if c.CurrentProject.HasBlog() && c.CurrentUser != nil {
|
||||
isProjectOwner := false
|
||||
owners, err := FetchProjectOwners(c.Context(), c.Conn, c.CurrentProject.ID)
|
||||
if err != nil {
|
||||
|
|
|
@ -216,7 +216,6 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
|
|||
|
||||
hmnOnly.GET(hmnurl.RegexLibraryAny, LibraryNotPortedYet)
|
||||
|
||||
// NOTE(asaf): Any-project routes:
|
||||
attachProjectRoutes := func(rb *RouteBuilder) {
|
||||
rb.GET(hmnurl.RegexHomepage, func(c *RequestContext) ResponseData {
|
||||
if c.CurrentProject.IsHMN() {
|
||||
|
@ -226,31 +225,53 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
|
|||
}
|
||||
})
|
||||
|
||||
rb.POST(hmnurl.RegexForumNewThreadSubmit, authMiddleware(csrfMiddleware(ForumNewThreadSubmit)))
|
||||
rb.GET(hmnurl.RegexForumNewThread, authMiddleware(ForumNewThread))
|
||||
// Middleware used for forum action routes - anything related to actually creating or editing forum content
|
||||
needsForums := func(h Handler) Handler {
|
||||
return func(c *RequestContext) ResponseData {
|
||||
// 404 if the project has forums disabled
|
||||
if !c.CurrentProject.HasForums() {
|
||||
return FourOhFour(c)
|
||||
}
|
||||
// Require auth if forums are enabled
|
||||
return authMiddleware(h)(c)
|
||||
}
|
||||
}
|
||||
rb.POST(hmnurl.RegexForumNewThreadSubmit, needsForums(csrfMiddleware(ForumNewThreadSubmit)))
|
||||
rb.GET(hmnurl.RegexForumNewThread, needsForums(ForumNewThread))
|
||||
rb.GET(hmnurl.RegexForumThread, ForumThread)
|
||||
rb.GET(hmnurl.RegexForum, Forum)
|
||||
rb.POST(hmnurl.RegexForumMarkRead, authMiddleware(csrfMiddleware(ForumMarkRead)))
|
||||
rb.POST(hmnurl.RegexForumMarkRead, authMiddleware(csrfMiddleware(ForumMarkRead))) // needs auth but doesn't need forums enabled
|
||||
rb.GET(hmnurl.RegexForumPost, ForumPostRedirect)
|
||||
rb.GET(hmnurl.RegexForumPostReply, authMiddleware(ForumPostReply))
|
||||
rb.POST(hmnurl.RegexForumPostReply, authMiddleware(csrfMiddleware(ForumPostReplySubmit)))
|
||||
rb.GET(hmnurl.RegexForumPostEdit, authMiddleware(ForumPostEdit))
|
||||
rb.POST(hmnurl.RegexForumPostEdit, authMiddleware(csrfMiddleware(ForumPostEditSubmit)))
|
||||
rb.GET(hmnurl.RegexForumPostDelete, authMiddleware(ForumPostDelete))
|
||||
rb.POST(hmnurl.RegexForumPostDelete, authMiddleware(csrfMiddleware(ForumPostDeleteSubmit)))
|
||||
rb.GET(hmnurl.RegexForumPostReply, needsForums(ForumPostReply))
|
||||
rb.POST(hmnurl.RegexForumPostReply, needsForums(csrfMiddleware(ForumPostReplySubmit)))
|
||||
rb.GET(hmnurl.RegexForumPostEdit, needsForums(ForumPostEdit))
|
||||
rb.POST(hmnurl.RegexForumPostEdit, needsForums(csrfMiddleware(ForumPostEditSubmit)))
|
||||
rb.GET(hmnurl.RegexForumPostDelete, needsForums(ForumPostDelete))
|
||||
rb.POST(hmnurl.RegexForumPostDelete, needsForums(csrfMiddleware(ForumPostDeleteSubmit)))
|
||||
rb.GET(hmnurl.RegexWikiArticle, WikiArticleRedirect)
|
||||
|
||||
// Middleware used for blog action routes - anything related to actually creating or editing blog content
|
||||
needsBlogs := func(h Handler) Handler {
|
||||
return func(c *RequestContext) ResponseData {
|
||||
// 404 if the project has blogs disabled
|
||||
if !c.CurrentProject.HasBlog() {
|
||||
return FourOhFour(c)
|
||||
}
|
||||
// Require auth if blogs are enabled
|
||||
return authMiddleware(h)(c)
|
||||
}
|
||||
}
|
||||
rb.GET(hmnurl.RegexBlog, BlogIndex)
|
||||
rb.GET(hmnurl.RegexBlogNewThread, authMiddleware(BlogNewThread))
|
||||
rb.POST(hmnurl.RegexBlogNewThread, authMiddleware(csrfMiddleware(BlogNewThreadSubmit)))
|
||||
rb.GET(hmnurl.RegexBlogNewThread, needsBlogs(BlogNewThread))
|
||||
rb.POST(hmnurl.RegexBlogNewThread, needsBlogs(csrfMiddleware(BlogNewThreadSubmit)))
|
||||
rb.GET(hmnurl.RegexBlogThread, BlogThread)
|
||||
rb.GET(hmnurl.RegexBlogPost, BlogPostRedirectToThread)
|
||||
rb.GET(hmnurl.RegexBlogPostReply, authMiddleware(BlogPostReply))
|
||||
rb.POST(hmnurl.RegexBlogPostReply, authMiddleware(csrfMiddleware(BlogPostReplySubmit)))
|
||||
rb.GET(hmnurl.RegexBlogPostEdit, authMiddleware(BlogPostEdit))
|
||||
rb.POST(hmnurl.RegexBlogPostEdit, authMiddleware(csrfMiddleware(BlogPostEditSubmit)))
|
||||
rb.GET(hmnurl.RegexBlogPostDelete, authMiddleware(BlogPostDelete))
|
||||
rb.POST(hmnurl.RegexBlogPostDelete, authMiddleware(csrfMiddleware(BlogPostDeleteSubmit)))
|
||||
rb.GET(hmnurl.RegexBlogPostReply, needsBlogs(BlogPostReply))
|
||||
rb.POST(hmnurl.RegexBlogPostReply, needsBlogs(csrfMiddleware(BlogPostReplySubmit)))
|
||||
rb.GET(hmnurl.RegexBlogPostEdit, needsBlogs(BlogPostEdit))
|
||||
rb.POST(hmnurl.RegexBlogPostEdit, needsBlogs(csrfMiddleware(BlogPostEditSubmit)))
|
||||
rb.GET(hmnurl.RegexBlogPostDelete, needsBlogs(BlogPostDelete))
|
||||
rb.POST(hmnurl.RegexBlogPostDelete, needsBlogs(csrfMiddleware(BlogPostDeleteSubmit)))
|
||||
rb.GET(hmnurl.RegexBlogsRedirect, func(c *RequestContext) ResponseData {
|
||||
return c.Redirect(c.UrlContext.Url(
|
||||
fmt.Sprintf("blog%s", c.PathParams["remainder"]), nil,
|
||||
|
|
Loading…
Reference in New Issue