Mute specific friends new photo upload notifications
This commit is contained in:
parent
01c38c5c21
commit
147a9162ba
|
@ -28,12 +28,26 @@ func Subscription() http.HandlerFunc {
|
|||
templates.Redirect(w, "/")
|
||||
return
|
||||
} else {
|
||||
if idInt, err := strconv.Atoi(idStr); err != nil {
|
||||
session.FlashError(w, r, "Comment table ID invalid.")
|
||||
templates.Redirect(w, "/")
|
||||
return
|
||||
} else {
|
||||
tableID = uint64(idInt)
|
||||
// Is the table_id expected to be a username?
|
||||
switch tableName {
|
||||
case "friend.photos":
|
||||
// Special "Friend uploaded a new photo" opt-out.
|
||||
if user, err := models.FindUser(idStr); err != nil {
|
||||
session.FlashError(w, r, "Username not found!")
|
||||
templates.Redirect(w, "/")
|
||||
return
|
||||
} else {
|
||||
tableID = user.ID
|
||||
}
|
||||
default:
|
||||
// Integer IDs in all other cases.
|
||||
if idInt, err := strconv.Atoi(idStr); err != nil {
|
||||
session.FlashError(w, r, "Comment table ID invalid.")
|
||||
templates.Redirect(w, "/")
|
||||
return
|
||||
} else {
|
||||
tableID = uint64(idInt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,7 +61,7 @@ func Subscription() http.HandlerFunc {
|
|||
}
|
||||
|
||||
// Validate everything else.
|
||||
if _, ok := models.CommentableTables[tableName]; !ok {
|
||||
if _, ok := models.SubscribableTables[tableName]; !ok {
|
||||
session.FlashError(w, r, "You can not comment on that.")
|
||||
templates.Redirect(w, "/")
|
||||
return
|
||||
|
@ -61,6 +75,12 @@ func Subscription() http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
// Language to use in the flash messages.
|
||||
var kind = "comments"
|
||||
if tableName == "friend.photos" {
|
||||
kind = "new photo uploads"
|
||||
}
|
||||
|
||||
// Get their subscription.
|
||||
sub, err := models.GetSubscription(currentUser, tableName, tableID)
|
||||
if err != nil {
|
||||
|
@ -69,7 +89,15 @@ func Subscription() http.HandlerFunc {
|
|||
if _, err := models.SubscribeTo(currentUser, tableName, tableID); err != nil {
|
||||
session.FlashError(w, r, "Couldn't create subscription: %s", err)
|
||||
} else {
|
||||
session.Flash(w, r, "You will now be notified about comments on this page.")
|
||||
session.Flash(w, r, "You will now be notified about %s on this page.", kind)
|
||||
}
|
||||
} else {
|
||||
// An explicit subscribe=false, may be a preemptive opt-out as in
|
||||
// friend new photo notifications.
|
||||
if _, err := models.UnsubscribeTo(currentUser, tableName, tableID); err != nil {
|
||||
session.FlashError(w, r, "Couldn't create subscription: %s", err)
|
||||
} else {
|
||||
session.Flash(w, r, "You will no longer be notified about %s on this page.", kind)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -79,9 +107,9 @@ func Subscription() http.HandlerFunc {
|
|||
session.FlashError(w, r, "Couldn't save your subscription settings: %s", err)
|
||||
} else {
|
||||
if subscribe {
|
||||
session.Flash(w, r, "You will now be notified about comments on this page.")
|
||||
session.Flash(w, r, "You will now be notified about %s on this page.", kind)
|
||||
} else {
|
||||
session.Flash(w, r, "You will no longer be notified about new comments on that thread.")
|
||||
session.Flash(w, r, "You will no longer be notified about new %s on this page.", kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -195,6 +195,16 @@ func UserPhotos() http.HandlerFunc {
|
|||
profilePictureHidden = visibility
|
||||
}
|
||||
|
||||
// Friend Photos Notification Opt-out:
|
||||
// If your friend posts too many photos and you want to mute them.
|
||||
// NOTE: notifications are "on by default" and only an explicit "false"
|
||||
// stored in the database indicates an opt-out.
|
||||
// New photo upload notification subscription status.
|
||||
var areNotificationsMuted bool
|
||||
if exists, v := models.IsSubscribed(currentUser, "friend.photos", user.ID); exists {
|
||||
areNotificationsMuted = !v
|
||||
}
|
||||
|
||||
var vars = map[string]interface{}{
|
||||
"IsOwnPhotos": currentUser.ID == user.ID,
|
||||
"IsShyUser": isShy,
|
||||
|
@ -202,6 +212,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,
|
||||
"AreNotificationsMuted": areNotificationsMuted,
|
||||
"ProfilePictureHiddenVisibility": profilePictureHidden,
|
||||
"User": user,
|
||||
"Photos": photos,
|
||||
|
|
|
@ -29,6 +29,16 @@ var CommentableTables = map[string]interface{}{
|
|||
"threads": nil,
|
||||
}
|
||||
|
||||
// SubscribableTables are the set of table names that allow notification subscriptions.
|
||||
var SubscribableTables = map[string]interface{}{
|
||||
"photos": nil,
|
||||
"threads": nil,
|
||||
|
||||
// Special case: new photo uploads from your friends. You can't comment on this,
|
||||
// but you can (un)subscribe from it all the same.
|
||||
"friend.photos": nil,
|
||||
}
|
||||
|
||||
// Preload related tables for the forum (classmethod).
|
||||
func (c *Comment) Preload() *gorm.DB {
|
||||
return DB.Preload("User.ProfilePhoto")
|
||||
|
|
|
@ -288,8 +288,10 @@ func FilterPhotoUploadNotificationUserIDs(photo *Photo, userIDs []uint64) []uint
|
|||
result = []uint64{}
|
||||
|
||||
// Collect notification opt-out profile fields and map them by user ID for easy lookup.
|
||||
prefs = []*ProfileField{}
|
||||
prefs = []*ProfileField{} // Global Notification preferences
|
||||
mutes = []*Subscription{} // Individual "friend.photos" notification mutes
|
||||
mapPrefs = map[uint64]map[string]bool{}
|
||||
mapMutes = map[uint64]bool{}
|
||||
)
|
||||
if len(userIDs) == 0 {
|
||||
return userIDs
|
||||
|
@ -308,6 +310,15 @@ func FilterPhotoUploadNotificationUserIDs(photo *Photo, userIDs []uint64) []uint
|
|||
log.Error("FilterPhotoUploadNotificationUserIDs: couldn't collect user preferences: %s", r.Error)
|
||||
}
|
||||
|
||||
// Collect any muted notification threads, e.g. the user doesn't want your new photo notifications.
|
||||
r = DB.Model(&Subscription{}).Where(
|
||||
"table_name = 'friend.photos' AND table_id = ? AND subscribed IS FALSE",
|
||||
photo.UserID,
|
||||
).Find(&mutes)
|
||||
if r.Error != nil {
|
||||
log.Error("FilterPhotoUploadNotificationUserIDs: couldn't collect user notification mutes: %s", r.Error)
|
||||
}
|
||||
|
||||
// Map the preferences by user ID.
|
||||
for _, row := range prefs {
|
||||
if _, ok := mapPrefs[row.UserID]; !ok {
|
||||
|
@ -315,6 +326,9 @@ func FilterPhotoUploadNotificationUserIDs(photo *Photo, userIDs []uint64) []uint
|
|||
}
|
||||
mapPrefs[row.UserID][row.Name] = row.Value == "true"
|
||||
}
|
||||
for _, row := range mutes {
|
||||
mapMutes[row.UserID] = true
|
||||
}
|
||||
|
||||
// Narrow the notification recipients based on photo property and their preferences.
|
||||
for _, userID := range userIDs {
|
||||
|
@ -333,6 +347,11 @@ func FilterPhotoUploadNotificationUserIDs(photo *Photo, userIDs []uint64) []uint
|
|||
continue
|
||||
}
|
||||
|
||||
// They muted your friend "new photo" notifications?
|
||||
if mapMutes[userID] {
|
||||
continue
|
||||
}
|
||||
|
||||
// They get the notification.
|
||||
result = append(result, userID)
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ type Subscription struct {
|
|||
ID uint64 `gorm:"primaryKey"`
|
||||
UserID uint64 `gorm:"index"` // who it belongs to
|
||||
Subscribed bool `gorm:"index"`
|
||||
TableName string // on which of your tables (photos, comments, ...)
|
||||
TableID uint64
|
||||
TableName string `gorm:"index"` // on which of your tables (photos, comments, ...)
|
||||
TableID uint64 `gorm:"index"`
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
@ -81,6 +81,9 @@ func IsSubscribed(user *User, tableName string, tableID uint64) (exists bool, no
|
|||
}
|
||||
|
||||
// SubscribeTo creates a subscription to a thing (comment thread) to be notified of future activity on.
|
||||
//
|
||||
// If a Subscription row already exists, it is NOT modified. So if a user has expressly opted out of a
|
||||
// comment thread, they do not get re-subscribed when they comment on it again.
|
||||
func SubscribeTo(user *User, tableName string, tableID uint64) (*Subscription, error) {
|
||||
// Is there already a subscription row?
|
||||
if sub, err := GetSubscription(user, tableName, tableID); err == nil {
|
||||
|
@ -98,6 +101,26 @@ func SubscribeTo(user *User, tableName string, tableID uint64) (*Subscription, e
|
|||
return sub, result.Error
|
||||
}
|
||||
|
||||
// UnsubscribeTo will create an explicit opt-out Subscription only if no subscription exists.
|
||||
//
|
||||
// It is the inverse of SubscribeTo.
|
||||
func UnsubscribeTo(user *User, tableName string, tableID uint64) (*Subscription, error) {
|
||||
// Is there already a subscription row?
|
||||
if sub, err := GetSubscription(user, tableName, tableID); err == nil {
|
||||
return sub, err
|
||||
}
|
||||
|
||||
// Create the default subscription.
|
||||
sub := &Subscription{
|
||||
UserID: user.ID,
|
||||
Subscribed: false,
|
||||
TableName: tableName,
|
||||
TableID: tableID,
|
||||
}
|
||||
result := DB.Create(sub)
|
||||
return sub, result.Error
|
||||
}
|
||||
|
||||
// Save a subscription.
|
||||
func (n *Subscription) Save() error {
|
||||
return DB.Save(n).Error
|
||||
|
|
|
@ -669,10 +669,19 @@
|
|||
<a href="/comments/subscription?table_name={{.TableName}}&table_id={{.TableID}}&next={{UrlEncode $Root.Request.URL.String}}&subscribe=false"
|
||||
class="has-text-warning is-small"
|
||||
title="Turn off notifications about this thread"
|
||||
onclick="return confirm('Do you want to turn off notifications about this comment thread?')">
|
||||
onclick="return confirm('Do you want to TURN OFF notifications about this comment thread?')">
|
||||
<i class="fa fa-microphone-slash mr-1"></i> Mute this thread
|
||||
</a>
|
||||
</small>
|
||||
{{else if eq .Type "new_photo"}}
|
||||
<small>
|
||||
<a href="/comments/subscription?table_name=friend.photos&table_id={{.AboutUser.Username}}&next={{UrlEncode $Root.Request.URL.String}}&subscribe=false"
|
||||
class="has-text-warning is-small"
|
||||
title="Turn off notifications about @{{.AboutUser.Username}}'s new photo uploads"
|
||||
onclick="return confirm('Do you want to TURN OFF notifications about @{{.AboutUser.Username}}\'s new photo uploads?\n\nNote: to re-subscribe to their new photo notifications, see the link at the top of @{{.AboutUser.Username}}\'s Photo Gallery page.')">
|
||||
<i class="fa fa-microphone-slash mr-1"></i> Mute these notifications
|
||||
</a>
|
||||
</small>
|
||||
{{end}}
|
||||
</small>
|
||||
</div>
|
||||
|
|
|
@ -255,7 +255,7 @@
|
|||
{{end}}
|
||||
|
||||
<div class="block">
|
||||
<div class="level">
|
||||
<div class="level mb-2">
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
{{if .Pager.Total}}
|
||||
|
@ -290,6 +290,23 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Show an "Unsubscribe to this user's new photo notifications" if you are Friends. -->
|
||||
{{if .AreFriends}}
|
||||
<p class="block">
|
||||
<a href="/comments/subscription?table_name=friend.photos&table_id={{.User.Username}}&next={{UrlEncode .Request.URL.String}}&subscribe={{if .AreNotificationsMuted}}true{{else}}false{{end}}"
|
||||
class="{{if .AreNotificationsMuted}}has-text-success{{else}}{{end}}">
|
||||
<span class="icon"><i class="fa fa-bell{{if not .AreNotificationsMuted}}-slash{{end}}"></i></span>
|
||||
<span>
|
||||
{{if .AreNotificationsMuted}}
|
||||
Enable notifications about <strong>{{.User.Username}}</strong>'s new photos
|
||||
{{else}}
|
||||
Mute notifications about <strong>{{.User.Username}}</strong>'s new photos
|
||||
{{end}}
|
||||
</span>
|
||||
</a>
|
||||
</p>
|
||||
{{end}}
|
||||
|
||||
<!-- If viewing our own profile, and we don't have a profile picture set, offer advice. -->
|
||||
{{if and (not .IsSiteGallery) (eq .CurrentUser.ProfilePhoto.ID 0) (eq .CurrentUser.ID .User.ID)}}
|
||||
<div class="notification is-success is-light content">
|
||||
|
|
Loading…
Reference in New Issue
Block a user