mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-31 18:45:03 +00:00
fix: list bot users in gitea admin user list and admin users API (#40060)
Fixes https://github.com/go-gitea/gitea/issues/40056 Signed-off-by: Soujas K <kudchadkarsoujas@gmail.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
5 files changed
+28
-19
No files matched your search
@@ -33,7 +33,7 @@ func runListUsers(ctx context.Context, c *cli.Command) error {
|
||||
return err
|
||||
}
|
||||
|
||||
users, err := user_model.GetAllUsers(ctx)
|
||||
users, err := user_model.GetAllUsersForAdminListing(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -41,17 +41,17 @@ func runListUsers(ctx context.Context, c *cli.Command) error {
|
||||
w := tabwriter.NewWriter(os.Stdout, 5, 0, 1, ' ', 0)
|
||||
|
||||
if c.IsSet("admin") {
|
||||
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\n")
|
||||
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tType\n")
|
||||
for _, u := range users {
|
||||
if u.IsAdmin {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", u.ID, u.Name, u.Email, u.IsActive)
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%s\n", u.ID, u.Name, u.Email, u.IsActive, u.Type.DisplayName())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
twofa := user_model.UserList(users).GetTwoFaStatus(ctx)
|
||||
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n")
|
||||
fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\tType\n")
|
||||
for _, u := range users {
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\t%t\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin, twofa[u.ID])
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\t%t\t%s\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin, twofa[u.ID], u.Type.DisplayName())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-4
@@ -68,13 +68,20 @@ const (
|
||||
UserTypeRemoteUser // 5
|
||||
)
|
||||
|
||||
// AdminListedUserTypes HINT: USER-TYPE-GLOSSARY: administrators list every user type except organizations
|
||||
var AdminListedUserTypes = []UserType{UserTypeIndividual, UserTypeUserReserved, UserTypeBot, UserTypeRemoteUser}
|
||||
|
||||
// DisplayName returns the English name of the user type for logs and the CLI, the UI translates "concept_user_*" instead
|
||||
func (t UserType) DisplayName() string {
|
||||
switch t {
|
||||
case UserTypeOrganization, UserTypeOrganizationReserved:
|
||||
return "Organization"
|
||||
case UserTypeUserReserved:
|
||||
return "Reserved"
|
||||
case UserTypeBot:
|
||||
return "Bot"
|
||||
case UserTypeRemoteUser:
|
||||
return "Remote"
|
||||
default:
|
||||
return "User"
|
||||
}
|
||||
@@ -251,10 +258,10 @@ func (u *User) GetEmail() string {
|
||||
return u.Email
|
||||
}
|
||||
|
||||
// GetAllUsers returns a slice of all individual users found in DB.
|
||||
func GetAllUsers(ctx context.Context) ([]*User, error) {
|
||||
users := make([]*User, 0)
|
||||
return users, db.GetEngine(ctx).OrderBy("id").Where("type = ?", UserTypeIndividual).Find(&users)
|
||||
// GetAllUsersForAdminListing returns a slice of all users of AdminListedUserTypes found in DB.
|
||||
func GetAllUsersForAdminListing(ctx context.Context) (users []*User, err error) {
|
||||
err = db.GetEngine(ctx).OrderBy("id").In("type", AdminListedUserTypes).Find(&users)
|
||||
return users, err
|
||||
}
|
||||
|
||||
// IsLocal returns true if user login type is LoginPlain.
|
||||
|
||||
@@ -459,7 +459,7 @@ func SearchUsers(ctx *context.APIContext) {
|
||||
|
||||
searchOpts := user_model.SearchUserOptions{
|
||||
Actor: ctx.Doer,
|
||||
Types: []user_model.UserType{user_model.UserTypeIndividual},
|
||||
Types: user_model.AdminListedUserTypes,
|
||||
LoginName: ctx.FormTrim("login_name"),
|
||||
SourceID: ctx.FormOptionalInt64("source_id"),
|
||||
Keyword: ctx.FormTrim("q"),
|
||||
|
||||
@@ -70,8 +70,7 @@ func Users(ctx *context.Context) {
|
||||
|
||||
sortType := ctx.FormString("sort", UserSearchDefaultAdminSort)
|
||||
|
||||
// unfiltered, an administrator needs to list every account kind
|
||||
types := []user_model.UserType{user_model.UserTypeIndividual, user_model.UserTypeUserReserved, user_model.UserTypeBot, user_model.UserTypeRemoteUser}
|
||||
types := user_model.AdminListedUserTypes
|
||||
userTypeFilter := api.UserTypeString(ctx.FormString("user_type"))
|
||||
ctx.Data["UserTypeFilter"] = ""
|
||||
if t, err := convert.UserTypeFromString(userTypeFilter); err == nil {
|
||||
|
||||
@@ -22,6 +22,8 @@ import (
|
||||
"gitea.dev/tests"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
func TestAPIAdminListPackages(t *testing.T) {
|
||||
@@ -55,20 +57,21 @@ func TestAPIAdminAccessAndSSHKeys(t *testing.T) {
|
||||
t.Run("ListUsers", func(t *testing.T) {
|
||||
adminUsername := "user1"
|
||||
token := getUserToken(t, adminUsername, auth_model.AccessTokenScopeReadAdmin)
|
||||
bot := &user_model.User{Name: "list-bot", Email: "list-bot@example.com", Type: user_model.UserTypeBot}
|
||||
require.NoError(t, user_model.CreateUser(t.Context(), bot, &user_model.Meta{}))
|
||||
|
||||
req := NewRequest(t, "GET", "/api/v1/admin/users").
|
||||
req := NewRequest(t, "GET", "/api/v1/admin/users?limit=50").
|
||||
AddTokenAuth(token)
|
||||
resp := MakeRequest(t, req, http.StatusOK)
|
||||
users := DecodeJSON(t, resp, []api.User{})
|
||||
|
||||
found := false
|
||||
userTypes := map[string]api.UserTypeString{}
|
||||
for _, user := range users {
|
||||
if user.UserName == adminUsername {
|
||||
found = true
|
||||
}
|
||||
userTypes[user.UserName] = user.Type
|
||||
}
|
||||
assert.True(t, found)
|
||||
numberOfUsers := unittest.GetCount(t, &user_model.User{}, "type = 0")
|
||||
assert.Equal(t, api.UserTypeStringUser, userTypes[adminUsername])
|
||||
assert.Equal(t, api.UserTypeStringBot, userTypes[bot.Name])
|
||||
numberOfUsers := unittest.GetCount(t, &user_model.User{}, builder.In("type", user_model.AdminListedUserTypes))
|
||||
assert.Len(t, users, numberOfUsers)
|
||||
})
|
||||
|
||||
|
||||
Reference in new issue
Block a user