aboutsummaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
authoryp05327 <576951401@qq.com>2024-01-15 15:51:43 +0900
committerGitHub <noreply@github.com>2024-01-15 06:51:43 +0000
commitce0225c1b87d682f53b87496c8dd6ccee0396f0b (patch)
tree2ab05a9d17869c2a16e5d0e21522106043d823d5 /models
parentb820019fec1bd955b6cb9dba1ce2f2571924ae64 (diff)
downloadgitea-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.go15
-rw-r--r--models/user/user.go29
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
}