0
0
mirror of https://github.com/go-gitea/gitea.git synced 2024-11-27 23:48:39 +01:00
gitea/models/user/block.go
KN4CK3R c337ff0ec7
Add user blocking (#29028)
Fixes #17453

This PR adds the abbility to block a user from a personal account or
organization to restrict how the blocked user can interact with the
blocker. The docs explain what's the consequence of blocking a user.

Screenshots:


![grafik](https://github.com/go-gitea/gitea/assets/1666336/4ed884f3-e06a-4862-afd3-3b8aa2488dc6)


![grafik](https://github.com/go-gitea/gitea/assets/1666336/ae6d4981-f252-4f50-a429-04f0f9f1cdf1)


![grafik](https://github.com/go-gitea/gitea/assets/1666336/ca153599-5b0f-4b4a-90fe-18bdfd6f0b6b)

---------

Co-authored-by: Lauris BH <lauris@nix.lv>
2024-03-04 08:16:03 +00:00

124 lines
2.9 KiB
Go

// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package user
import (
"context"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
var (
ErrBlockOrganization = util.NewInvalidArgumentErrorf("cannot block an organization")
ErrCanNotBlock = util.NewInvalidArgumentErrorf("cannot block the user")
ErrCanNotUnblock = util.NewInvalidArgumentErrorf("cannot unblock the user")
ErrBlockedUser = util.NewPermissionDeniedErrorf("user is blocked")
)
type Blocking struct {
ID int64 `xorm:"pk autoincr"`
BlockerID int64 `xorm:"UNIQUE(block)"`
Blocker *User `xorm:"-"`
BlockeeID int64 `xorm:"UNIQUE(block)"`
Blockee *User `xorm:"-"`
Note string
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
}
func (*Blocking) TableName() string {
return "user_blocking"
}
func init() {
db.RegisterModel(new(Blocking))
}
func UpdateBlockingNote(ctx context.Context, id int64, note string) error {
_, err := db.GetEngine(ctx).ID(id).Cols("note").Update(&Blocking{Note: note})
return err
}
func IsUserBlockedBy(ctx context.Context, blockee *User, blockerIDs ...int64) bool {
if len(blockerIDs) == 0 {
return false
}
if blockee.IsAdmin {
return false
}
cond := builder.Eq{"user_blocking.blockee_id": blockee.ID}.
And(builder.In("user_blocking.blocker_id", blockerIDs))
has, _ := db.GetEngine(ctx).Where(cond).Exist(&Blocking{})
return has
}
type FindBlockingOptions struct {
db.ListOptions
BlockerID int64
BlockeeID int64
}
func (opts *FindBlockingOptions) ToConds() builder.Cond {
cond := builder.NewCond()
if opts.BlockerID != 0 {
cond = cond.And(builder.Eq{"user_blocking.blocker_id": opts.BlockerID})
}
if opts.BlockeeID != 0 {
cond = cond.And(builder.Eq{"user_blocking.blockee_id": opts.BlockeeID})
}
return cond
}
func FindBlockings(ctx context.Context, opts *FindBlockingOptions) ([]*Blocking, int64, error) {
return db.FindAndCount[Blocking](ctx, opts)
}
func GetBlocking(ctx context.Context, blockerID, blockeeID int64) (*Blocking, error) {
blocks, _, err := FindBlockings(ctx, &FindBlockingOptions{
BlockerID: blockerID,
BlockeeID: blockeeID,
})
if err != nil {
return nil, err
}
if len(blocks) == 0 {
return nil, nil
}
return blocks[0], nil
}
type BlockingList []*Blocking
func (blocks BlockingList) LoadAttributes(ctx context.Context) error {
ids := make(container.Set[int64], len(blocks)*2)
for _, b := range blocks {
ids.Add(b.BlockerID)
ids.Add(b.BlockeeID)
}
userList, err := GetUsersByIDs(ctx, ids.Values())
if err != nil {
return err
}
userMap := make(map[int64]*User, len(userList))
for _, u := range userList {
userMap[u.ID] = u
}
for _, b := range blocks {
b.Blocker = userMap[b.BlockerID]
b.Blockee = userMap[b.BlockeeID]
}
return nil
}