Noah
030fadcf8d
Implement block lists. They work like friend lists but are unidirectional, but take effect in both directions (blocker and blockee can not see one another on the site -- except admin users can always see all users). * Profile page says 404 * User gallery says 404 * User search page filters out blocked users * Compose endpoint blocks sending messages to blocked users (except admin) * Site Gallery filters photos by blocked (and uncertified) users * Inbox page hides chat list for blocked users (can still read the chat history if you have a link to the old thread)
125 lines
2.8 KiB
Go
125 lines
2.8 KiB
Go
package models
|
|
|
|
import (
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// Block table.
|
|
type Block struct {
|
|
ID uint64 `gorm:"primaryKey"`
|
|
SourceUserID uint64 `gorm:"index"`
|
|
TargetUserID uint64 `gorm:"index"`
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
// AddBlock is sourceUserId adding targetUserId to their block list.
|
|
func AddBlock(sourceUserID, targetUserID uint64) error {
|
|
// Unfriend in the process.
|
|
RemoveFriend(sourceUserID, targetUserID)
|
|
|
|
// Did we already block this user?
|
|
var b *Block
|
|
forward := DB.Where(
|
|
"source_user_id = ? AND target_user_id = ?",
|
|
sourceUserID, targetUserID,
|
|
).First(&b).Error
|
|
|
|
// Update existing.
|
|
if forward == nil {
|
|
return nil
|
|
}
|
|
|
|
// Create the block.
|
|
b = &Block{
|
|
SourceUserID: sourceUserID,
|
|
TargetUserID: targetUserID,
|
|
}
|
|
return DB.Create(b).Error
|
|
}
|
|
|
|
// IsBlocking quickly sees if either user blocks the other.
|
|
func IsBlocking(sourceUserID, targetUserID uint64) bool {
|
|
b := &Block{}
|
|
result := DB.Where(
|
|
"(source_user_id = ? AND target_user_id = ?) OR "+
|
|
"(target_user_id = ? AND source_user_id = ?)",
|
|
sourceUserID, targetUserID,
|
|
sourceUserID, targetUserID,
|
|
).First(&b)
|
|
return result.Error == nil
|
|
}
|
|
|
|
// IsBlocked quickly checks if sourceUserID currently blocks targetUserID.
|
|
func IsBlocked(sourceUserID, targetUserID uint64) bool {
|
|
b := &Block{}
|
|
result := DB.Where(
|
|
"source_user_id = ? AND target_user_id = ?",
|
|
sourceUserID, targetUserID,
|
|
).First(&b)
|
|
return result.Error == nil
|
|
}
|
|
|
|
// PaginateBlockList views a user's blocklist.
|
|
func PaginateBlockList(userID uint64, pager *Pagination) ([]*User, error) {
|
|
// We paginate over the Block table.
|
|
var (
|
|
bs = []*Block{}
|
|
userIDs = []uint64{}
|
|
query *gorm.DB
|
|
)
|
|
|
|
query = DB.Where(
|
|
"source_user_id = ?",
|
|
userID,
|
|
)
|
|
|
|
query = query.Order(pager.Sort)
|
|
query.Model(&Block{}).Count(&pager.Total)
|
|
result := query.Offset(pager.GetOffset()).Limit(pager.PerPage).Find(&bs)
|
|
if result.Error != nil {
|
|
return nil, result.Error
|
|
}
|
|
|
|
// Now of these friends get their User objects.
|
|
for _, b := range bs {
|
|
userIDs = append(userIDs, b.TargetUserID)
|
|
}
|
|
|
|
return GetUsers(userIDs)
|
|
}
|
|
|
|
// BlockedUserIDs returns all user IDs blocked by the user.
|
|
func BlockedUserIDs(userId uint64) []uint64 {
|
|
var (
|
|
bs = []*Block{}
|
|
userIDs = []uint64{}
|
|
)
|
|
DB.Where("source_user_id = ? OR target_user_id = ?", userId, userId).Find(&bs)
|
|
for _, row := range bs {
|
|
for _, uid := range []uint64{row.TargetUserID, row.SourceUserID} {
|
|
if uid != userId {
|
|
userIDs = append(userIDs, uid)
|
|
}
|
|
}
|
|
}
|
|
return userIDs
|
|
}
|
|
|
|
// UnblockUser removes targetUserID from your blocklist.
|
|
func UnblockUser(sourceUserID, targetUserID uint64) error {
|
|
result := DB.Where(
|
|
"source_user_id = ? AND target_user_id = ?",
|
|
sourceUserID, targetUserID,
|
|
).Delete(&Block{})
|
|
return result.Error
|
|
}
|
|
|
|
// Save photo.
|
|
func (b *Block) Save() error {
|
|
result := DB.Save(b)
|
|
return result.Error
|
|
}
|