Add permission check on post editing

This commit is contained in:
Ben Visness 2021-07-21 21:16:10 -05:00
parent 27b8157a89
commit e9ba9b3dde
10 changed files with 103 additions and 24 deletions

View File

@ -0,0 +1,44 @@
package migrations
import (
"context"
"time"
"git.handmade.network/hmn/hmn/src/migration/types"
"git.handmade.network/hmn/hmn/src/oops"
"github.com/jackc/pgx/v4"
)
func init() {
registerMigration(DropSuperuserColumn{})
}
type DropSuperuserColumn struct{}
func (m DropSuperuserColumn) Version() types.MigrationVersion {
return types.MigrationVersion(time.Date(2021, 7, 22, 1, 59, 29, 0, time.UTC))
}
func (m DropSuperuserColumn) Name() string {
return "DropSuperuserColumn"
}
func (m DropSuperuserColumn) Description() string {
return "Drop the is_superuser column on users, in favor of is_staff"
}
func (m DropSuperuserColumn) Up(ctx context.Context, tx pgx.Tx) error {
_, err := tx.Exec(ctx, `
ALTER TABLE auth_user
DROP is_superuser;
`)
if err != nil {
return oops.New(err, "failed to drop superuser column")
}
return nil
}
func (m DropSuperuserColumn) Down(ctx context.Context, tx pgx.Tx) error {
panic("Implement me")
}

View File

