diff --git a/pkg/controller/chat/chat.go b/pkg/controller/chat/chat.go index 58bfd0c..9a3a178 100644 --- a/pkg/controller/chat/chat.go +++ b/pkg/controller/chat/chat.go @@ -104,6 +104,8 @@ func Landing() http.HandlerFunc { avatar = "/static/img/shy-private.png" case models.PhotoFriends: avatar = "/static/img/shy-friends.png" + case models.PhotoInnerCircle: + avatar = "/static/img/shy-secret.png" } // Country flag emoji. diff --git a/pkg/controller/photo/user_gallery.go b/pkg/controller/photo/user_gallery.go index b35fb27..9d987d5 100644 --- a/pkg/controller/photo/user_gallery.go +++ b/pkg/controller/photo/user_gallery.go @@ -196,6 +196,13 @@ func UserPhotos() http.HandlerFunc { likeMap := models.MapLikes(currentUser, "photos", photoIDs) commentMap := models.MapCommentCounts("photos", photoIDs) + // Can we see their default profile picture? If no: show a hint on the Gallery page that + // their default pic isn't visible. + var profilePictureHidden models.PhotoVisibility + if ok, visibility := user.CanSeeProfilePicture(currentUser); !ok && visibility != models.PhotoPublic { + profilePictureHidden = visibility + } + var vars = map[string]interface{}{ "IsOwnPhotos": currentUser.ID == user.ID, "IsShyUser": isShy, @@ -203,6 +210,7 @@ func UserPhotos() http.HandlerFunc { "IsMyPrivateUnlockedFor": isGranted, // have WE granted THIS USER to see our private pics? "AreWeGrantedPrivate": isGrantee, // have THEY granted US private photo access. "AreFriends": areFriends, + "ProfilePictureHiddenVisibility": profilePictureHidden, "User": user, "Photos": photos, "PhotoCount": models.CountPhotosICanSee(user, currentUser), diff --git a/pkg/models/user.go b/pkg/models/user.go index 4586561..8eed924 100644 --- a/pkg/models/user.go +++ b/pkg/models/user.go @@ -536,16 +536,46 @@ func (u *User) NameOrUsername() string { // // Expects that UserRelationships are available on the user. func (u *User) VisibleAvatarURL(currentUser *User) string { - if u.ProfilePhoto.Visibility == PhotoPrivate && !u.UserRelationship.IsPrivateGranted { - return "/static/img/shy-private.png" - } else if u.ProfilePhoto.Visibility == PhotoFriends && !u.UserRelationship.IsFriend { - return "/static/img/shy-friends.png" - } else if u.ProfilePhoto.CroppedFilename != "" { + canSee, visibility := u.CanSeeProfilePicture(currentUser) + if canSee { return config.PhotoWebPath + "/" + u.ProfilePhoto.CroppedFilename } + + switch visibility { + case PhotoPrivate: + return "/static/img/shy-private.png" + case PhotoInnerCircle: + return "/static/img/shy-secret.png" + case PhotoFriends: + return "/static/img/shy-friends.png" + } + return "/static/img/shy.png" } +// CanSeeProfilePicture returns whether the current user can see the user's profile picture. +// +// Returns a boolean (false if currentUser can't see) and the Visibility setting of the profile photo. +// +// If the user has no profile photo, returns (false, PhotoPublic) which should manifest as the blue shy.png placeholder image. +func (u *User) CanSeeProfilePicture(currentUser *User) (bool, PhotoVisibility) { + visibility := u.ProfilePhoto.Visibility + if visibility == PhotoPrivate && !u.UserRelationship.IsPrivateGranted { + // Private photo + return false, visibility + } else if visibility == PhotoFriends && !u.UserRelationship.IsFriend { + // Friends only + return false, visibility + } else if visibility == PhotoInnerCircle && !currentUser.IsInnerCircle() { + // Inner circle only + return false, visibility + } else if u.ProfilePhoto.CroppedFilename != "" { + // Happy path + return true, visibility + } + return false, PhotoPublic +} + // HashPassword sets the user's hashed (bcrypt) password. func (u *User) HashPassword(password string) error { passwd, err := bcrypt.GenerateFromPassword([]byte(password), config.BcryptCost) diff --git a/pkg/models/user_relationship.go b/pkg/models/user_relationship.go index 0ff49d6..d9d6dcf 100644 --- a/pkg/models/user_relationship.go +++ b/pkg/models/user_relationship.go @@ -5,17 +5,19 @@ package models // The zero-values should fail safely: in case the UserRelationship isn't populated correctly, // private profile pics show as private by default. type UserRelationship struct { - IsFriend bool // if true, a friends-only profile pic can show - IsPrivateGranted bool // if true, a private profile pic can show + IsFriend bool // if true, a friends-only profile pic can show + IsPrivateGranted bool // if true, a private profile pic can show + IsInnerCirclePeer bool // if true, the current user is in the inner circle so may see circle-only profile picture } // SetUserRelationships updates a set of User objects to populate their UserRelationships in // relationship to the current user who is looking. -func SetUserRelationships(user *User, users []*User) error { +func SetUserRelationships(currentUser *User, users []*User) error { // Collect the current user's Friendships and Private Grants. var ( - friendIDs = FriendIDs(user.ID) - privateGrants = PrivateGrantedUserIDs(user.ID) + friendIDs = FriendIDs(currentUser.ID) + privateGrants = PrivateGrantedUserIDs(currentUser.ID) + isInnerCircle = currentUser.IsInnerCircle() ) // Map them for easier lookup. @@ -34,7 +36,9 @@ func SetUserRelationships(user *User, users []*User) error { // Inject the UserRelationships. for _, u := range users { - if u.ID == user.ID { + u.UserRelationship.IsInnerCirclePeer = isInnerCircle + + if u.ID == currentUser.ID { // Current user - set both bools to true - you can always see your own profile pic. u.UserRelationship.IsFriend = true u.UserRelationship.IsPrivateGranted = true diff --git a/web/static/css/theme.css b/web/static/css/theme.css index 409119f..8c9cfbf 100644 --- a/web/static/css/theme.css +++ b/web/static/css/theme.css @@ -58,7 +58,7 @@ img { } .has-text-private { - color: #CC00CC; + color: #CC00CC !important; } .has-text-private-light { diff --git a/web/static/img/shy-secret.png b/web/static/img/shy-secret.png new file mode 100644 index 0000000..2040293 Binary files /dev/null and b/web/static/img/shy-secret.png differ diff --git a/web/templates/account/profile.html b/web/templates/account/profile.html index 8f80ecd..c9f3888 100644 --- a/web/templates/account/profile.html +++ b/web/templates/account/profile.html @@ -8,17 +8,7 @@
- {{if .User.ProfilePhoto.ID}} - {{if and (eq .User.ProfilePhoto.Visibility "private") (not .User.UserRelationship.IsPrivateGranted)}} - - {{else if and (eq .User.ProfilePhoto.Visibility "friends") (not .User.UserRelationship.IsFriend)}} - - {{else}} - - {{end}} - {{else}} - - {{end}} + {{if and .LoggedIn (eq .CurrentUser.ID .User.ID) (not .IsPrivate)}} diff --git a/web/templates/faq.html b/web/templates/faq.html index b644a52..cc0537a 100644 --- a/web/templates/faq.html +++ b/web/templates/faq.html @@ -378,8 +378,40 @@ granted access to see your private photos. + {{if .CurrentUser.IsInnerCircle}} +
  • + {{PrettyCircle}} + : + your profile pic displays as a gradient + + placeholder image for members outside the inner circle. +
      +
    • + Note: only {{PrettyCircle}} members see this info on the FAQ page. + Members outside the circle will see the gradient avatar, but be told that it means + "Private." +
    • +
    +
  • + {{end}} +

    + Note that it is required that your default profile picture must include your face, + but with the visibility settings you may limit who will see it if you need to. +

    + +

    + If you find a member's gallery where they have no face visible in any of their pictures, it may + be that their default profile picture is just not visible to you, and a notice appears at the top + of their gallery page if this is the case. +

    + +

    + If you find a member whose profile photo you can see, and it also does not include their + face, please report their profile to the admin. +

    +

    What are the visibility options for my profile page?

    diff --git a/web/templates/partials/like_modal.html b/web/templates/partials/like_modal.html index 396c9ce..965aa74 100644 --- a/web/templates/partials/like_modal.html +++ b/web/templates/partials/like_modal.html @@ -27,6 +27,8 @@ {{else if and (eq $User.ProfilePhoto.Visibility "friends") (not $User.UserRelationship.IsFriend)}} + {{else if and (eq $User.ProfilePhoto.Visibility "circle") (not $User.UserRelationship.IsInnerCirclePeer)}} + {{else}} {{end}} diff --git a/web/templates/partials/user_avatar.html b/web/templates/partials/user_avatar.html index 2f97315..2d96b3d 100644 --- a/web/templates/partials/user_avatar.html +++ b/web/templates/partials/user_avatar.html @@ -9,6 +9,8 @@ {{else if and (eq .ProfilePhoto.Visibility "friends") (not .UserRelationship.IsFriend)}} + {{else if and (eq .ProfilePhoto.Visibility "circle") (not .UserRelationship.IsInnerCirclePeer)}} + {{else}} {{end}} @@ -28,6 +30,8 @@ {{else if and (eq .ProfilePhoto.Visibility "friends") (not .UserRelationship.IsFriend)}} + {{else if and (eq .ProfilePhoto.Visibility "circle") (not .UserRelationship.IsInnerCirclePeer)}} + {{else}} {{end}} @@ -47,6 +51,8 @@ {{else if and (eq .ProfilePhoto.Visibility "friends") (not .UserRelationship.IsFriend)}} + {{else if and (eq .ProfilePhoto.Visibility "circle") (not .UserRelationship.IsInnerCirclePeer)}} + {{else}} {{end}} @@ -66,6 +72,8 @@ {{else if and (eq .ProfilePhoto.Visibility "friends") (not .UserRelationship.IsFriend)}} + {{else if and (eq .ProfilePhoto.Visibility "circle") (not .UserRelationship.IsInnerCirclePeer)}} + {{else}} {{end}} @@ -85,6 +93,8 @@ {{else if and (eq .ProfilePhoto.Visibility "friends") (not .UserRelationship.IsFriend)}} + {{else if and (eq .ProfilePhoto.Visibility "circle") (not .UserRelationship.IsInnerCirclePeer)}} + {{else}} {{end}} diff --git a/web/templates/photo/gallery.html b/web/templates/photo/gallery.html index 5f4c24b..cff1b83 100644 --- a/web/templates/photo/gallery.html +++ b/web/templates/photo/gallery.html @@ -192,6 +192,27 @@

    {{end}} + + {{if .ProfilePictureHiddenVisibility}} +
    + + Notice: + @{{.User.Username}}'s default profile picture is set to + {{if eq .ProfilePictureHiddenVisibility "friends"}} + + Friends only + {{else if eq .ProfilePictureHiddenVisibility "circle"}} + + Private + {{else}} + + Private + {{end}} + visibility and can not be seen by you. + Learn more +
    + {{end}} + {{if .InnerCircleInviteView}}