diff --git a/api/comment_delete.go b/api/comment_delete.go index 81b8a77..69d0373 100644 --- a/api/comment_delete.go +++ b/api/comment_delete.go @@ -2,19 +2,26 @@ package main import ( "net/http" + "time" ) -func commentDelete(commentHex string) error { - if commentHex == "" { +func commentDelete(commentHex string, deleterHex string) error { + if commentHex == "" || deleterHex == "" { return errorMissingField } statement := ` UPDATE comments - SET deleted = true, markdown = '[deleted]', html = '[deleted]', commenterHex = 'anonymous' + SET + deleted = true, + markdown = '[deleted]', + html = '[deleted]', + commenterHex = 'anonymous', + deleterHex = $2, + deletionDate = $3 WHERE commentHex = $1; ` - _, err := db.Exec(statement, commentHex) + _, err := db.Exec(statement, commentHex, deleterHex, time.Now().UTC()) if err != nil { // TODO: make sure this is the error is actually non-existant commentHex @@ -65,7 +72,7 @@ func commentDeleteHandler(w http.ResponseWriter, r *http.Request) { return } - if err = commentDelete(*x.CommentHex); err != nil { + if err = commentDelete(*x.CommentHex, c.CommenterHex); err != nil { bodyMarshal(w, response{"success": false, "message": err.Error()}) return } diff --git a/api/comment_delete_test.go b/api/comment_delete_test.go index 14e77c7..cbaa1ab 100644 --- a/api/comment_delete_test.go +++ b/api/comment_delete_test.go @@ -8,15 +8,16 @@ import ( func TestCommentDeleteBasics(t *testing.T) { failTestOnError(t, setupTestEnv()) - commentHex, _ := commentNew("temp-commenter-hex", "example.com", "/path.html", "root", "**foo**", "approved", time.Now().UTC()) - commentNew("temp-commenter-hex", "example.com", "/path.html", commentHex, "**bar**", "approved", time.Now().UTC()) + commenterHex = "temp-commenter-hex" + commentHex, _ := commentNew(commenterHex, "example.com", "/path.html", "root", "**foo**", "approved", time.Now().UTC()) + commentNew(commenterHex, "example.com", "/path.html", commentHex, "**bar**", "approved", time.Now().UTC()) - if err := commentDelete(commentHex); err != nil { + if err := commentDelete(commentHex, commenterHex); err != nil { t.Errorf("unexpected error deleting comment: %v", err) return } - c, _, _ := commentList("temp-commenter-hex", "example.com", "/path.html", false) + c, _, _ := commentList(commenterHex, "example.com", "/path.html", false) if len(c) != 0 { t.Errorf("expected no comments found %d comments", len(c)) @@ -27,7 +28,7 @@ func TestCommentDeleteBasics(t *testing.T) { func TestCommentDeleteEmpty(t *testing.T) { failTestOnError(t, setupTestEnv()) - if err := commentDelete(""); err == nil { + if err := commentDelete("", "test-commenter-hex"); err == nil { t.Errorf("expected error deleting comment with empty commentHex") return } diff --git a/api/email_moderate.go b/api/email_moderate.go index 3cefb3d..3fa3a34 100644 --- a/api/email_moderate.go +++ b/api/email_moderate.go @@ -7,18 +7,7 @@ import ( func emailModerateHandler(w http.ResponseWriter, r *http.Request) { unsubscribeSecretHex := r.FormValue("unsubscribeSecretHex") - e, err := emailGetByUnsubscribeSecretHex(unsubscribeSecretHex) - if err != nil { - fmt.Fprintf(w, "error: %v", err.Error()) - return - } - action := r.FormValue("action") - if action != "delete" && action != "approve" { - fmt.Fprintf(w, "error: invalid action") - return - } - commentHex := r.FormValue("commentHex") if commentHex == "" { fmt.Fprintf(w, "error: invalid commentHex") @@ -26,23 +15,35 @@ func emailModerateHandler(w http.ResponseWriter, r *http.Request) { } statement := ` - SELECT domain + SELECT domain, deleted FROM comments WHERE commentHex = $1; ` row := db.QueryRow(statement, commentHex) var domain string - if err = row.Scan(&domain); err != nil { + var deleted bool + if err := row.Scan(&domain, &deleted); err != nil { // TODO: is this the only error? fmt.Fprintf(w, "error: no such comment found (perhaps it has been deleted?)") return } + if deleted { + fmt.Fprintf(w, "error: that comment has already been deleted") + return + } + + e, err := emailGetByUnsubscribeSecretHex(unsubscribeSecretHex) + if err != nil { + fmt.Fprintf(w, "error: %v", err.Error()) + return + } + isModerator, err := isDomainModerator(domain, e.Email) if err != nil { logger.Errorf("error checking if %s is a moderator: %v", e.Email, err) - fmt.Fprintf(w, "error checking if %s is a moderator: %v", e.Email, err) + fmt.Fprintf(w, "error: %v", errorInternal) return } @@ -51,10 +52,31 @@ func emailModerateHandler(w http.ResponseWriter, r *http.Request) { return } - if action == "approve" { + // Do not use commenterGetByEmail here because we don't know which provider + // should be used. This was poor design on multiple fronts on my part, but + // let's deal with that later. For now, it suffices to match the + // deleter/approver with any account owned by the same email. + statement = ` + SELECT commenterHex + FROM commenters + WHERE email = $1; + ` + row = db.QueryRow(statement, e.Email) + + var commenterHex string + if err = row.Scan(&commenterHex); err != nil { + logger.Errorf("cannot retrieve commenterHex by email %q: %v", e.Email, err) + fmt.Fprintf(w, "error: %v", errorInternal) + return + } + + switch action { + case "approve": err = commentApprove(commentHex) - } else { - err = commentDelete(commentHex) + case "delete": + err = commentDelete(commentHex, commenterHex) + default: + err = errorInvalidAction } if err != nil { diff --git a/api/errors.go b/api/errors.go index bc9710a..5ab8c16 100644 --- a/api/errors.go +++ b/api/errors.go @@ -52,3 +52,4 @@ var errorCannotDeleteOwnerWithActiveDomains = errors.New("You cannot delete your var errorNoSuchOwner = errors.New("No such owner.") var errorCannotUpdateOauthProfile = errors.New("You cannot update the profile of an external account managed by third-party log in. Please use the appropriate platform to update your details.") var errorUnsupportedCommentoImportVersion = errors.New("Unsupported Commento import format version.") +var errorInvalidAction = errors.New("Invalid action.") diff --git a/db/20210228122203-comment-delete-log.sql b/db/20210228122203-comment-delete-log.sql new file mode 100644 index 0000000..b7ed38d --- /dev/null +++ b/db/20210228122203-comment-delete-log.sql @@ -0,0 +1,2 @@ +ALTER TABLE comments ADD deleterHex TEXT; +ALTER TABLE comments ADD deletionDate TIMESTAMP;