feat(user-management): Enhance admin management and role handling

pull/9231/head^2 v3.47.0
千石 2025-07-29 19:45:28 +08:00 committed by GitHub
commit 55b2bb6b80
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 39 additions and 5 deletions

View File

@ -2,6 +2,7 @@ package db
import (
"encoding/base64"
"fmt"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/go-webauthn/webauthn/webauthn"
@ -140,3 +141,13 @@ func UpdateUserBasePathPrefix(oldPath, newPath string) ([]string, error) {
return modifiedUsernames, nil
}
func CountUsersByRoleAndEnabledExclude(roleID uint, excludeUserID uint) (int64, error) {
var count int64
jsonValue := fmt.Sprintf("[%d]", roleID)
err := db.Model(&model.User{}).
Where("disabled = ? AND id != ?", false, excludeUserID).
Where("JSON_CONTAINS(role, ?)", jsonValue).
Count(&count).Error
return count, err
}

View File

@ -97,8 +97,12 @@ func UpdateRole(r *model.Role) error {
if err != nil {
return err
}
if old.Name == "admin" || old.Name == "guest" {
switch old.Name {
case "admin":
return errs.ErrChangeDefaultRole
case "guest":
r.Name = "guest"
}
for i := range r.PermissionScopes {
r.PermissionScopes[i].Path = utils.FixAndCleanPath(r.PermissionScopes[i].Path)

View File

@ -165,3 +165,11 @@ func DelUserCache(username string) error {
userCache.Del(username)
return nil
}
func CountEnabledAdminsExcluding(userID uint) (int64, error) {
adminRole, err := GetRoleByName("admin")
if err != nil {
return 0, err
}
return db.CountUsersByRoleAndEnabledExclude(adminRole.ID, userID)
}

View File

@ -66,9 +66,13 @@ func UpdateRole(c *gin.Context) {
common.ErrorResp(c, err, 500, true)
return
}
if role.Name == "admin" || role.Name == "guest" {
switch role.Name {
case "admin":
common.ErrorResp(c, errs.ErrChangeDefaultRole, 403)
return
case "guest":
req.Name = "guest"
}
if err := op.UpdateRole(&req); err != nil {
common.ErrorResp(c, err, 500, true)

View File

@ -83,9 +83,16 @@ func UpdateUser(c *gin.Context) {
if req.OtpSecret == "" {
req.OtpSecret = user.OtpSecret
}
if req.Disabled && req.IsAdmin() {
common.ErrorStrResp(c, "admin user can not be disabled", 400)
return
if req.Disabled && user.IsAdmin() {
count, err := op.CountEnabledAdminsExcluding(user.ID)
if err != nil {
common.ErrorResp(c, err, 500)
return
}
if count == 0 {
common.ErrorStrResp(c, "at least one enabled admin must be kept", 400)
return
}
}
if err := op.UpdateUser(&req); err != nil {
common.ErrorResp(c, err, 500)