diff options
author | yp05327 <576951401@qq.com> | 2024-01-15 15:51:43 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-15 06:51:43 +0000 |
commit | ce0225c1b87d682f53b87496c8dd6ccee0396f0b (patch) | |
tree | 2ab05a9d17869c2a16e5d0e21522106043d823d5 /models | |
parent | b820019fec1bd955b6cb9dba1ce2f2571924ae64 (diff) | |
download | gitea-ce0225c1b87d682f53b87496c8dd6ccee0396f0b.tar.gz gitea-ce0225c1b87d682f53b87496c8dd6ccee0396f0b.zip |
Forbid removing the last admin user (#28337)
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Diffstat (limited to 'models')
-rw-r--r-- | models/error.go | 15 | ||||
-rw-r--r-- | models/user/user.go | 29 |
2 files changed, 40 insertions, 4 deletions
diff --git a/models/error.go b/models/error.go index b7bb967b73..83dfe29805 100644 --- a/models/error.go +++ b/models/error.go @@ -57,6 +57,21 @@ func (err ErrUserOwnPackages) Error() string { return fmt.Sprintf("user still has ownership of packages [uid: %d]", err.UID) } +// ErrDeleteLastAdminUser represents a "DeleteLastAdminUser" kind of error. +type ErrDeleteLastAdminUser struct { + UID int64 +} + +// IsErrDeleteLastAdminUser checks if an error is a ErrDeleteLastAdminUser. +func IsErrDeleteLastAdminUser(err error) bool { + _, ok := err.(ErrDeleteLastAdminUser) + return ok +} + +func (err ErrDeleteLastAdminUser) Error() string { + return fmt.Sprintf("can not delete the last admin user [uid: %d]", err.UID) +} + // ErrNoPendingRepoTransfer is an error type for repositories without a pending // transfer request type ErrNoPendingRepoTransfer struct { diff --git a/models/user/user.go b/models/user/user.go index 204c8f41b6..6d1b1aef18 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -730,9 +730,18 @@ func CreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOve return committer.Commit() } +// IsLastAdminUser check whether user is the last admin +func IsLastAdminUser(ctx context.Context, user *User) bool { + if user.IsAdmin && CountUsers(ctx, &CountUserFilter{IsAdmin: util.OptionalBoolTrue}) <= 1 { + return true + } + return false +} + // CountUserFilter represent optional filters for CountUsers type CountUserFilter struct { LastLoginSince *int64 + IsAdmin util.OptionalBool } // CountUsers returns number of users. @@ -741,13 +750,25 @@ func CountUsers(ctx context.Context, opts *CountUserFilter) int64 { } func countUsers(ctx context.Context, opts *CountUserFilter) int64 { - sess := db.GetEngine(ctx).Where(builder.Eq{"type": "0"}) + sess := db.GetEngine(ctx) + cond := builder.NewCond() + cond = cond.And(builder.Eq{"type": UserTypeIndividual}) - if opts != nil && opts.LastLoginSince != nil { - sess = sess.Where(builder.Gte{"last_login_unix": *opts.LastLoginSince}) + if opts != nil { + if opts.LastLoginSince != nil { + cond = cond.And(builder.Gte{"last_login_unix": *opts.LastLoginSince}) + } + + if !opts.IsAdmin.IsNone() { + cond = cond.And(builder.Eq{"is_admin": opts.IsAdmin.IsTrue()}) + } + } + + count, err := sess.Where(cond).Count(new(User)) + if err != nil { + log.Error("user.countUsers: %v", err) } - count, _ := sess.Count(new(User)) return count } |