Minor improvements

* Add a "Report" link to the footer of forums.
* Allow some non-admin users to view a private forum and its threads.
  * Moderators and approved followers can see it
  * Note: the endpoint to follow a forum won't let a user invite themselves
    to a private forum. Currently there is no way to approve a user except
    by also adding them as a moderator.
  * Explore and Newest tabs can show these private forums if viewable.
This commit is contained in:
Noah Petherbridge 2024-08-21 23:06:06 -07:00
parent d765fde6cd
commit 170cd11f9c
10 changed files with 73 additions and 13 deletions

View File

@ -99,6 +99,7 @@ var (
{"report.photo", "Report a problematic photo"}, {"report.photo", "Report a problematic photo"},
{"report.message", "Report a direct message conversation"}, {"report.message", "Report a direct message conversation"},
{"report.comment", "Report a forum post or comment"}, {"report.comment", "Report a forum post or comment"},
{"report.forum", "Report a forum or community"},
}, },
}, },
} }

View File

@ -102,6 +102,15 @@ func Feedback() http.HandlerFunc {
return return
} }
} }
case "forums":
// Get this forum.
forum, err := models.GetForum(fb.TableID)
if err != nil {
session.FlashError(w, r, "Couldn't get comment ID %d: %s", fb.TableID, err)
} else {
templates.Redirect(w, fmt.Sprintf("/f/%s", forum.Fragment))
return
}
default: default:
session.FlashError(w, r, "Couldn't visit TableID %s/%d: not a supported TableName", fb.TableName, fb.TableID) session.FlashError(w, r, "Couldn't visit TableID %s/%d: not a supported TableName", fb.TableName, fb.TableID)
} }

View File

@ -18,6 +18,8 @@ func Explore() http.HandlerFunc {
var sortWhitelist = []string{ var sortWhitelist = []string{
"title asc", "title asc",
"title desc", "title desc",
"created_at desc",
"created_at asc",
} }
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

View File

@ -35,14 +35,14 @@ func Subscribe() http.HandlerFunc {
return return
} }
switch intent {
case "follow":
// Is it a private forum? // Is it a private forum?
if forum.Private && !currentUser.IsAdmin { if forum.Private && !currentUser.IsAdmin {
templates.NotFoundPage(w, r) templates.NotFoundPage(w, r)
return return
} }
switch intent {
case "follow":
_, err := models.CreateForumMembership(currentUser, forum) _, err := models.CreateForumMembership(currentUser, forum)
if err != nil { if err != nil {
session.FlashError(w, r, "Couldn't follow this forum: %s", err) session.FlashError(w, r, "Couldn't follow this forum: %s", err)

View File

@ -83,6 +83,15 @@ func Contact() http.HandlerFunc {
} else { } else {
log.Error("/contact: couldn't produce table label for comment %d: %s", tableID, err) log.Error("/contact: couldn't produce table label for comment %d: %s", tableID, err)
} }
case "report.forum":
tableName = "forums"
// Find this forum.
if forum, err := models.GetForum(uint64(tableID)); err == nil {
tableLabel = fmt.Sprintf(`The forum "%s" (/f/%s)`, forum.Title, forum.Fragment)
} else {
log.Error("/contact: couldn't produce table label for comment %d: %s", tableID, err)
}
} }
} }

View File

@ -104,9 +104,24 @@ func PaginateForums(user *User, categories []string, search *Search, subscribed
wheres = append(wheres, "explicit = false") wheres = append(wheres, "explicit = false")
} }
// Hide private forums except for admins. // Hide private forums except for admins and approved users.
if !user.IsAdmin { if !user.IsAdmin {
wheres = append(wheres, "private is not true") wheres = append(wheres, `
(
private IS NOT TRUE
OR EXISTS (
SELECT 1
FROM forum_memberships
WHERE forum_id = forums.id
AND user_id = ?
AND (
is_moderator IS TRUE
OR approved IS TRUE
)
)
)`,
)
placeholders = append(placeholders, user.ID)
} }
// Followed forums only? (for the My List category on home page) // Followed forums only? (for the My List category on home page)

