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 {
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(ctx context.Context, query *q.Query, options ...models.Option) (commonmodels.Users, error)
// 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(ctx context.Context, user *commonmodels.User) (int, error)
// 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
}
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)
}
@ -206,11 +210,22 @@ func (m *manager) List(ctx context.Context, query *q.Query, options ...models.Op
}
opts := models.NewOptions(options...)
if !opts.IncludeDefaultAdmin {
query.Keywords["user_id__gt"] = 1
query = excludeDefaultAdmin(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) {
salt := utils.GenerateRandomString()
u.Password = utils.Encrypt(password, salt, utils.SHA256)

View File

@ -5,12 +5,13 @@ package user
import (
context "context"
models "github.com/goharbor/harbor/src/common/models"
commonmodels "github.com/goharbor/harbor/src/common/models"
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
@ -18,20 +19,27 @@ type Manager struct {
mock.Mock
}
// Count provides a mock function with given fields: ctx, query
func (_m *Manager) Count(ctx context.Context, query *q.Query) (int64, error) {
ret := _m.Called(ctx, query)
// Count provides a mock function with given fields: ctx, query, options
func (_m *Manager) Count(ctx context.Context, query *q.Query, options ...models.Option) (int64, error) {
_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
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok {
r0 = rf(ctx, query)
if rf, ok := ret.Get(0).(func(context.Context, *q.Query, ...models.Option) int64); ok {
r0 = rf(ctx, query, options...)
} else {
r0 = ret.Get(0).(int64)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
r1 = rf(ctx, query)
if rf, ok := ret.Get(1).(func(context.Context, *q.Query, ...models.Option) error); ok {
r1 = rf(ctx, query, options...)
} else {
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
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)
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)
} else {
r0 = ret.Get(0).(int)
}
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)
} else {
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
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)
var r0 *models.User
if rf, ok := ret.Get(0).(func(context.Context, int) *models.User); ok {
var r0 *commonmodels.User
if rf, ok := ret.Get(0).(func(context.Context, int) *commonmodels.User); ok {
r0 = rf(ctx, id)
} else {
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
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)
var r0 *models.User
if rf, ok := ret.Get(0).(func(context.Context, string) *models.User); ok {
var r0 *commonmodels.User
if rf, ok := ret.Get(0).(func(context.Context, string) *commonmodels.User); ok {
r0 = rf(ctx, username)
} else {
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
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))
for _i := range options {
_va[_i] = options[_i]
@ -145,17 +153,17 @@ func (_m *Manager) List(ctx context.Context, query *q.Query, options ...usermode
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
var r0 models.Users
if rf, ok := ret.Get(0).(func(context.Context, *q.Query, ...usermodels.Option) models.Users); ok {
var r0 commonmodels.Users
if rf, ok := ret.Get(0).(func(context.Context, *q.Query, ...models.Option) commonmodels.Users); ok {
r0 = rf(ctx, query, options...)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(models.Users)
r0 = ret.Get(0).(commonmodels.Users)
}
}
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...)
} else {
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
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)
var r0 *models.User
if rf, ok := ret.Get(0).(func(context.Context, string, string) *models.User); ok {
var r0 *commonmodels.User
if rf, ok := ret.Get(0).(func(context.Context, string, string) *commonmodels.User); ok {
r0 = rf(ctx, username, password)
} else {
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
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)
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)
} else {
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
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))
for _i := range col {
_va[_i] = col[_i]
@ -241,7 +249,7 @@ func (_m *Manager) UpdateProfile(ctx context.Context, _a1 *models.User, col ...s
ret := _m.Called(_ca...)
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...)
} else {
r0 = ret.Error(0)