forked from mirror/gitea
c337ff0ec7
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>
124 lines
2.9 KiB
Go
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
|
|
}
|