diff --git a/pkg/controller/photo/edit_delete.go b/pkg/controller/photo/edit_delete.go
index 490500d..8893f45 100644
--- a/pkg/controller/photo/edit_delete.go
+++ b/pkg/controller/photo/edit_delete.go
@@ -52,17 +52,20 @@ func Edit() http.HandlerFunc {
caption = r.FormValue("caption")
isExplicit = r.FormValue("explicit") == "true"
isGallery = r.FormValue("gallery") == "true"
- visibility = r.FormValue("visibility")
+ visibility = models.PhotoVisibility(r.FormValue("visibility"))
// Profile pic fields
setProfilePic = r.FormValue("intent") == "profile-pic"
crop = pphoto.ParseCropCoords(r.FormValue("crop"))
+
+ // Are we GOING private?
+ goingPrivate = visibility == models.PhotoPrivate && visibility != photo.Visibility
)
photo.Caption = caption
photo.Explicit = isExplicit
photo.Gallery = isGallery
- photo.Visibility = models.PhotoVisibility(visibility)
+ photo.Visibility = visibility
// Are we cropping ourselves a new profile pic?
log.Error("Profile pic? %+v and crop is: %+v", setProfilePic, crop)
@@ -99,6 +102,12 @@ func Edit() http.HandlerFunc {
// Flash success.
session.Flash(w, r, "Photo settings updated!")
+ // If this picture has moved to Private, revoke any notification we gave about it before.
+ if goingPrivate {
+ log.Info("The picture is GOING PRIVATE, revoke any notifications about it")
+ models.RemoveNotification("photos", photo.ID)
+ }
+
// Whose photo gallery to redirect to? if admin editing a user's photo,
// go back to the owner's gallery instead of our own.
if photo.UserID != currentUser.ID {
diff --git a/pkg/controller/photo/upload.go b/pkg/controller/photo/upload.go
index e539678..91b05da 100644
--- a/pkg/controller/photo/upload.go
+++ b/pkg/controller/photo/upload.go
@@ -131,6 +131,9 @@ func Upload() http.HandlerFunc {
user.Save()
}
+ // Notify all of our friends that we posted a new picture.
+ go notifyFriendsNewPhoto(p, user)
+
session.Flash(w, r, "Your photo has been uploaded successfully.")
templates.Redirect(w, "/photo/u/"+user.Username)
return
@@ -142,3 +145,33 @@ func Upload() http.HandlerFunc {
}
})
}
+
+// Create a notification for all our Friends about a new photo.
+// Run in a background goroutine in case it takes a while.
+func notifyFriendsNewPhoto(photo *models.Photo, currentUser *models.User) {
+ var friendIDs []uint64
+
+ // Who to notify?
+ if photo.Visibility == models.PhotoPrivate {
+ // Private grantees
+ friendIDs = models.PrivateGranteeUserIDs(currentUser.ID)
+ log.Info("Notify %d private grantees about the new photo by %s", len(friendIDs), currentUser.Username)
+ } else {
+ // Friends
+ friendIDs = models.FriendIDs(currentUser.ID)
+ log.Info("Notify %d friends about the new photo by %s", len(friendIDs), currentUser.Username)
+ }
+
+ for _, fid := range friendIDs {
+ notif := &models.Notification{
+ UserID: fid,
+ AboutUser: *currentUser,
+ Type: models.NotificationNewPhoto,
+ TableName: "photos",
+ TableID: photo.ID,
+ }
+ if err := models.CreateNotification(notif); err != nil {
+ log.Error("Couldn't notify user %d about %s's new photo: %s", fid, currentUser.Username, err)
+ }
+ }
+}
diff --git a/pkg/models/notification.go b/pkg/models/notification.go
index 05186f7..3a8e9da 100644
--- a/pkg/models/notification.go
+++ b/pkg/models/notification.go
@@ -39,12 +39,41 @@ const (
NotificationCertRejected = "cert_rejected"
NotificationCertApproved = "cert_approved"
NotificationPrivatePhoto = "private_photo"
+ NotificationNewPhoto = "new_photo"
NotificationCustom = "custom" // custom message pushed
)
// CreateNotification
func CreateNotification(n *Notification) error {
- return DB.Create(n).Error
+ // Insert via raw SQL query, reasoning:
+ // the AboutUser relationship has gorm do way too much work:
+ // - Upsert the user profile photo
+ // - Upsert the user profile fields
+ // - Upsert the user row itself
+ // .. and if we notify all your friends, all these wasteful queries ran
+ // for every single notification created!
+ if n.AboutUserID == nil && n.AboutUser.ID > 0 {
+ n.AboutUserID = &n.AboutUser.ID
+ }
+ return DB.Exec(
+ `
+ INSERT INTO notifications
+ (user_id, about_user_id, type, read, table_name, table_id, message, link, created_at, updated_at)
+ VALUES
+ (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ `,
+ n.UserID,
+ n.AboutUserID,
+ n.Type,
+ false,
+ n.TableName,
+ n.TableID,
+ n.Message,
+ n.Link,
+ time.Now(),
+ time.Now(),
+ ).Error
+ // return DB.Create(n).Error
}
// GetNotification by ID.
diff --git a/pkg/models/private_photo.go b/pkg/models/private_photo.go
index 66ee1cb..675c6ac 100644
--- a/pkg/models/private_photo.go
+++ b/pkg/models/private_photo.go
@@ -89,6 +89,19 @@ func PrivateGrantedUserIDs(userId uint64) []uint64 {
return userIDs
}
+// PrivateGranteeUserIDs are the users whom WE have granted access to our photos (userId is the photo owners).
+func PrivateGranteeUserIDs(userId uint64) []uint64 {
+ var (
+ ps = []*PrivatePhoto{}
+ userIDs = []uint64{}
+ )
+ DB.Where("source_user_id = ?", userId).Find(&ps)
+ for _, row := range ps {
+ userIDs = append(userIDs, row.TargetUserID)
+ }
+ return userIDs
+}
+
/*
PaginatePrivatePhotoList views a user's list of private photo grants.
diff --git a/web/templates/account/dashboard.html b/web/templates/account/dashboard.html
index d343e42..29d5c71 100644
--- a/web/templates/account/dashboard.html
+++ b/web/templates/account/dashboard.html
@@ -322,6 +322,23 @@
has granted you access to see their
private photos!
+ {{else if eq .Type "new_photo"}}
+
+ {{if and $Body.Photo (eq $Body.Photo.Visibility "private")}}
+
+ {{else}}
+
+ {{end}}
+
+
+ {{.AboutUser.Username}}
+ has uploaded a new
+ {{if and $Body.Photo (eq $Body.Photo.Visibility "private")}}
+ private photo!
+ {{else}}
+ photo!
+ {{end}}
+
{{else if eq .Type "cert_approved"}}