Tweak admin permissions and photo view counts
* Profile pictures on profile pages now link to the gallery when clicked. * Admins can no longer automatically see the default profile pic on profile pages unless they have photo moderator ability. * Photo view counts are not added when an admin with photo moderator ability should not have otherwise been able to see the photo.
This commit is contained in:
parent
3fdae1d8d7
commit
f2e847922f
|
@ -72,9 +72,9 @@ func Profile() http.HandlerFunc {
|
|||
// Inject relationship booleans for profile picture display.
|
||||
models.SetUserRelationships(currentUser, []*models.User{user})
|
||||
|
||||
// Admin user can always see the profile pic - but only on this page. Other avatar displays
|
||||
// will show the yellow or pink shy.png if the admin is not friends or not granted.
|
||||
if currentUser.IsAdmin {
|
||||
// Admin user (photo moderator) can always see the profile pic - but only on this page.
|
||||
// Other avatar displays will show the yellow or pink shy.png if the admin is not friends or not granted.
|
||||
if currentUser.HasAdminScope(config.ScopePhotoModerator) {
|
||||
user.UserRelationship.IsFriend = true
|
||||
user.UserRelationship.IsPrivateGranted = true
|
||||
}
|
||||
|
|
|
@ -98,20 +98,7 @@ func Likes() http.HandlerFunc {
|
|||
if user, err := models.GetUser(photo.UserID); err == nil {
|
||||
// Safety check: if the current user should not see this picture, they can not "Like" it.
|
||||
// Example: you unfriended them but they still had the image on their old browser page.
|
||||
var unallowed bool
|
||||
if currentUser.ID != user.ID {
|
||||
if (photo.Visibility == models.PhotoFriends && !models.AreFriends(user.ID, currentUser.ID)) ||
|
||||
(photo.Visibility == models.PhotoPrivate && !models.IsPrivateUnlocked(user.ID, currentUser.ID)) {
|
||||
unallowed = true
|
||||
}
|
||||
}
|
||||
|
||||
// Blocking safety check: if either user blocks the other, liking is not allowed.
|
||||
if models.IsBlocking(currentUser.ID, user.ID) {
|
||||
unallowed = true
|
||||
}
|
||||
|
||||
if unallowed {
|
||||
if ok, _ := photo.ShouldBeSeenBy(currentUser); !ok {
|
||||
SendJSON(w, http.StatusForbidden, Response{
|
||||
Error: "You are not allowed to like that photo.",
|
||||
})
|
||||
|
@ -121,7 +108,7 @@ func Likes() http.HandlerFunc {
|
|||
// Mark this photo as 'viewed' if it received a like.
|
||||
// Example: on a gallery view the photo is only 'viewed' if interacted with (lightbox),
|
||||
// going straight for the 'Like' button should count as well.
|
||||
photo.View(currentUser.ID)
|
||||
photo.View(currentUser)
|
||||
|
||||
targetUser = user
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ func ViewPhoto() http.HandlerFunc {
|
|||
}
|
||||
|
||||
// Check permission to have seen this photo.
|
||||
if ok, err := photo.CanBeSeenBy(currentUser); !ok {
|
||||
if ok, err := photo.ShouldBeSeenBy(currentUser); !ok {
|
||||
log.Error("Photo %d can't be seen by %s: %s", photo.ID, currentUser.Username, err)
|
||||
SendJSON(w, http.StatusNotFound, Response{
|
||||
Error: "Photo Not Found",
|
||||
|
@ -58,7 +58,7 @@ func ViewPhoto() http.HandlerFunc {
|
|||
}
|
||||
|
||||
// Mark a view.
|
||||
if err := photo.View(currentUser.ID); err != nil {
|
||||
if err := photo.View(currentUser); err != nil {
|
||||
log.Error("Update photo(%d) views: %s", photo.ID, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ func View() http.HandlerFunc {
|
|||
_, isSubscribed := models.IsSubscribed(currentUser, "photos", photo.ID)
|
||||
|
||||
// Mark this photo as "Viewed" by the user.
|
||||
if err := photo.View(currentUser.ID); err != nil {
|
||||
if err := photo.View(currentUser); err != nil {
|
||||
log.Error("Update photo(%d) views: %s", photo.ID, err)
|
||||
}
|
||||
|
||||
|
|
|
@ -109,8 +109,27 @@ func GetPhotos(IDs []uint64) (map[uint64]*Photo, error) {
|
|||
|
||||
// CanBeSeenBy checks whether a photo can be seen by the current user.
|
||||
//
|
||||
// An admin user with omni photo view permission can always see the photo.
|
||||
//
|
||||
// Note: this function incurs several DB queries to look up the photo's owner and block lists.
|
||||
func (p *Photo) CanBeSeenBy(currentUser *User) (bool, error) {
|
||||
// Admins with photo moderator ability can always see.
|
||||
if currentUser.HasAdminScope(config.ScopePhotoModerator) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return p.ShouldBeSeenBy(currentUser)
|
||||
}
|
||||
|
||||
// ShouldBeSeenBy checks whether a photo should be seen by the current user.
|
||||
//
|
||||
// Even if the current user is an admin with photo moderator ability, this function will return
|
||||
// whether the admin 'should' be able to see if not for their admin status. Example: a private
|
||||
// photo may be shown to the admin so they can moderate it, but they shouldn't be able to "like"
|
||||
// it or mark it as "viewed."
|
||||
//
|
||||
// Note: this function incurs several DB queries to look up the photo's owner and block lists.
|
||||
func (p *Photo) ShouldBeSeenBy(currentUser *User) (bool, error) {
|
||||
// Find the photo's owner.
|
||||
user, err := GetUser(p.UserID)
|
||||
if err != nil {
|
||||
|
@ -120,7 +139,7 @@ func (p *Photo) CanBeSeenBy(currentUser *User) (bool, error) {
|
|||
var isOwnPhoto = currentUser.ID == user.ID
|
||||
|
||||
// Is either one blocking?
|
||||
if !currentUser.IsAdmin && IsBlocking(currentUser.ID, user.ID) {
|
||||
if IsBlocking(currentUser.ID, user.ID) {
|
||||
return false, errors.New("is blocking")
|
||||
}
|
||||
|
||||
|
@ -129,13 +148,13 @@ func (p *Photo) CanBeSeenBy(currentUser *User) (bool, error) {
|
|||
areFriends = AreFriends(user.ID, currentUser.ID)
|
||||
isPrivate = user.Visibility == UserVisibilityPrivate && !areFriends
|
||||
)
|
||||
if isPrivate && !currentUser.IsAdmin && !isOwnPhoto {
|
||||
if isPrivate && !isOwnPhoto {
|
||||
return false, errors.New("user is private and we aren't friends")
|
||||
}
|
||||
|
||||
// Is this a private photo and are we allowed to see?
|
||||
isGranted := IsPrivateUnlocked(user.ID, currentUser.ID)
|
||||
if p.Visibility == PhotoPrivate && !isGranted && !isOwnPhoto && !currentUser.IsAdmin {
|
||||
if p.Visibility == PhotoPrivate && !isGranted && !isOwnPhoto {
|
||||
return false, errors.New("photo is private")
|
||||
}
|
||||
|
||||
|
@ -193,14 +212,19 @@ func PaginateUserPhotos(userID uint64, conf UserGallery, pager *Pagination) ([]*
|
|||
|
||||
// View a photo, incrementing its Views count but not its UpdatedAt.
|
||||
// Debounced with a Redis key.
|
||||
func (p *Photo) View(userID uint64) error {
|
||||
func (p *Photo) View(user *User) error {
|
||||
// The owner of the photo does not count views.
|
||||
if p.UserID == userID {
|
||||
if p.UserID == user.ID {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Should the viewer be able to see this, regardless of their admin ability?
|
||||
if ok, err := p.ShouldBeSeenBy(user); !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
// Debounce this.
|
||||
var redisKey = fmt.Sprintf(config.PhotoViewDebounceRedisKey, userID, p.ID)
|
||||
var redisKey = fmt.Sprintf(config.PhotoViewDebounceRedisKey, user.ID, p.ID)
|
||||
if redis.Exists(redisKey) {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -42,6 +42,8 @@ func SetUserRelationships(currentUser *User, users []*User) error {
|
|||
|
||||
// Inject the UserRelationships.
|
||||
for _, u := range users {
|
||||
u.UserRelationship.Computed = true
|
||||
|
||||
if u.ID == currentUser.ID {
|
||||
// Current user - set both bools to true - you can always see your own profile pic.
|
||||
u.UserRelationship.IsFriend = true
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
{{if or (not .CurrentUser) .IsExternalView}}
|
||||
<img src="{{.User.VisibleAvatarURL nil}}" data-photo-id="{{.User.ProfilePhoto.ID}}">
|
||||
{{else}}
|
||||
<img src="{{.User.VisibleAvatarURL .CurrentUser}}" data-photo-id="{{.User.ProfilePhoto.ID}}">
|
||||
<a href="/u/{{.User.Username}}/photos">
|
||||
<img src="{{.User.VisibleAvatarURL .CurrentUser}}" data-photo-id="{{.User.ProfilePhoto.ID}}">
|
||||
</a>
|
||||
{{end}}
|
||||
|
||||
<!-- CurrentUser can upload a new profile pic -->
|
||||
|
|
|
@ -804,7 +804,7 @@
|
|||
}).then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.StatusCode !== 200) {
|
||||
window.alert(data.data.error);
|
||||
console.error("When marking photo %d as viewed: status code %d: %s", photoID, data.StatusCode, data.data.error);
|
||||
return;
|
||||
}
|
||||
}).catch(window.alert);
|
||||
|
|
Loading…
Reference in New Issue
Block a user