Add options to the user.Count method (#16285)

Fixes #16269, exclude the admin account by default
  Add excludeDefaultAdmin method -- exclude default admin by option
  Update authModeCanBeModified method -- the user count should be 0 without admin

Signed-off-by: stonezdj <stonezdj@gmail.com>
This commit is contained in:
stonezdj(Daojun Zhang) 2022-07-06 13:57:31 +08:00 committed by GitHub
parent 6917021b41
commit dcccb44db8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 38 deletions

View File

@ -227,5 +227,5 @@ func (c *controller) authModeCanBeModified(ctx context.Context) (bool, error) {
if err != nil { if err != nil {
return false, err return false, err
} }
return cnt == 1, nil // admin user only return cnt == 0, nil
} }

View File

@ -42,7 +42,7 @@ type Manager interface {
// List users according to the query // List users according to the query
List(ctx context.Context, query *q.Query, options ...models.Option) (commonmodels.Users, error) List(ctx context.Context, query *q.Query, options ...models.Option) (commonmodels.Users, error)
// Count counts the number of users according to the query // Count counts the number of users according to the query
Count(ctx context.Context, query *q.Query) (int64, error) Count(ctx context.Context, query *q.Query, options ...models.Option) (int64, error)
// Create creates the user, the password of input should be plaintext // Create creates the user, the password of input should be plaintext
Create(ctx context.Context, user *commonmodels.User) (int, error) Create(ctx context.Context, user *commonmodels.User) (int, error)
// Delete deletes the user by updating user's delete flag and update the name and Email // Delete deletes the user by updating user's delete flag and update the name and Email
@ -131,7 +131,11 @@ func (m *manager) MatchLocalPassword(ctx context.Context, usernameOrEmail, passw
return nil, nil return nil, nil
} }
func (m *manager) Count(ctx context.Context, query *q.Query) (int64, error) { func (m *manager) Count(ctx context.Context, query *q.Query, options ...models.Option) (int64, error) {
opts := models.NewOptions(options...)
if !opts.IncludeDefaultAdmin {
query = excludeDefaultAdmin(query)
}
return m.dao.Count(ctx, query) return m.dao.Count(ctx, query)
} }
@ -206,11 +210,22 @@ func (m *manager) List(ctx context.Context, query *q.Query, options ...models.Op
} }
opts := models.NewOptions(options...) opts := models.NewOptions(options...)
if !opts.IncludeDefaultAdmin { if !opts.IncludeDefaultAdmin {
query.Keywords["user_id__gt"] = 1 query = excludeDefaultAdmin(query)
} }
return m.dao.List(ctx, query) return m.dao.List(ctx, query)
} }
func excludeDefaultAdmin(query *q.Query) (qu *q.Query) {
if query == nil {
query = q.New(q.KeyWords{})
}
if query.Keywords == nil {
query.Keywords = q.KeyWords{}
}
query.Keywords["user_id__gt"] = 1
return query
}
func injectPasswd(u *commonmodels.User, password string) { func injectPasswd(u *commonmodels.User, password string) {
salt := utils.GenerateRandomString() salt := utils.GenerateRandomString()
u.Password = utils.Encrypt(password, salt, utils.SHA256) u.Password = utils.Encrypt(password, salt, utils.SHA256)

View File

@ -5,12 +5,13 @@ package user
import ( import (
context "context" context "context"
models "github.com/goharbor/harbor/src/common/models" commonmodels "github.com/goharbor/harbor/src/common/models"
mock "github.com/stretchr/testify/mock" mock "github.com/stretchr/testify/mock"
q "github.com/goharbor/harbor/src/lib/q" models "github.com/goharbor/harbor/src/pkg/user/models"
usermodels "github.com/goharbor/harbor/src/pkg/user/models" q "github.com/goharbor/harbor/src/lib/q"
) )
// Manager is an autogenerated mock type for the Manager type // Manager is an autogenerated mock type for the Manager type
@ -18,20 +19,27 @@ type Manager struct {
mock.Mock mock.Mock
} }
// Count provides a mock function with given fields: ctx, query // Count provides a mock function with given fields: ctx, query, options
func (_m *Manager) Count(ctx context.Context, query *q.Query) (int64, error) { func (_m *Manager) Count(ctx context.Context, query *q.Query, options ...models.Option) (int64, error) {
ret := _m.Called(ctx, query) _va := make([]interface{}, len(options))
for _i := range options {
_va[_i] = options[_i]
}
var _ca []interface{}
_ca = append(_ca, ctx, query)
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 int64 var r0 int64
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok { if rf, ok := ret.Get(0).(func(context.Context, *q.Query, ...models.Option) int64); ok {
r0 = rf(ctx, query) r0 = rf(ctx, query, options...)
} else { } else {
r0 = ret.Get(0).(int64) r0 = ret.Get(0).(int64)
} }
var r1 error var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok { if rf, ok := ret.Get(1).(func(context.Context, *q.Query, ...models.Option) error); ok {
r1 = rf(ctx, query) r1 = rf(ctx, query, options...)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
} }
@ -40,18 +48,18 @@ func (_m *Manager) Count(ctx context.Context, query *q.Query) (int64, error) {
} }
// Create provides a mock function with given fields: ctx, _a1 // Create provides a mock function with given fields: ctx, _a1
func (_m *Manager) Create(ctx context.Context, _a1 *models.User) (int, error) { func (_m *Manager) Create(ctx context.Context, _a1 *commonmodels.User) (int, error) {
ret := _m.Called(ctx, _a1) ret := _m.Called(ctx, _a1)
var r0 int var r0 int
if rf, ok := ret.Get(0).(func(context.Context, *models.User) int); ok { if rf, ok := ret.Get(0).(func(context.Context, *commonmodels.User) int); ok {
r0 = rf(ctx, _a1) r0 = rf(ctx, _a1)
} else { } else {
r0 = ret.Get(0).(int) r0 = ret.Get(0).(int)
} }
var r1 error var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *models.User) error); ok { if rf, ok := ret.Get(1).(func(context.Context, *commonmodels.User) error); ok {
r1 = rf(ctx, _a1) r1 = rf(ctx, _a1)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
@ -89,15 +97,15 @@ func (_m *Manager) DeleteGDPR(ctx context.Context, id int) error {
} }
// Get provides a mock function with given fields: ctx, id // Get provides a mock function with given fields: ctx, id
func (_m *Manager) Get(ctx context.Context, id int) (*models.User, error) { func (_m *Manager) Get(ctx context.Context, id int) (*commonmodels.User, error) {
ret := _m.Called(ctx, id) ret := _m.Called(ctx, id)
var r0 *models.User var r0 *commonmodels.User
if rf, ok := ret.Get(0).(func(context.Context, int) *models.User); ok { if rf, ok := ret.Get(0).(func(context.Context, int) *commonmodels.User); ok {
r0 = rf(ctx, id) r0 = rf(ctx, id)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.User) r0 = ret.Get(0).(*commonmodels.User)
} }
} }
@ -112,15 +120,15 @@ func (_m *Manager) Get(ctx context.Context, id int) (*models.User, error) {
} }
// GetByName provides a mock function with given fields: ctx, username // GetByName provides a mock function with given fields: ctx, username
func (_m *Manager) GetByName(ctx context.Context, username string) (*models.User, error) { func (_m *Manager) GetByName(ctx context.Context, username string) (*commonmodels.User, error) {
ret := _m.Called(ctx, username) ret := _m.Called(ctx, username)
var r0 *models.User var r0 *commonmodels.User
if rf, ok := ret.Get(0).(func(context.Context, string) *models.User); ok { if rf, ok := ret.Get(0).(func(context.Context, string) *commonmodels.User); ok {
r0 = rf(ctx, username) r0 = rf(ctx, username)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.User) r0 = ret.Get(0).(*commonmodels.User)
} }
} }
@ -135,7 +143,7 @@ func (_m *Manager) GetByName(ctx context.Context, username string) (*models.User
} }
// List provides a mock function with given fields: ctx, query, options // List provides a mock function with given fields: ctx, query, options
func (_m *Manager) List(ctx context.Context, query *q.Query, options ...usermodels.Option) (models.Users, error) { func (_m *Manager) List(ctx context.Context, query *q.Query, options ...models.Option) (commonmodels.Users, error) {
_va := make([]interface{}, len(options)) _va := make([]interface{}, len(options))
for _i := range options { for _i := range options {
_va[_i] = options[_i] _va[_i] = options[_i]
@ -145,17 +153,17 @@ func (_m *Manager) List(ctx context.Context, query *q.Query, options ...usermode
_ca = append(_ca, _va...) _ca = append(_ca, _va...)
ret := _m.Called(_ca...) ret := _m.Called(_ca...)
var r0 models.Users var r0 commonmodels.Users
if rf, ok := ret.Get(0).(func(context.Context, *q.Query, ...usermodels.Option) models.Users); ok { if rf, ok := ret.Get(0).(func(context.Context, *q.Query, ...models.Option) commonmodels.Users); ok {
r0 = rf(ctx, query, options...) r0 = rf(ctx, query, options...)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(models.Users) r0 = ret.Get(0).(commonmodels.Users)
} }
} }
var r1 error var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *q.Query, ...usermodels.Option) error); ok { if rf, ok := ret.Get(1).(func(context.Context, *q.Query, ...models.Option) error); ok {
r1 = rf(ctx, query, options...) r1 = rf(ctx, query, options...)
} else { } else {
r1 = ret.Error(1) r1 = ret.Error(1)
@ -165,15 +173,15 @@ func (_m *Manager) List(ctx context.Context, query *q.Query, options ...usermode
} }
// MatchLocalPassword provides a mock function with given fields: ctx, username, password // MatchLocalPassword provides a mock function with given fields: ctx, username, password
func (_m *Manager) MatchLocalPassword(ctx context.Context, username string, password string) (*models.User, error) { func (_m *Manager) MatchLocalPassword(ctx context.Context, username string, password string) (*commonmodels.User, error) {
ret := _m.Called(ctx, username, password) ret := _m.Called(ctx, username, password)
var r0 *models.User var r0 *commonmodels.User
if rf, ok := ret.Get(0).(func(context.Context, string, string) *models.User); ok { if rf, ok := ret.Get(0).(func(context.Context, string, string) *commonmodels.User); ok {
r0 = rf(ctx, username, password) r0 = rf(ctx, username, password)
} else { } else {
if ret.Get(0) != nil { if ret.Get(0) != nil {
r0 = ret.Get(0).(*models.User) r0 = ret.Get(0).(*commonmodels.User)
} }
} }
@ -188,11 +196,11 @@ func (_m *Manager) MatchLocalPassword(ctx context.Context, username string, pass
} }
// Onboard provides a mock function with given fields: ctx, _a1 // Onboard provides a mock function with given fields: ctx, _a1
func (_m *Manager) Onboard(ctx context.Context, _a1 *models.User) error { func (_m *Manager) Onboard(ctx context.Context, _a1 *commonmodels.User) error {
ret := _m.Called(ctx, _a1) ret := _m.Called(ctx, _a1)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *models.User) error); ok { if rf, ok := ret.Get(0).(func(context.Context, *commonmodels.User) error); ok {
r0 = rf(ctx, _a1) r0 = rf(ctx, _a1)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
@ -230,7 +238,7 @@ func (_m *Manager) UpdatePassword(ctx context.Context, id int, newPassword strin
} }
// UpdateProfile provides a mock function with given fields: ctx, _a1, col // UpdateProfile provides a mock function with given fields: ctx, _a1, col
func (_m *Manager) UpdateProfile(ctx context.Context, _a1 *models.User, col ...string) error { func (_m *Manager) UpdateProfile(ctx context.Context, _a1 *commonmodels.User, col ...string) error {
_va := make([]interface{}, len(col)) _va := make([]interface{}, len(col))
for _i := range col { for _i := range col {
_va[_i] = col[_i] _va[_i] = col[_i]
@ -241,7 +249,7 @@ func (_m *Manager) UpdateProfile(ctx context.Context, _a1 *models.User, col ...s
ret := _m.Called(_ca...) ret := _m.Called(_ca...)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *models.User, ...string) error); ok { if rf, ok := ret.Get(0).(func(context.Context, *commonmodels.User, ...string) error); ok {
r0 = rf(ctx, _a1, col...) r0 = rf(ctx, _a1, col...)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)