From 295183559da628fb1d8e331bd4825ed4acad2ed9 Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Tue, 1 Oct 2024 23:13:09 -0700 Subject: [PATCH] Admin labels on photos surrounding explicit flags * Add 'admin labels' to photos so an admin can classify a photo as: * Not Explicit: e.g. it was flagged by the community but does not actually need to be explicit. This option will hide the prompt to report the explicit photo again. * Force Explicit: if a user is fighting an explicit flag and keeps removing it from their photo, the photo can be force marked explicit. * Admin labels appear on the Permalink page and in the edit photo settings when viewed as a photo moderator admin. --- pkg/config/admin_labels.go | 37 +++++++++++++++++++++++++ pkg/controller/photo/edit_delete.go | 25 +++++++++++++++++ pkg/models/photo.go | 16 +++++++++++ web/templates/admin/feedback.html | 5 ++++ web/templates/photo/gallery.html | 4 +-- web/templates/photo/permalink.html | 12 ++++++++- web/templates/photo/upload.html | 42 ++++++++++++++++++++++++++++- 7 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 pkg/config/admin_labels.go diff --git a/pkg/config/admin_labels.go b/pkg/config/admin_labels.go new file mode 100644 index 0000000..f03eee1 --- /dev/null +++ b/pkg/config/admin_labels.go @@ -0,0 +1,37 @@ +package config + +import "strings" + +// Admin Labels. +const ( + // Admin Labels for Photos + AdminLabelPhotoNonExplicit = "non-explicit" + AdminLabelPhotoForceExplicit = "force-explicit" +) + +var ( + AdminLabelPhotoOptions = []ChecklistOption{ + { + Value: AdminLabelPhotoNonExplicit, + Label: "This is not an Explicit photo", + Help: "Hide the prompt 'Should this photo be marked as explicit?' as this photo does not NEED to be Explicit. " + + "Note: the owner of this photo MAY still mark it explicit if they want to.", + }, + { + Value: AdminLabelPhotoForceExplicit, + Label: "Force this photo to be marked as Explicit", + Help: "Enabling this option will force the Explicit tag to stay on, and not allow the user to remove it.", + }, + } +) + +// HasAdminLabel checks if a comma-separated set of admin labels contains the label. +func HasAdminLabel(needle string, haystack string) bool { + labels := strings.Split(haystack, ",") + for _, label := range labels { + if strings.TrimSpace(label) == needle { + return true + } + } + return false +} diff --git a/pkg/controller/photo/edit_delete.go b/pkg/controller/photo/edit_delete.go index a88bd42..d1a23ee 100644 --- a/pkg/controller/photo/edit_delete.go +++ b/pkg/controller/photo/edit_delete.go @@ -111,6 +111,24 @@ func Edit() http.HandlerFunc { models.NewFieldDiff("Visibility", photo.Visibility, visibility), } + // Admin label options. + if requestUser.HasAdminScope(config.ScopePhotoModerator) { + var adminLabel string + if labels, ok := r.PostForm["admin_label"]; ok { + adminLabel = strings.Join(labels, ",") + } + diffs = append(diffs, + models.NewFieldDiff("Admin Label", photo.AdminLabel, adminLabel), + ) + + photo.AdminLabel = adminLabel + } + + // Admin label: forced explicit? + if photo.HasAdminLabelForceExplicit() { + isExplicit = true + } + photo.Caption = caption photo.AltText = altText photo.Explicit = isExplicit @@ -167,6 +185,9 @@ func Edit() http.HandlerFunc { // Allow this change but clear the Flagged status. photo.Flagged = false + + // Clear the notification about this. + models.RemoveSpecificNotification(currentUser.ID, models.NotificationExplicitPhoto, "photos", photo.ID) } if err := photo.Save(); err != nil { @@ -211,6 +232,10 @@ func Edit() http.HandlerFunc { "EditPhoto": photo, "SiteGalleryThrottled": SiteGalleryThrottled, "SiteGalleryThrottleLimit": config.SiteGalleryRateLimitMax, + + // Available admin labels enum. + "RequestUser": requestUser, + "AvailableAdminLabels": config.AdminLabelPhotoOptions, } if err := tmpl.Execute(w, r, vars); err != nil { diff --git a/pkg/models/photo.go b/pkg/models/photo.go index 8e8e64e..dc07a1f 100644 --- a/pkg/models/photo.go +++ b/pkg/models/photo.go @@ -22,6 +22,7 @@ type Photo struct { Caption string AltText string Flagged bool // photo has been reported by the community + AdminLabel string // admin label(s) on this photo (e.g. verified non-explicit) Visibility PhotoVisibility `gorm:"index"` Gallery bool `gorm:"index"` // photo appears in the public gallery (if public) Explicit bool `gorm:"index"` // is an explicit photo @@ -274,6 +275,21 @@ func GetOrphanedPhotos() ([]*Photo, int64, error) { return ps, count, res.Error } +// HasAdminLabelNonExplicit checks if the non-explicit admin label is applied to this photo. +func (p *Photo) HasAdminLabelNonExplicit() bool { + return config.HasAdminLabel(config.AdminLabelPhotoNonExplicit, p.AdminLabel) +} + +// HasAdminLabelForceExplicit checks if the force-explicit admin label is applied to this photo. +func (p *Photo) HasAdminLabelForceExplicit() bool { + return config.HasAdminLabel(config.AdminLabelPhotoForceExplicit, p.AdminLabel) +} + +// HasAdminLabel checks if the photo has an admin label (for convenient front-end access on the Edit page). +func (p *Photo) HasAdminLabel(label string) bool { + return config.HasAdminLabel(label, p.AdminLabel) +} + // PhotoMap helps map a set of users to look up by ID. type PhotoMap map[uint64]*Photo diff --git a/web/templates/admin/feedback.html b/web/templates/admin/feedback.html index 465b4f8..7dd4bfd 100644 --- a/web/templates/admin/feedback.html +++ b/web/templates/admin/feedback.html @@ -239,6 +239,11 @@ class="blurred-explicit"> +
+ + Edit this photo + +
{{end}} {{end}} diff --git a/web/templates/photo/gallery.html b/web/templates/photo/gallery.html index 004701f..a7fb83c 100644 --- a/web/templates/photo/gallery.html +++ b/web/templates/photo/gallery.html @@ -568,7 +568,7 @@ {{template "card-body" .}} - {{if and (not .Explicit) (ne .UserID $Root.CurrentUser.ID)}} + {{if and (not .Explicit) (ne .UserID $Root.CurrentUser.ID) (not .HasAdminLabelNonExplicit)}}
- {{if and (not .Explicit) (ne .UserID $Root.CurrentUser.ID)}} + {{if and (not .Explicit) (ne .UserID $Root.CurrentUser.ID) (not .HasAdminLabelNonExplicit)}} + + {{if .CurrentUser.HasAdminScope "social.moderator.photo"}} + {{if .Photo.AdminLabel}} +
+ + Admin Label: {{.Photo.AdminLabel}} +
+ {{end}} + {{end}} + - {{if and (not .Photo.Explicit) (ne .Photo.UserID .CurrentUser.ID)}} + {{if and (not .Photo.Explicit) (ne .Photo.UserID .CurrentUser.ID) (not .Photo.HasAdminLabelNonExplicit)}}
+ + {{if and .EditPhoto (.RequestUser.HasAdminScope "social.moderator.photo")}} +
+
+ + +

+ The options below can apply moderation rules to this picture, especially regarding + its 'explicit' status. For example: if a community member flagged this picture as + explicit, but it does NOT need to be marked as such, select that label below: and + the website will no longer allow this photo to be flagged as explicit again. +

+
+ + {{range .AvailableAdminLabels}} +
+ +

+ {{.Help}} +

+
+ {{end}} + +

+ Reminder: click on 'Save Changes' to apply these labels! +

+ + {{end}} +