@ -17,9 +17,8 @@ type User struct {
DateJoined time.Time `db:"date_joined"`
LastLogin *time.Time `db:"last_login"`
IsSuperuser bool `db:"is_superuser"`
IsStaff bool `db:"is_staff"`
IsActive bool `db:"is_active"`
IsStaff bool `db:"is_staff"`
IsActive bool `db:"is_active"`
Name string `db:"name"`
Bio string `db:"bio"`

View File

@ -157,11 +157,10 @@ func UserToTemplate(u *models.User, currentTheme string) User {
}
return User{
ID: u.ID,
Username: u.Username,
Email: email,
IsSuperuser: u.IsSuperuser,
IsStaff: u.IsStaff,
ID: u.ID,
Username: u.Username,
Email: email,
IsStaff: u.IsStaff,
Name: UserDisplayName(u),
Blurb: u.Blurb,

View File

@ -19,8 +19,8 @@
{{ define "content" }}
<div class="content-block ph3 ph0-ns">
{{ if .ThreadTitle }}
<h2>{{ .ThreadTitle }}</h2>
{{ if .Title }}
<h2>{{ .Title }}</h2>
{{ end }}
<div class="flex flex-column flex-row-ns">
<form id="form" action="{{ .SubmitUrl }}" method="post" class="flex-fair-ns">

View File

@ -1,7 +1,7 @@
<header class="mb3">
<div class="user-options flex justify-center justify-end-ns">
{{ if .User }}
{{ if .User.IsSuperuser }}
{{ if .User.IsStaff }}
<a class="admin-panel" href="{{ .Header.AdminUrl }}"><span class="icon-settings"> Admin</span></a>
{{ end }}
<a class="username settings" href="{{ .Header.UserSettingsUrl }}"><span class="icon-settings"></span> {{ .User.Username }}</a>

View File

@ -117,11 +117,10 @@ type Project struct {
}
type User struct {
ID int
Username string
Email string
IsSuperuser bool
IsStaff bool
ID int
Username string
Email string
IsStaff bool
Name string
Blurb string

View File

@ -41,7 +41,7 @@ type forumSubcategoryData struct {
type editorData struct {
templates.BaseData
SubmitUrl string
ThreadTitle string
Title string
SubmitLabel string
IsEditing bool // false if new post, true if updating existing one
@ -710,7 +710,7 @@ func ForumPostReply(c *RequestContext) ResponseData {
SubmitUrl: hmnurl.BuildForumPostReply(c.CurrentProject.Slug, lineageBuilder.GetSubforumLineageSlugs(currentCatId), requestedThreadId, requestedPostId),
SubmitLabel: "Submit Reply",
ThreadTitle: result.Thread.Title,
Title: "Replying to post",
PostReplyingTo: &templatePost,
}, c.Perf)
return res
@ -820,6 +820,12 @@ func ForumPostEdit(c *RequestContext) ResponseData {
}
result := postQueryResult.(*postQuery)
// Ensure that the user is permitted to edit the post
isPostAuthor := result.Author != nil && result.Author.ID == c.CurrentUser.ID
if !(isPostAuthor || c.CurrentUser.IsStaff) {
return FourOhFour(c)
}
baseData := getBaseData(c)
baseData.Title = fmt.Sprintf("Editing \"%s\" | %s", result.Thread.Title, *categoryTree[currentCatId].Name)
baseData.MathjaxEnabled = true
@ -832,7 +838,7 @@ func ForumPostEdit(c *RequestContext) ResponseData {
res.MustWriteTemplate("editor.html", editorData{
BaseData: baseData,
SubmitUrl: hmnurl.BuildForumPostEdit(c.CurrentProject.Slug, lineageBuilder.GetSubforumLineageSlugs(currentCatId), requestedThreadId, requestedPostId),
ThreadTitle: result.Thread.Title,
Title: result.Thread.Title,
SubmitLabel: "Submit Edited Post",
IsEditing: true,
@ -868,8 +874,38 @@ func ForumPostEditSubmit(c *RequestContext) ResponseData {
return FourOhFour(c)
}
c.Req.ParseForm()
// Ensure that the user is permitted to edit the post
type postResult struct {
AuthorID *int `db:"author.id"`
}
iresult, err := db.QueryOne(c.Context(), c.Conn, postResult{},
`
SELECT $columns
FROM
handmade_post AS post
LEFT JOIN auth_user AS author ON post.author_id = author.id
WHERE
post.category_id = $1
AND post.thread_id = $2
AND post.id = $3
AND NOT post.deleted
ORDER BY postdate
`,
currentCatId,
threadId,
postId,
)
if err != nil && !errors.Is(err, db.ErrNoMatchingRows) {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get author of post to delete"))
}
result := iresult.(*postResult)
isPostAuthor := result.AuthorID != nil && *result.AuthorID == c.CurrentUser.ID
if !(isPostAuthor || c.CurrentUser.IsStaff) {
return FourOhFour(c)
}
c.Req.ParseForm()
unparsed := c.Req.Form.Get("body")
editReason := c.Req.Form.Get("editreason")
@ -888,8 +924,8 @@ func createNewForumPostAndVersion(ctx context.Context, tx pgx.Tx, catId, threadI
// Create post
err := tx.QueryRow(ctx,
`
INSERT INTO handmade_post (postdate, category_id, thread_id, current_id, author_id, category_kind, project_id, reply_id)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
INSERT INTO handmade_post (postdate, category_id, thread_id, current_id, author_id, category_kind, project_id, reply_id, preview)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING id
`,
time.Now(),
@ -900,6 +936,7 @@ func createNewForumPostAndVersion(ctx context.Context, tx pgx.Tx, catId, threadI
models.CatKindForum,
projectId,
replyId,
"", // empty preview, will be updated later
).Scan(&postId)
if err != nil {
panic(oops.New(err, "failed to create post"))

View File

@ -288,7 +288,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
canView := false
canEdit := false
if c.CurrentUser != nil {
if c.CurrentUser.IsSuperuser {
if c.CurrentUser.IsStaff {
canView = true
canEdit = true
} else {

View File

@ -162,6 +162,7 @@ func NewWebsiteRoutes(conn *pgxpool.Pool, perfCollector *perf.PerfCollector) htt
mainRoutes.POST(hmnurl.RegexForumPostReply, authMiddleware(ForumPostReplySubmit))
mainRoutes.GET(hmnurl.RegexForumPostEdit, authMiddleware(ForumPostEdit))
mainRoutes.POST(hmnurl.RegexForumPostEdit, authMiddleware(ForumPostEditSubmit))
// mainRoutes.GET(hmnurl.RegexForumPostDelete, authMiddleware(ForumPostDelete))
mainRoutes.GET(hmnurl.RegexProjectCSS, ProjectCSS)

View File

@ -100,7 +100,7 @@ func UserProfile(c *RequestContext) ResponseData {
AND ($2 OR (project.flags = 0 AND project.lifecycle = ANY ($3)))
`,
profileUser.ID,
(c.CurrentUser != nil && (profileUser == c.CurrentUser || c.CurrentUser.IsSuperuser)),
(c.CurrentUser != nil && (profileUser == c.CurrentUser || c.CurrentUser.IsStaff)),
models.VisibleProjectLifecycles,
)
if err != nil {