website/pkg/controller/photo/private.go
Noah 6c91c67c97 More Private User Avatars
* Users who set their Profile Picture to "friends only" or "private" can have
  their avatar be private all over the website to users who are not their
  friends or not granted access.
* Users who are not your friends see a yellow placeholder avatar, and users
  not granted access to a private Profile Pic sees a purple avatar.
* Admin users see these same placeholder avatars most places too (on search,
  forums, comments, etc.) if the user did not friend or grant the admin. But
  admins ALWAYS see it on their Profile Page directly, for ability to moderate.
* Fix marking Notifications as read: clicking the link in an unread notification
  now will wait on the ajax request to finish before allowing the redirect.
* Update the FAQ
2022-09-08 21:42:20 -07:00

159 lines
4.6 KiB
Go

package photo
import (
"fmt"
"net/http"
"strings"
"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/session"
"code.nonshy.com/nonshy/website/pkg/templates"
)
// Private controller (/photo/private) to see and modify your Private Photo grants.
func Private() http.HandlerFunc {
// Reuse the upload page but with an EditPhoto variable.
tmpl := templates.Must("photo/private.html")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var (
view = r.FormValue("view")
isGrantee = view == "grantee"
)
currentUser, err := session.CurrentUser(r)
if err != nil {
session.FlashError(w, r, "Unexpected error: could not get currentUser.")
templates.Redirect(w, "/")
return
}
// Get the users.
pager := &models.Pagination{
PerPage: config.PageSizePrivatePhotoGrantees,
Sort: "updated_at desc",
}
pager.ParsePage(r)
users, err := models.PaginatePrivatePhotoList(currentUser, isGrantee, pager)
if err != nil {
session.FlashError(w, r, "Couldn't paginate users: %s", err)
templates.Redirect(w, "/")
return
}
var vars = map[string]interface{}{
"IsGrantee": isGrantee,
"CountGrantee": models.CountPrivateGrantee(currentUser.ID),
"Users": users,
"Pager": pager,
}
if err := tmpl.Execute(w, r, vars); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})
}
// Share your private photos with a new user.
func Share() http.HandlerFunc {
tmpl := templates.Must("photo/share.html")
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// To whom?
var (
user *models.User
username = strings.TrimSpace(strings.ToLower(r.FormValue("to")))
isRevokeAll = r.FormValue("intent") == "revoke-all"
)
if username != "" {
if u, err := models.FindUser(username); err != nil {
session.FlashError(w, r, "That username was not found, please try again.")
templates.Redirect(w, r.URL.Path)
return
} else {
user = u
}
}
currentUser, err := session.CurrentUser(r)
if err != nil {
session.FlashError(w, r, "Unexpected error: could not get currentUser.")
templates.Redirect(w, "/")
return
}
// Are we revoking our privates from ALL USERS?
if isRevokeAll {
models.RevokePrivatePhotosAll(currentUser.ID)
session.Flash(w, r, "Your private photos have been locked from ALL users.")
templates.Redirect(w, "/photo/private")
// Remove ALL notifications sent to ALL users who had access before.
models.RemoveNotification("__private_photos", currentUser.ID)
return
}
if user != nil && currentUser.ID == user.ID {
session.FlashError(w, r, "You cannot share your private photos with yourself.")
templates.Redirect(w, r.URL.Path)
return
}
// Any blocking?
if user != nil && models.IsBlocking(currentUser.ID, user.ID) && !currentUser.IsAdmin {
session.FlashError(w, r, "You are blocked from contacting this user.")
templates.Redirect(w, r.URL.Path)
return
}
// POSTing?
if r.Method == http.MethodPost {
var (
intent = r.PostFormValue("intent")
)
// If submitting, do it and redirect.
if intent == "submit" {
models.UnlockPrivatePhotos(currentUser.ID, user.ID)
session.Flash(w, r, "Your private photos have been unlocked for %s.", user.Username)
templates.Redirect(w, "/photo/private")
// Create a notification for this.
notif := &models.Notification{
UserID: user.ID,
AboutUser: *currentUser,
Type: models.NotificationPrivatePhoto,
TableName: "__private_photos",
TableID: currentUser.ID,
Link: fmt.Sprintf("/photo/u/%s", currentUser.Username),
}
if err := models.CreateNotification(notif); err != nil {
log.Error("Couldn't create PrivatePhoto notification: %s", err)
}
return
} else if intent == "revoke" {
models.RevokePrivatePhotos(currentUser.ID, user.ID)
session.Flash(w, r, "You have revoked access to your private photos for %s.", user.Username)
templates.Redirect(w, "/photo/private")
// Remove any notification we created when the grant was given.
models.RemoveSpecificNotification(user.ID, models.NotificationPrivatePhoto, "__private_photos", currentUser.ID)
return
}
// The other intent is "preview" so the user gets the confirmation
// screen before they continue, which shows the selected user info.
}
var vars = map[string]interface{}{
"User": user,
}
if err := tmpl.Execute(w, r, vars); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
})
}