View File

@ -49,7 +49,22 @@ func PaginateRecentPosts(user *User, categories []string, subscribed, allComment
// Private forums. // Private forums.
if !user.IsAdmin { if !user.IsAdmin {
wheres = append(wheres, "forums.private is not true") wheres = append(wheres, `
(
forums.private IS NOT TRUE
OR EXISTS (
SELECT 1
FROM forum_memberships
WHERE forum_id = forums.id
AND user_id = ?
AND (
is_moderator IS TRUE
OR approved IS TRUE
)
)
)`,
)
placeholders = append(placeholders, user.ID)
} }
// Forums I follow? // Forums I follow?

View File

@ -595,7 +595,7 @@
Your <strong>certification photo</strong> was rejected! Your <strong>certification photo</strong> was rejected!
</span> </span>
{{else if eq .Type "forum_moderator"}} {{else if eq .Type "forum_moderator"}}
<span class="icon"><i class="fa fa-peace has-text-success"></i></span> <span class="icon"><i class="fa fa-user-tie has-text-success"></i></span>
<span> <span>
You have been appointed as a <strong class="has-text-success">moderator</strong> You have been appointed as a <strong class="has-text-success">moderator</strong>
for the forum <a href="/f/{{$Body.Forum.Fragment}}">{{$Body.Forum.Title}}</a>! for the forum <a href="/f/{{$Body.Forum.Fragment}}">{{$Body.Forum.Title}}</a>!

View File

@ -197,9 +197,9 @@
<div class="block p-2"> <div class="block p-2">
<div class="box"> <div class="box">
<label class="label">Forum Info</label> <label class="label"><i class="fa fa-info-circle"></i> Forum Info</label>
<div class="mb-4"> <div class="mb-4">
Created: <span title="{{.Forum.CreatedAt}}">{{.Forum.CreatedAt.Format "Jan _2 2006"}}</span> Created on: <span title="{{.Forum.CreatedAt}}">{{.Forum.CreatedAt.Format "Jan _2 2006"}}</span>
<div class="mt-2"> <div class="mt-2">
{{if .Forum.Explicit}} {{if .Forum.Explicit}}
<span class="tag is-danger is-light"> <span class="tag is-danger is-light">
@ -231,7 +231,7 @@
</div> </div>
</div> </div>
<label class="label">Forum Moderators</label> <label class="label"><i class="fa fa-user-tie"></i> Forum Moderators</label>
<!-- The owner first --> <!-- The owner first -->
{{template "avatar-16x16" .Forum.Owner}} {{template "avatar-16x16" .Forum.Owner}}
@ -249,6 +249,14 @@
</a> </a>
</span> </span>
{{end}} {{end}}
<div class="columns is-multiline is-mobile mt-4 is-size-7">
<div class="column is-narrow">
<a href="/contact?intent=report&subject=report.forum&id={{.Forum.ID}}" class="has-text-danger">
<i class="fa fa-flag"></i> Report this forum
</a>
</div>
</div>
</div> </div>
</div> </div>

View File

@ -87,6 +87,7 @@
<select id="sort" name="sort"> <select id="sort" name="sort">
<option value="title asc"{{if eq .Sort "title asc"}} selected{{end}}>Title (A-Z)</option> <option value="title asc"{{if eq .Sort "title asc"}} selected{{end}}>Title (A-Z)</option>
<option value="title desc"{{if eq .Sort "title desc"}} selected{{end}}>Title (Z-A)</option> <option value="title desc"{{if eq .Sort "title desc"}} selected{{end}}>Title (Z-A)</option>
<option value="created_at desc"{{if eq .Sort "created_at desc"}} selected{{end}}>Recently created</option>
</select> </select>
</div> </div>
</div> </div>