diff --git a/pkg/config/config.go b/pkg/config/config.go index b5f9cf8..35990be 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -101,6 +101,13 @@ const ( // Min number of public photos for inner circle members to see the prompt to invite. InnerCircleMinimumPublicPhotos = 5 + + // Rate limit for too many Site Gallery pictures. + // Some users sign up and immediately max out their gallery and spam + // the Site Gallery page. These limits can ensure only a few Site Gallery + // pictures can be posted per day. + SiteGalleryRateLimitMax = 5 + SiteGalleryRateLimitInterval = 24 * time.Hour ) // Forum settings diff --git a/pkg/controller/photo/edit_delete.go b/pkg/controller/photo/edit_delete.go index aff8058..2f5211f 100644 --- a/pkg/controller/photo/edit_delete.go +++ b/pkg/controller/photo/edit_delete.go @@ -6,6 +6,7 @@ import ( "path/filepath" "strconv" + "code.nonshy.com/nonshy/website/pkg/config" "code.nonshy.com/nonshy/website/pkg/log" "code.nonshy.com/nonshy/website/pkg/models" pphoto "code.nonshy.com/nonshy/website/pkg/photo" @@ -59,6 +60,9 @@ func Edit() http.HandlerFunc { } } + // Is the user throttled for Site Gallery photo uploads? + var SiteGalleryThrottled = models.IsSiteGalleryThrottled(currentUser, photo) + // Are we saving the changes? if r.Method == http.MethodPost { var ( @@ -76,6 +80,11 @@ func Edit() http.HandlerFunc { goingCircle = visibility == models.PhotoInnerCircle && visibility != photo.Visibility ) + // Respect the Site Gallery throttle in case the user is messing around. + if SiteGalleryThrottled { + isGallery = false + } + photo.Caption = caption photo.Explicit = isExplicit photo.Gallery = isGallery @@ -137,7 +146,9 @@ func Edit() http.HandlerFunc { } var vars = map[string]interface{}{ - "EditPhoto": photo, + "EditPhoto": photo, + "SiteGalleryThrottled": SiteGalleryThrottled, + "SiteGalleryThrottleLimit": config.SiteGalleryRateLimitMax, } if err := tmpl.Execute(w, r, vars); err != nil { diff --git a/pkg/controller/photo/upload.go b/pkg/controller/photo/upload.go index 7722a59..eb4397c 100644 --- a/pkg/controller/photo/upload.go +++ b/pkg/controller/photo/upload.go @@ -7,6 +7,7 @@ import ( "os" "path/filepath" + "code.nonshy.com/nonshy/website/pkg/config" "code.nonshy.com/nonshy/website/pkg/log" "code.nonshy.com/nonshy/website/pkg/models" "code.nonshy.com/nonshy/website/pkg/photo" @@ -40,6 +41,10 @@ func Upload() http.HandlerFunc { vars["PhotoCount"] = photoCount vars["PhotoQuota"] = photoQuota + // Is the user throttled from sharing a Site Gallery photo too frequently? + vars["SiteGalleryThrottled"] = models.IsSiteGalleryThrottled(user, nil) + vars["SiteGalleryThrottleLimit"] = config.SiteGalleryRateLimitMax + // If they do not have a profile picture currently set (and are not uploading one now), // the front-end should point this out to them. if (user.ProfilePhotoID == nil || *user.ProfilePhotoID == 0) && vars["Intent"] != "profile_pic" { @@ -63,6 +68,11 @@ func Upload() http.HandlerFunc { confirm2 = r.PostFormValue("confirm2") == "true" ) + // Enforce that they can not override the Site Gallery throttle. + if vars["SiteGalleryThrottled"].(bool) && isGallery { + isGallery = false + } + // Are they at quota already? if photoCount >= photoQuota { session.FlashError(w, r, "You have too many photos to upload a new one. Please delete a photo to make room for a new one.") diff --git a/pkg/models/photo.go b/pkg/models/photo.go index e055854..ba1b1c0 100644 --- a/pkg/models/photo.go +++ b/pkg/models/photo.go @@ -170,6 +170,48 @@ func CountPhotos(userID uint64) int64 { return count } +/* +IsSiteGalleryThrottled returns whether the user is throttled from marking additional pictures for the Site Gallery. + +The thresholds are in pkg/config but the idea is a user can only upload (say) 5 Site Gallery photos within a +24 hour time span, so that new users who sign up and immediately max out their full gallery don't end up +spamming the Site Gallery for pages and pages. + +If the user has too many recent Site Gallery pictures: + + - Newly uploaded photos can NOT check the Gallery box. + - Editing any existing photo which is NOT in the Gallery: you can not mark the box either. + - Existing Gallery photos CAN be un-marked for the gallery, which (if it is one of the 5 recent + photos) may put the user below the threshold again. + +If the user is on the Edit page for an existing photo, provide the Photo; otherwise leave it nil +if the user is uploading a new photo for the first time. +*/ +func IsSiteGalleryThrottled(user *User, editPhoto *Photo) bool { + // If the editing photo is already in the gallery, allow the user to keep or remove it. + if editPhoto != nil && editPhoto.Gallery { + return false + } + + var count = CountRecentGalleryPhotos(user, config.SiteGalleryRateLimitInterval) + log.Debug("IsSiteGalleryThrottled(%s): they have %d recent Gallery photos", user.Username, count) + return count >= config.SiteGalleryRateLimitMax +} + +// CountRecentGalleryPhotos returns the count of recently uploaded Site Gallery photos for a user, +// within the past 24 hours, to rate limit spammy bulk uploads that will flood the gallery. +func CountRecentGalleryPhotos(user *User, duration time.Duration) (count int64) { + result := DB.Where( + "user_id = ? AND created_at >= ? AND gallery IS TRUE", + user.ID, + time.Now().Add(-duration), + ).Model(&Photo{}).Count(&count) + if result.Error != nil { + log.Error("CountRecentGalleryPhotos(%d): %s", user.ID, result.Error) + } + return +} + // CountPhotosICanSee returns the number of photos on an account which can be seen by the given viewer. func CountPhotosICanSee(user *User, viewer *User) int64 { // Visibility filters to query by. diff --git a/web/templates/faq.html b/web/templates/faq.html index 71e7cb6..b644a52 100644 --- a/web/templates/faq.html +++ b/web/templates/faq.html @@ -16,12 +16,12 @@
  • @@ -47,6 +48,7 @@
  • Do I have to post my nudes here?
  • Do I have to include my face in my nudes?
  • What appears on the Site Gallery?
  • +
  • Why can't I feature my photo on the Site Gallery? NEW Jan 5 2024
  • Can I include other people in my photos?
  • What is considered "explicit" in photos?
  • Are digitally altered or 'photoshopped' pictures okay?
  • @@ -429,6 +431,52 @@ at all.

    +

    How does blocking somebody work on nonshy?

    + +

    + If somebody on {{PrettyTitle}} is bothering you or you just do not wish to see their + presence or content around the website anymore, you may "Block" them by going to their profile + page and clicking on the Block button. +

    + +

    + When you block somebody, {{PrettyTitle}} draws a hard line between your + two accounts and will make it so that you two do not see each other anywhere + on the website: +

    + + + +

    + The idea is that if you block somebody, it should look as though they may have just deleted their + {{PrettyTitle}} account completely and you should not see them anymore and they should not see + you either. +

    + +

    + If you find any corner of the site where this fails to happen (and you see somebody who you have + blocked), please report it as a bug to be fixed. +

    +

    Photo FAQs

    Do I have to post my nudes here?

    @@ -484,6 +532,54 @@ the Gallery -- it will then only appear on your profile page.

    + + +

    + In January 2024 we have added a rate limit on how frequently you can upload a new photo + and have it appear on the site-wide Photo Gallery in order to cut down on "spam" when a + new member would sign up and immediately upload all 100 of their photos to their gallery + page. +

    + +

    + We don't want the Site Gallery to be dominated by large swaths of only one person's + photos that go on for pages and pages, so you may only feature up to + 5 photos per day on the Site Gallery. + When you have 5 or more photos, uploaded within the last 24 hours and marked to share with the + Site Gallery, you will not be able to add additional photos to the gallery until you + wait a day OR edit one of those recent photos to remove it from + the gallery. +

    + +

    + If you have been throttled from sharing new Site Gallery photos, your options are: +

    + + + +

    + Our recommendation: take it slow! Share a few pictures per day on your gallery + until you eventually fill it out. This is also a better way to get engagement on your photos: + your friends are more likely to "Like" and comment on your photos if you drip feed them slowly + vs. if you upload your 100 photos all at once. +

    +

    Can I include other people in my photos?

    diff --git a/web/templates/photo/upload.html b/web/templates/photo/upload.html index 3423e6f..b8491f9 100644 --- a/web/templates/photo/upload.html +++ b/web/templates/photo/upload.html @@ -322,9 +322,27 @@ - Show this photo in the site-wide Photo Gallery + {{if and (or .EditPhoto.Gallery (not .EditPhoto)) (not .SiteGalleryThrottled)}}checked{{end}} + {{if .SiteGalleryThrottled}}disabled{{end}}> + {{if .SiteGalleryThrottled}}{{end}} + Show this photo in the site-wide Photo Gallery + {{if .SiteGalleryThrottled}}{{end}} + + {{if .SiteGalleryThrottled}} +

    + + You have shared too many photos with the Site Gallery recently!

    + We currently limit members to featuring {{.SiteGalleryThrottleLimit}} photos + on the Site Gallery per day, so that one member doesn't dominate page after + page of the gallery by uploading all of their pictures at once. + Learn more +

    + You may still upload all the photos you like to your gallery, but new ones can not be featured + on the Site Gallery until you have waited 24 hours. You MAY "edit" your recently posted photos + and un-check the Site Gallery box if you really want this one to be featured now. +

    + {{else}}

    Leave this box checked and your photo can appear in the site's Photo Gallery page. Mainly your Public photos will appear @@ -334,6 +352,7 @@ the gallery to users whom you have granted access. If this is undesirable, un-check the Gallery box to skip the Site Gallery.

    + {{end}}