From d623f0bc3c58b476fd07292cdcbbe26d02a9f851 Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Sat, 16 Mar 2024 13:29:28 -0700 Subject: [PATCH] User endpoint to flag photos that should be Explicit --- pkg/controller/api/mark_explicit.go | 110 ++++++++++++ pkg/controller/photo/mark_explicit.go | 63 +++++++ pkg/router/router.go | 1 + pkg/templates/templates.go | 1 + web/templates/partials/mark_explicit.html | 203 ++++++++++++++++++++++ web/templates/photo/gallery.html | 31 ++-- web/templates/photo/permalink.html | 17 +- 7 files changed, 405 insertions(+), 21 deletions(-) create mode 100644 pkg/controller/api/mark_explicit.go create mode 100644 pkg/controller/photo/mark_explicit.go create mode 100644 web/templates/partials/mark_explicit.html diff --git a/pkg/controller/api/mark_explicit.go b/pkg/controller/api/mark_explicit.go new file mode 100644 index 0000000..21a0ee5 --- /dev/null +++ b/pkg/controller/api/mark_explicit.go @@ -0,0 +1,110 @@ +package api + +import ( + "fmt" + "net/http" + + "code.nonshy.com/nonshy/website/pkg/log" + "code.nonshy.com/nonshy/website/pkg/models" + "code.nonshy.com/nonshy/website/pkg/session" + "code.nonshy.com/nonshy/website/pkg/templates" +) + +// User endpoint to flag other photos as explicit on their behalf. +func MarkPhotoExplicit() http.HandlerFunc { + // Request JSON schema. + type Request struct { + PhotoID uint64 `json:"photoID"` + Reason string `json:"reason"` + Other string `json:"other"` + } + + // Response JSON schema. + type Response struct { + OK bool `json:"OK"` + Error string `json:"error,omitempty"` + } + + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Get current user. + currentUser, err := session.CurrentUser(r) + if err != nil { + session.FlashError(w, r, "Failed to get current user: %s", err) + templates.Redirect(w, "/") + return + } + + // Parse request payload. + var req Request + if err := ParseJSON(r, &req); err != nil { + SendJSON(w, http.StatusBadRequest, Response{ + Error: fmt.Sprintf("Error with request payload: %s", err), + }) + return + } + + // Form validation. + if req.Reason == "" { + SendJSON(w, http.StatusBadRequest, Response{ + Error: "Please select one of the reasons why this photo should've been marked Explicit.", + }) + return + } + + // Get this photo. + photo, err := models.GetPhoto(req.PhotoID) + if err != nil { + SendJSON(w, http.StatusBadRequest, Response{ + Error: "That photo was not found!", + }) + return + } + + if !photo.Explicit { + photo.Explicit = true + if err := photo.Save(); err != nil { + SendJSON(w, http.StatusBadRequest, Response{ + Error: fmt.Sprintf("Couldn't save the photo: %s", err), + }) + return + } + + // If a non-admin user has hit this API, log an admin report for visibility and + // to keep a pulse on things (e.g. in case of abuse). + if !currentUser.IsAdmin { + fb := &models.Feedback{ + Intent: "report", + Subject: "User flagged an explicit photo", + UserID: currentUser.ID, + TableName: "photos", + TableID: photo.ID, + Message: fmt.Sprintf( + "A user has flagged that a photo should have been marked as Explicit.\n\n"+ + "* Reported by: %s (ID %d)\n"+ + "* Reason given: %s\n"+ + "* Elaboration (if other): %s\n\n"+ + "The photo had been immediately marked as Explicit.", + currentUser.Username, + currentUser.ID, + req.Reason, + req.Other, + ), + } + + // Save the feedback. + if err := models.CreateFeedback(fb); err != nil { + log.Error("Couldn't save feedback from user updating their DOB: %s", err) + } + } + } + + // Log the change. + models.LogUpdated(&models.User{ID: photo.UserID}, currentUser, "photos", photo.ID, "Marked explicit by admin action.", []models.FieldDiff{ + models.NewFieldDiff("Explicit", false, true), + }) + + SendJSON(w, http.StatusOK, Response{ + OK: true, + }) + }) +} diff --git a/pkg/controller/photo/mark_explicit.go b/pkg/controller/photo/mark_explicit.go new file mode 100644 index 0000000..fe5957d --- /dev/null +++ b/pkg/controller/photo/mark_explicit.go @@ -0,0 +1,63 @@ +package photo + +import ( + "net/http" + "strconv" + "strings" + + "code.nonshy.com/nonshy/website/pkg/models" + "code.nonshy.com/nonshy/website/pkg/session" + "code.nonshy.com/nonshy/website/pkg/templates" +) + +// User endpoint to flag other photos as explicit on their behalf. +func MarkPhotoExplicit() http.HandlerFunc { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var ( + photoID uint64 + next = r.FormValue("next") + ) + + if !strings.HasPrefix(next, "/") { + next = "/" + } + + // Get current user. + currentUser, err := session.CurrentUser(r) + if err != nil { + session.FlashError(w, r, "Failed to get current user: %s", err) + templates.Redirect(w, "/") + return + } + + if idInt, err := strconv.Atoi(r.FormValue("photo_id")); err == nil { + photoID = uint64(idInt) + } else { + session.FlashError(w, r, "Invalid or missing photo_id parameter: %s", err) + templates.Redirect(w, next) + return + } + + // Get this photo. + photo, err := models.GetPhoto(photoID) + if err != nil { + session.FlashError(w, r, "Didn't find photo ID in database: %s", err) + templates.Redirect(w, next) + return + } + + photo.Explicit = true + if err := photo.Save(); err != nil { + session.FlashError(w, r, "Couldn't save photo: %s", err) + } else { + session.Flash(w, r, "Marked photo as Explicit!") + } + + // Log the change. + models.LogUpdated(&models.User{ID: photo.UserID}, currentUser, "photos", photo.ID, "Marked explicit by admin action.", []models.FieldDiff{ + models.NewFieldDiff("Explicit", false, true), + }) + + templates.Redirect(w, next) + }) +} diff --git a/pkg/router/router.go b/pkg/router/router.go index 6e7ebcf..a87e6ff 100644 --- a/pkg/router/router.go +++ b/pkg/router/router.go @@ -111,6 +111,7 @@ func New() http.Handler { mux.Handle("GET /v1/likes/users", middleware.LoginRequired(api.WhoLikes())) mux.Handle("POST /v1/notifications/read", middleware.LoginRequired(api.ReadNotification())) mux.Handle("POST /v1/notifications/delete", middleware.LoginRequired(api.ClearNotification())) + mux.Handle("POST /v1/photos/mark-explicit", middleware.LoginRequired(api.MarkPhotoExplicit())) mux.Handle("GET /v1/comment-photos/remove-orphaned", api.RemoveOrphanedCommentPhotos()) mux.Handle("POST /v1/barertc/report", barertc.Report()) mux.Handle("POST /v1/barertc/profile", barertc.Profile()) diff --git a/pkg/templates/templates.go b/pkg/templates/templates.go index 654ee6c..0738dc6 100644 --- a/pkg/templates/templates.go +++ b/pkg/templates/templates.go @@ -134,6 +134,7 @@ var baseTemplates = []string{ config.TemplatePath + "/partials/user_avatar.html", config.TemplatePath + "/partials/like_modal.html", config.TemplatePath + "/partials/right_click.html", + config.TemplatePath + "/partials/mark_explicit.html", config.TemplatePath + "/partials/themes.html", } diff --git a/web/templates/partials/mark_explicit.html b/web/templates/partials/mark_explicit.html new file mode 100644 index 0000000..a3e79da --- /dev/null +++ b/web/templates/partials/mark_explicit.html @@ -0,0 +1,203 @@ + +{{define "mark-explicit-modal"}} + + + +{{end}} diff --git a/web/templates/photo/gallery.html b/web/templates/photo/gallery.html index 068371d..a0a8638 100644 --- a/web/templates/photo/gallery.html +++ b/web/templates/photo/gallery.html @@ -540,14 +540,14 @@ {{template "card-body" .}} - - {{if and ($Root.CurrentUser.IsAdmin) (not .Explicit)}} + + {{if not .Explicit}}
- - - Mark photo as Explicit + + + Should this photo be marked Explicit?
{{end}} @@ -666,14 +666,14 @@ {{template "card-body" .}} - - {{if and ($Root.CurrentUser.IsAdmin) (not .Explicit)}} + + {{if not .Explicit}}
- - - Mark photo as Explicit + + + Should this photo be marked Explicit?
{{end}} @@ -794,4 +794,7 @@ }); }); + + +{{template "mark-explicit-modal" .}} {{end}} diff --git a/web/templates/photo/permalink.html b/web/templates/photo/permalink.html index be41a55..a5e7af0 100644 --- a/web/templates/photo/permalink.html +++ b/web/templates/photo/permalink.html @@ -98,14 +98,14 @@ {{end}} - - {{if and (.CurrentUser.IsAdmin) (not .Photo.Explicit)}} + + {{if not .Photo.Explicit}}
- - - Mark photo as Explicit + + + Should this photo be marked Explicit?
{{end}} @@ -333,4 +333,7 @@ + + +{{template "mark-explicit-modal" .}} {{end}}