package models import ( "time" "code.nonshy.com/nonshy/website/pkg/log" "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(user *User, pager *Pagination) ([]*User, error) { // We paginate over the Block table. var ( bs = []*Block{} userIDs = []uint64{} query *gorm.DB ) query = DB.Where( "source_user_id = ?", user.ID, ) 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(user, userIDs) } // BlockedUserIDs returns all user IDs blocked by the user (bidirectional, source or target 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 } // 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 ( bs = []*Block{} userIDs = []uint64{} ) DB.Where("source_user_id = ?", userId).Find(&bs) for _, row := range bs { for _, uid := range []uint64{row.TargetUserID, row.SourceUserID} { if uid != userId { userIDs = append(userIDs, uid) } } } return userIDs } // BlockedUsernames returns all usernames blocked by (or blocking) the user. func BlockedUsernames(userId uint64) []string { var ( userIDs = BlockedUserIDs(userId) usernames = []string{} ) if len(userIDs) == 0 { return usernames } if res := DB.Table( "users", ).Select( "username", ).Where( "id IN ?", userIDs, ).Scan(&usernames); res.Error != nil { log.Error("BlockedUsernames(%d): %s", userId, res.Error) } return usernames } // 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 }