Tighten up user blocking in Notifications & Comments

The following bugs are resolved:
* A blocked user comments on a Photo that you have also commented on
  (are subscribed to), and you would be notified about their comment.
* A blocked user comments on a Forum Thread that you are subscribed to,
  and you would be notified about their post.
* Comments by blocked users (on photos and forum threads) were visible
  to you after you have blocked them.
This commit is contained in:
Noah Petherbridge 2023-09-16 23:07:32 -07:00
parent ca34f63296
commit b788480eb6
6 changed files with 72 additions and 14 deletions

View File

@ -81,6 +81,14 @@ func Likes() http.HandlerFunc {
return
}
}
// Blocking safety check: if either user blocks the other, liking is not allowed.
if models.IsBlocking(currentUser.ID, user.ID) {
SendJSON(w, http.StatusForbidden, Response{
Error: "You are not allowed to like that photo.",
})
return
}
targetUser = user
}
} else {
@ -91,15 +99,31 @@ func Likes() http.HandlerFunc {
if user, err := models.GetUser(req.TableID); err == nil {
targetUser = user
log.Warn("found user %s", targetUser.Username)
// Blocking safety check: if either user blocks the other, liking is not allowed.
if models.IsBlocking(currentUser.ID, user.ID) {
SendJSON(w, http.StatusForbidden, Response{
Error: "You are not allowed to like that profile.",
})
return
}
} else {
log.Error("For like on users table: didn't find user %d: %s", req.TableID, err)
}
case "comments":
log.Error("subject is users, find %d", req.TableID)
log.Error("subject is comments, find %d", req.TableID)
if comment, err := models.GetComment(req.TableID); err == nil {
targetUser = &comment.User
notificationMessage = comment.Message
log.Warn("found user %s", targetUser.Username)
// Blocking safety check: if either user blocks the other, liking is not allowed.
if models.IsBlocking(currentUser.ID, targetUser.ID) {
SendJSON(w, http.StatusForbidden, Response{
Error: "You are not allowed to like that comment.",
})
return
}
} else {
log.Error("For like on users table: didn't find user %d: %s", req.TableID, err)
}

View File

@ -180,8 +180,8 @@ func PostComment() http.HandlerFunc {
}
}
// Notify subscribers to this comment thread.
for _, userID := range models.GetSubscribers(comment.TableName, comment.TableID) {
// Notify subscribers to this comment thread (filter the subscribers by the blocking status of the current user).
for _, userID := range models.FilterBlockingUserIDs(currentUser, models.GetSubscribers(comment.TableName, comment.TableID)) {
if notifyUser != nil && userID == notifyUser.ID {
// Don't notify the recipient twice.
continue

View File

@ -345,8 +345,8 @@ func NewPost() http.HandlerFunc {
queryString = fmt.Sprintf("?page=%d", lastPage)
}
// Notify watchers about this new post.
for _, userID := range models.GetSubscribers("threads", thread.ID) {
// Notify watchers about this new post. Filter by blocked user IDs.
for _, userID := range models.FilterBlockingUserIDs(currentUser, models.GetSubscribers("threads", thread.ID)) {
if userID == currentUser.ID {
continue
}

View File

@ -84,7 +84,7 @@ func View() http.HandlerFunc {
commentMap := models.MapCommentCounts("photos", []uint64{photo.ID})
// Get all the comments.
comments, err := models.ListComments("photos", photo.ID)
comments, err := models.ListComments(currentUser, "photos", photo.ID)
if err != nil {
log.Error("Couldn't list comments for photo %d: %s", photo.ID, err)
}

View File

@ -109,6 +109,36 @@ func BlockedUserIDs(userId uint64) []uint64 {
return userIDs
}
// MapBlockedUserIDs returns BlockedUserIDs as a lookup hashmap (not for front-end templates currently).
func MapBlockedUserIDs(userId uint64) map[uint64]interface{} {
var (
result = map[uint64]interface{}{}
blockedIDs = BlockedUserIDs(userId)
)
for _, uid := range blockedIDs {
result[uid] = nil
}
return result
}
// FilterBlockingUserIDs narrows down a set of User IDs to remove ones that block (or are blocked by) the current user.
func FilterBlockingUserIDs(currentUser *User, userIDs []uint64) []uint64 {
var (
// Get the IDs to exclude.
blockedIDs = MapBlockedUserIDs(currentUser.ID)
// Filter the result.
result = []uint64{}
)
for _, uid := range userIDs {
if _, ok := blockedIDs[uid]; ok {
continue
}
result = append(result, uid)
}
return result
}
// BlockedUserIDsByUser returns all user IDs blocked by the user (one directional only)
func BlockedUserIDsByUser(userId uint64) []uint64 {
var (

View File

@ -70,11 +70,12 @@ func PaginateComments(user *User, tableName string, tableID uint64, pager *Pagin
var (
cs = []*Comment{}
query = (&Comment{}).Preload()
blockedUserIDs = BlockedUserIDs(user.ID)
)
query = query.Where(
"table_name = ? AND table_id = ?",
tableName, tableID,
"table_name = ? AND table_id = ? AND user_id NOT IN ?",
tableName, tableID, blockedUserIDs,
).Order(pager.Sort)
query.Model(&Comment{}).Count(&pager.Total)
@ -87,11 +88,14 @@ func PaginateComments(user *User, tableName string, tableID uint64, pager *Pagin
}
// ListComments returns a complete set of comments without paging.
func ListComments(tableName string, tableID uint64) ([]*Comment, error) {
var cs []*Comment
func ListComments(user *User, tableName string, tableID uint64) ([]*Comment, error) {
var (
cs []*Comment
blockedUserIDs = BlockedUserIDs(user.ID)
)
result := (&Comment{}).Preload().Where(
"table_name = ? AND table_id = ?",
tableName, tableID,
"table_name = ? AND table_id = ? AND user_id NOT IN ?",
tableName, tableID, blockedUserIDs,
).Order("created_at asc").Find(&cs)
return cs, result.Error
}