Inner circle followups: notifications, min public pictures

face-detect
Noah Petherbridge 2023-05-24 11:27:42 -07:00
parent b9f2bafd7a
commit 6cad3cadc7
6 changed files with 68 additions and 16 deletions

View File

@ -87,6 +87,9 @@ const (
// Quotas for uploaded photos. // Quotas for uploaded photos.
PhotoQuotaUncertified = 6 PhotoQuotaUncertified = 6
PhotoQuotaCertified = 100 PhotoQuotaCertified = 100
// Min number of public photos for inner circle members to see the prompt to invite.
InnerCircleMinimumPublicPhotos = 5
) )
// Forum settings // Forum settings

View File

@ -157,8 +157,14 @@ func notifyFriendsNewPhoto(photo *models.Photo, currentUser *models.User) {
friendIDs = models.PrivateGranteeUserIDs(currentUser.ID) friendIDs = models.PrivateGranteeUserIDs(currentUser.ID)
log.Info("Notify %d private grantees about the new photo by %s", len(friendIDs), currentUser.Username) log.Info("Notify %d private grantees about the new photo by %s", len(friendIDs), currentUser.Username)
} else if photo.Visibility == models.PhotoInnerCircle { } else if photo.Visibility == models.PhotoInnerCircle {
friendIDs = models.FriendIDsInCircle(currentUser.ID) // Inner circle members. If the pic is also Explicit, further narrow to explicit friend IDs.
log.Info("Notify %d circle friends about the new photo by %s", len(friendIDs), currentUser.Username) if photo.Explicit {
friendIDs = models.FriendIDsInCircleAreExplicit(currentUser.ID)
log.Info("Notify %d EXPLICIT circle friends about the new photo by %s", len(friendIDs), currentUser.Username)
} else {
friendIDs = models.FriendIDsInCircle(currentUser.ID)
log.Info("Notify %d circle friends about the new photo by %s", len(friendIDs), currentUser.Username)
}
} else { } else {
// Get all our friend IDs. If this photo is Explicit, only select // Get all our friend IDs. If this photo is Explicit, only select
// the friends who've opted-in for Explicit photo visibility. // the friends who've opted-in for Explicit photo visibility.

View File

@ -139,19 +139,21 @@ func UserPhotos() http.HandlerFunc {
commentMap := models.MapCommentCounts("photos", photoIDs) commentMap := models.MapCommentCounts("photos", photoIDs)
var vars = map[string]interface{}{ var vars = map[string]interface{}{
"IsOwnPhotos": currentUser.ID == user.ID, "IsOwnPhotos": currentUser.ID == user.ID,
"IsShyUser": isShy, "IsShyUser": isShy,
"IsShyFrom": isShyFrom, "IsShyFrom": isShyFrom,
"IsMyPrivateUnlockedFor": isGranted, // have WE granted THIS USER to see our private pics? "IsMyPrivateUnlockedFor": isGranted, // have WE granted THIS USER to see our private pics?
"AreWeGrantedPrivate": isGrantee, // have THEY granted US private photo access. "AreWeGrantedPrivate": isGrantee, // have THEY granted US private photo access.
"User": user, "User": user,
"Photos": photos, "Photos": photos,
"PhotoCount": models.CountPhotos(user.ID), "PhotoCount": models.CountPhotos(user.ID),
"Pager": pager, "PublicPhotoCount": models.CountPublicPhotos(user.ID),
"LikeMap": likeMap, "InnerCircleMinimumPublicPhotos": config.InnerCircleMinimumPublicPhotos,
"CommentMap": commentMap, "Pager": pager,
"ViewStyle": viewStyle, "LikeMap": likeMap,
"ExplicitCount": explicitCount, "CommentMap": commentMap,
"ViewStyle": viewStyle,
"ExplicitCount": explicitCount,
} }
if err := tmpl.Execute(w, r, vars); err != nil { if err := tmpl.Execute(w, r, vars); err != nil {

View File

@ -155,6 +155,31 @@ func FriendIDsInCircle(userId uint64) []uint64 {
return userIDs return userIDs
} }
// FriendIDsInCircleAreExplicit returns the combined friend IDs who are in the inner circle + have opted in to explicit content.
// It is the combination of FriendIDsAreExplicit and FriendIDsInCircle.
func FriendIDsInCircleAreExplicit(userId uint64) []uint64 {
var (
userIDs = []uint64{}
)
err := DB.Table(
"friends",
).Joins(
"JOIN users ON (users.id = friends.target_user_id)",
).Select(
"friends.target_user_id AS friend_id",
).Where(
"friends.source_user_id = ? AND friends.approved = ? AND users.explicit = ? AND (users.inner_circle = ? OR users.is_admin = ?)",
userId, true, true, true, true,
).Scan(&userIDs)
if err.Error != nil {
log.Error("SQL error collecting explicit FriendIDs for %d: %s", userId, err)
}
return userIDs
}
// CountFriendRequests gets a count of pending requests for the user. // CountFriendRequests gets a count of pending requests for the user.
func CountFriendRequests(userID uint64) (int64, error) { func CountFriendRequests(userID uint64) (int64, error) {
var count int64 var count int64

View File

@ -159,6 +159,22 @@ func CountExplicitPhotos(userID uint64, visibility []PhotoVisibility) (int64, er
return count, result.Error return count, result.Error
} }
// CountPublicPhotos returns the number of public photos on a user's page (to control whether the "invite to circle" prompt can appear).
func CountPublicPhotos(userID uint64) int64 {
query := DB.Where(
"user_id = ? AND visibility = ?",
userID,
PhotoPublic,
)
var count int64
result := query.Model(&Photo{}).Count(&count)
if result.Error != nil {
log.Error("CountPublicPhotos(%d): %s", userID, result.Error)
}
return count
}
// DistinctPhotoTypes returns types of photos the user has: a set of public, friends, or private. // DistinctPhotoTypes returns types of photos the user has: a set of public, friends, or private.
// //
// The result is cached on the User the first time it's queried. // The result is cached on the User the first time it's queried.

View File

@ -342,7 +342,7 @@
<!-- Inner circle invitation --> <!-- Inner circle invitation -->
{{if not .IsSiteGallery}} {{if not .IsSiteGallery}}
{{if and (.CurrentUser.IsInnerCircle) (not .User.InnerCircle) (ne .CurrentUser.Username .User.Username)}} {{if and (.CurrentUser.IsInnerCircle) (not .User.InnerCircle) (ne .CurrentUser.Username .User.Username) (ge .PublicPhotoCount .InnerCircleMinimumPublicPhotos)}}
<div class="block mt-0"> <div class="block mt-0">
<span class="icon"><img src="/static/img/circle-16.png"></span> <span class="icon"><img src="/static/img/circle-16.png"></span>
Does <strong>{{.User.Username}}</strong> show a lot of nudity? Consider Does <strong>{{.User.Username}}</strong> show a lot of nudity? Consider