Add notice of private profile pic, inner circle placeholder

* On a user gallery page: if the current user can not see their default
  profile pic (friends-only or private), include a notice and link to
  the FAQ about this.
* Add a new placeholder avatar for profile pics that are set to
  "Inner circle only" when viewed by members outside the circle.
This commit is contained in:
Noah Petherbridge 2024-01-07 14:20:01 -08:00
parent 20388172f0
commit 8fca36836c
11 changed files with 122 additions and 23 deletions

View File

@ -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.

View File

@ -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),

View File

@ -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)

View File

@ -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

View File

@ -58,7 +58,7 @@ img {
}
.has-text-private {
color: #CC00CC;
color: #CC00CC !important;
}
.has-text-private-light {

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -8,17 +8,7 @@
<div class="columns">
<div class="column is-narrow has-text-centered">
<figure class="profile-photo is-inline-block">
{{if .User.ProfilePhoto.ID}}
{{if and (eq .User.ProfilePhoto.Visibility "private") (not .User.UserRelationship.IsPrivateGranted)}}
<img src="/static/img/shy-private.png" data-photo-id="{{.User.ProfilePhoto.ID}}">
{{else if and (eq .User.ProfilePhoto.Visibility "friends") (not .User.UserRelationship.IsFriend)}}
<img src="/static/img/shy-friends.png" data-photo-id="{{.User.ProfilePhoto.ID}}">
{{else}}
<img src="{{PhotoURL .User.ProfilePhoto.CroppedFilename}}" data-photo-id="{{.User.ProfilePhoto.ID}}">
{{end}}
{{else}}
<img src="/static/img/shy.png">
{{end}}
<img src="{{.User.VisibleAvatarURL .CurrentUser}}" data-photo-id="{{.User.ProfilePhoto.ID}}">
<!-- CurrentUser can upload a new profile pic -->
{{if and .LoggedIn (eq .CurrentUser.ID .User.ID) (not .IsPrivate)}}

View File

@ -378,8 +378,40 @@
<a href="/photo/private">granted access</a> to see your
private photos.
</li>
{{if .CurrentUser.IsInnerCircle}}
<li>
<strong>{{PrettyCircle}}</strong>
<img src="/static/img/circle-24.png" width="16" height="16">:
your profile pic displays as a gradient
<img src="/static/img/shy-secret.png" width="16" height="16">
placeholder image for members outside the inner circle.
<ul>
<li>
<strong>Note:</strong> 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."
</li>
</ul>
</li>
{{end}}
</ul>
<p>
Note that it is <strong>required</strong> 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.
</p>
<p>
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.
</p>
<p>
If you find a member whose profile photo you <em>can</em> see, and it also does not include their
face, please <strong>report their profile</strong> to the admin.
</p>
<h3 id="profile-visibility">What are the visibility options for my profile page?</h3>
<p>

View File

@ -27,6 +27,8 @@
<img class="is-rounded" src="/static/img/shy-private.png">
{{else if and (eq $User.ProfilePhoto.Visibility "friends") (not $User.UserRelationship.IsFriend)}}
<img class="is-rounded" src="/static/img/shy-friends.png">
{{else if and (eq $User.ProfilePhoto.Visibility "circle") (not $User.UserRelationship.IsInnerCirclePeer)}}
<img class="is-rounded" src="/static/img/shy-secret.png">
{{else}}
<img class="is-rounded" src="{{PhotoURL $User.ProfilePhoto.CroppedFilename}}">
{{end}}

View File

@ -9,6 +9,8 @@
<img src="/static/img/shy-private.png" class="is-rounded">
{{else if and (eq .ProfilePhoto.Visibility "friends") (not .UserRelationship.IsFriend)}}
<img src="/static/img/shy-friends.png" class="is-rounded">
{{else if and (eq .ProfilePhoto.Visibility "circle") (not .UserRelationship.IsInnerCirclePeer)}}
<img src="/static/img/shy-secret.png">
{{else}}
<img src="{{PhotoURL .ProfilePhoto.CroppedFilename}}" class="is-rounded">
{{end}}
@ -28,6 +30,8 @@
<img src="/static/img/shy-private.png">
{{else if and (eq .ProfilePhoto.Visibility "friends") (not .UserRelationship.IsFriend)}}
<img src="/static/img/shy-friends.png">
{{else if and (eq .ProfilePhoto.Visibility "circle") (not .UserRelationship.IsInnerCirclePeer)}}
<img src="/static/img/shy-secret.png">
{{else}}
<img src="{{PhotoURL .ProfilePhoto.CroppedFilename}}">
{{end}}
@ -47,6 +51,8 @@
<img src="/static/img/shy-private.png">
{{else if and (eq .ProfilePhoto.Visibility "friends") (not .UserRelationship.IsFriend)}}
<img src="/static/img/shy-friends.png">
{{else if and (eq .ProfilePhoto.Visibility "circle") (not .UserRelationship.IsInnerCirclePeer)}}
<img src="/static/img/shy-secret.png">
{{else}}
<img src="{{PhotoURL .ProfilePhoto.CroppedFilename}}">
{{end}}
@ -66,6 +72,8 @@
<img src="/static/img/shy-private.png">
{{else if and (eq .ProfilePhoto.Visibility "friends") (not .UserRelationship.IsFriend)}}
<img src="/static/img/shy-friends.png">
{{else if and (eq .ProfilePhoto.Visibility "circle") (not .UserRelationship.IsInnerCirclePeer)}}
<img src="/static/img/shy-secret.png">
{{else}}
<img src="{{PhotoURL .ProfilePhoto.CroppedFilename}}">
{{end}}
@ -85,6 +93,8 @@
<img class="is-rounded" src="/static/img/shy-private.png">
{{else if and (eq .ProfilePhoto.Visibility "friends") (not .UserRelationship.IsFriend)}}
<img class="is-rounded" src="/static/img/shy-friends.png">
{{else if and (eq .ProfilePhoto.Visibility "circle") (not .UserRelationship.IsInnerCirclePeer)}}
<img src="/static/img/shy-secret.png">
{{else}}
<img class="is-rounded" src="{{PhotoURL .ProfilePhoto.CroppedFilename}}">
{{end}}

View File

@ -192,6 +192,27 @@
</div>
{{end}}
<!-- Notice if the current user can not see the user's default profile picture -->
{{if .ProfilePictureHiddenVisibility}}
<div class="block">
<i class="fa fa-info-circle mr-1"></i>
<strong>Notice:</strong>
@{{.User.Username}}'s default profile picture is set to
{{if eq .ProfilePictureHiddenVisibility "friends"}}
<img src="/static/img/shy-friends.png" width="16" height="16">
<strong class="has-text-warning-dark">Friends only</strong>
{{else if eq .ProfilePictureHiddenVisibility "circle"}}
<img src="/static/img/shy-secret.png" width="16" height="16">
<strong class="has-text-private">Private</strong>
{{else}}
<img src="/static/img/shy-private.png" width="16" height="16">
<strong class="has-text-private">Private</strong>
{{end}}
visibility and can not be seen by you.
<a href="/faq#private-avatar" target="_blank">Learn more <i class="fa fa-external-link"></i></a>
</div>
{{end}}
<!-- Inner circle invite notice -->
{{if .InnerCircleInviteView}}
<div class="notification is-info is-light content">