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.
This commit is contained in:
parent
542d0bb300
commit
295183559d
37
pkg/config/admin_labels.go
Normal file
37
pkg/config/admin_labels.go
Normal file
|
@ -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
|
||||||
|
}
|
|
@ -111,6 +111,24 @@ func Edit() http.HandlerFunc {
|
||||||
models.NewFieldDiff("Visibility", photo.Visibility, visibility),
|
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.Caption = caption
|
||||||
photo.AltText = altText
|
photo.AltText = altText
|
||||||
photo.Explicit = isExplicit
|
photo.Explicit = isExplicit
|
||||||
|
@ -167,6 +185,9 @@ func Edit() http.HandlerFunc {
|
||||||
|
|
||||||
// Allow this change but clear the Flagged status.
|
// Allow this change but clear the Flagged status.
|
||||||
photo.Flagged = false
|
photo.Flagged = false
|
||||||
|
|
||||||
|
// Clear the notification about this.
|
||||||
|
models.RemoveSpecificNotification(currentUser.ID, models.NotificationExplicitPhoto, "photos", photo.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := photo.Save(); err != nil {
|
if err := photo.Save(); err != nil {
|
||||||
|
@ -211,6 +232,10 @@ func Edit() http.HandlerFunc {
|
||||||
"EditPhoto": photo,
|
"EditPhoto": photo,
|
||||||
"SiteGalleryThrottled": SiteGalleryThrottled,
|
"SiteGalleryThrottled": SiteGalleryThrottled,
|
||||||
"SiteGalleryThrottleLimit": config.SiteGalleryRateLimitMax,
|
"SiteGalleryThrottleLimit": config.SiteGalleryRateLimitMax,
|
||||||
|
|
||||||
|
// Available admin labels enum.
|
||||||
|
"RequestUser": requestUser,
|
||||||
|
"AvailableAdminLabels": config.AdminLabelPhotoOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tmpl.Execute(w, r, vars); err != nil {
|
if err := tmpl.Execute(w, r, vars); err != nil {
|
||||||
|
|
|
@ -22,6 +22,7 @@ type Photo struct {
|
||||||
Caption string
|
Caption string
|
||||||
AltText string
|
AltText string
|
||||||
Flagged bool // photo has been reported by the community
|
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"`
|
Visibility PhotoVisibility `gorm:"index"`
|
||||||
Gallery bool `gorm:"index"` // photo appears in the public gallery (if public)
|
Gallery bool `gorm:"index"` // photo appears in the public gallery (if public)
|
||||||
Explicit bool `gorm:"index"` // is an explicit photo
|
Explicit bool `gorm:"index"` // is an explicit photo
|
||||||
|
@ -274,6 +275,21 @@ func GetOrphanedPhotos() ([]*Photo, int64, error) {
|
||||||
return ps, count, res.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.
|
// PhotoMap helps map a set of users to look up by ID.
|
||||||
type PhotoMap map[uint64]*Photo
|
type PhotoMap map[uint64]*Photo
|
||||||
|
|
||||||
|
|
|
@ -239,6 +239,11 @@
|
||||||
class="blurred-explicit">
|
class="blurred-explicit">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mt-3 has-text-smaller">
|
||||||
|
<a href="/photo/edit?id={{.TableID}}">
|
||||||
|
<i class="fa fa-edit mr-1"></i> Edit this photo
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -568,7 +568,7 @@
|
||||||
{{template "card-body" .}}
|
{{template "card-body" .}}
|
||||||
|
|
||||||
<!-- Quick mark photo as explicit -->
|
<!-- Quick mark photo as explicit -->
|
||||||
{{if and (not .Explicit) (ne .UserID $Root.CurrentUser.ID)}}
|
{{if and (not .Explicit) (ne .UserID $Root.CurrentUser.ID) (not .HasAdminLabelNonExplicit)}}
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<a href="#"
|
<a href="#"
|
||||||
class="has-text-danger is-size-7 nonshy-mark-explicit"
|
class="has-text-danger is-size-7 nonshy-mark-explicit"
|
||||||
|
@ -694,7 +694,7 @@
|
||||||
{{template "card-body" .}}
|
{{template "card-body" .}}
|
||||||
|
|
||||||
<!-- Quick mark photo as explicit -->
|
<!-- Quick mark photo as explicit -->
|
||||||
{{if and (not .Explicit) (ne .UserID $Root.CurrentUser.ID)}}
|
{{if and (not .Explicit) (ne .UserID $Root.CurrentUser.ID) (not .HasAdminLabelNonExplicit)}}
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<a href="#"
|
<a href="#"
|
||||||
class="has-text-danger is-size-7 nonshy-mark-explicit"
|
class="has-text-danger is-size-7 nonshy-mark-explicit"
|
||||||
|
|
|
@ -109,8 +109,18 @@
|
||||||
<small class="has-text-grey">Uploaded {{.Photo.CreatedAt.Format "Jan _2 2006 15:04:05"}}</small>
|
<small class="has-text-grey">Uploaded {{.Photo.CreatedAt.Format "Jan _2 2006 15:04:05"}}</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Show admin labels to admins -->
|
||||||
|
{{if .CurrentUser.HasAdminScope "social.moderator.photo"}}
|
||||||
|
{{if .Photo.AdminLabel}}
|
||||||
|
<div class="mt-2">
|
||||||
|
<i class="fa fa-peace has-text-danger mr-1"></i>
|
||||||
|
Admin Label: {{.Photo.AdminLabel}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<!-- Quick mark photo as explicit -->
|
<!-- Quick mark photo as explicit -->
|
||||||
{{if and (not .Photo.Explicit) (ne .Photo.UserID .CurrentUser.ID)}}
|
{{if and (not .Photo.Explicit) (ne .Photo.UserID .CurrentUser.ID) (not .Photo.HasAdminLabelNonExplicit)}}
|
||||||
<div class="mt-1">
|
<div class="mt-1">
|
||||||
<a href="#"
|
<a href="#"
|
||||||
class="has-text-danger is-size-7 nonshy-mark-explicit"
|
class="has-text-danger is-size-7 nonshy-mark-explicit"
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{{ $Root := . }}
|
||||||
{{ $User := .CurrentUser }}
|
{{ $User := .CurrentUser }}
|
||||||
|
|
||||||
<!-- Drag/Drop Modal -->
|
<!-- Drag/Drop Modal -->
|
||||||
|
@ -438,7 +439,8 @@
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
name="explicit"
|
name="explicit"
|
||||||
value="true"
|
value="true"
|
||||||
{{if .EditPhoto.Explicit}}checked{{end}}>
|
{{if .EditPhoto.Explicit}}checked{{end}}
|
||||||
|
{{if .EditPhoto.HasAdminLabelForceExplicit}}disabled{{end}}>
|
||||||
{{if $IsFlagged}}<del class="cursor-not-allowed">{{end}}
|
{{if $IsFlagged}}<del class="cursor-not-allowed">{{end}}
|
||||||
This photo contains explicit content
|
This photo contains explicit content
|
||||||
{{if $IsFlagged}}</del>{{end}}
|
{{if $IsFlagged}}</del>{{end}}
|
||||||
|
@ -488,6 +490,44 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Admin Labels -->
|
||||||
|
{{if and .EditPhoto (.RequestUser.HasAdminScope "social.moderator.photo")}}
|
||||||
|
<hr>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label has-text-danger">
|
||||||
|
<span>Admin Labels</span>
|
||||||
|
<span class="icon"><i class="fa fa-peace"></i></span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<p class="help">
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{range .AvailableAdminLabels}}
|
||||||
|
<div class="field">
|
||||||
|
<label class="checkbox">
|
||||||
|
<input type="checkbox"
|
||||||
|
name="admin_label"
|
||||||
|
value="{{.Value}}"
|
||||||
|
{{if ($Root.EditPhoto.HasAdminLabel .Value)}}checked{{end}}>
|
||||||
|
{{.Label}}
|
||||||
|
</label>
|
||||||
|
<p class="help">
|
||||||
|
{{.Help}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<p class="help">
|
||||||
|
<strong>Reminder:</strong> click on 'Save Changes' to apply these labels!
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{end}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user