Add users search API

Signed-off-by: He Weiwei <hweiwei@vmware.com>
This commit is contained in:
He Weiwei 2019-03-07 12:47:26 +08:00
parent 62bb10d2e4
commit 20556aebd2
6 changed files with 143 additions and 0 deletions

View File

@ -748,6 +748,45 @@ paths:
description: User need to log in first.
'500':
description: Internal errors.
/users/search:
get:
summary: Search users by username, email
description: |
This endpoint is to search the users by username, email.
parameters:
- name: username
in: query
type: string
required: false
description: Username for filtering results.
- name: email
in: query
type: string
required: false
description: Email for filtering results.
- name: page
in: query
type: integer
format: int32
required: false
description: 'The page nubmer, default is 1.'
- name: page_size
in: query
type: integer
format: int32
required: false
description: The size of per page.
tags:
- Products
responses:
'200':
description: Search users by username, email successfully.
schema:
type: array
items:
$ref: '#/definitions/UserSearch'
'500':
description: Unexpected internal errors.
'/users/{user_id}':
get:
summary: Get a user's profile.
@ -3485,6 +3524,15 @@ definitions:
type: string
update_time:
type: string
UserSearch:
type: object
properties:
user_id:
type: integer
format: int
description: The ID of the user.
username:
type: string
Password:
type: object
properties:

View File

@ -102,6 +102,7 @@ func init() {
beego.Router("/api/projects/:id", &ProjectAPI{}, "delete:Delete;get:Get;put:Put")
beego.Router("/api/users/:id", &UserAPI{}, "get:Get")
beego.Router("/api/users", &UserAPI{}, "get:List;post:Post;delete:Delete;put:Put")
beego.Router("/api/users/search", &UserAPI{}, "get:Search")
beego.Router("/api/users/:id([0-9]+)/password", &UserAPI{}, "put:ChangePassword")
beego.Router("/api/users/:id/permissions", &UserAPI{}, "get:ListUserPermissions")
beego.Router("/api/users/:id/sysadmin", &UserAPI{}, "put:ToggleUserAdminRole")
@ -913,6 +914,25 @@ func (a testapi) UsersGet(userName string, authInfo usrInfo) (int, []apilib.User
return httpStatusCode, successPayLoad, err
}
// Search registered users of Harbor.
func (a testapi) UsersSearch(userName string, authInfo ...usrInfo) (int, []apilib.UserSearch, error) {
_sling := sling.New().Get(a.basePath)
// create path and map variables
path := "/api/users/search"
_sling = _sling.Path(path)
// body params
type QueryParams struct {
UserName string `url:"username, omitempty"`
}
_sling = _sling.QueryStruct(&QueryParams{UserName: userName})
httpStatusCode, body, err := request(_sling, jsonAcceptHeader, authInfo...)
var successPayLoad []apilib.UserSearch
if 200 == httpStatusCode && nil == err {
err = json.Unmarshal(body, &successPayLoad)
}
return httpStatusCode, successPayLoad, err
}
// Get registered users by userid.
func (a testapi) UsersGetByID(userName string, authInfo usrInfo, userID int) (int, apilib.User, error) {
_sling := sling.New().Get(a.basePath)

View File

@ -46,6 +46,11 @@ type passwordReq struct {
NewPassword string `json:"new_password"`
}
type userSearch struct {
UserID int `json:"user_id"`
Username string `json:"username"`
}
// Prepare validates the URL and parms
func (ua *UserAPI) Prepare() {
ua.BaseController.Prepare()
@ -166,6 +171,40 @@ func (ua *UserAPI) List() {
ua.ServeJSON()
}
// Search ...
func (ua *UserAPI) Search() {
page, size := ua.GetPaginationParams()
query := &models.UserQuery{
Username: ua.GetString("username"),
Email: ua.GetString("email"),
Pagination: &models.Pagination{
Page: page,
Size: size,
},
}
total, err := dao.GetTotalOfUsers(query)
if err != nil {
ua.HandleInternalServerError(fmt.Sprintf("failed to get total of users: %v", err))
return
}
users, err := dao.ListUsers(query)
if err != nil {
ua.HandleInternalServerError(fmt.Sprintf("failed to get users: %v", err))
return
}
var userSearches []userSearch
for _, user := range users {
userSearches = append(userSearches, userSearch{UserID: user.UserID, Username: user.Username})
}
ua.SetPaginationHeader(total, page, size)
ua.Data["json"] = userSearches
ua.ServeJSON()
}
// Put ...
func (ua *UserAPI) Put() {
if !ua.modifiable() {

View File

@ -208,6 +208,35 @@ func TestUsersGet(t *testing.T) {
}
}
func TestUsersSearch(t *testing.T) {
fmt.Println("Testing User Search")
assert := assert.New(t)
apiTest := newHarborAPI()
testUser0002.Username = "testUser0002"
// case 1: Search user2 without auth, expect 401
testUser0002Auth = &usrInfo{"testUser0002", "testUser0002"}
code, users, err := apiTest.UsersSearch(testUser0002.Username)
if err != nil {
t.Error("Error occurred while search users", err.Error())
t.Log(err)
} else {
assert.Equal(401, code, "Search users status should be 401")
}
// case 2: Search user2 with with common auth, expect 200
code, users, err = apiTest.UsersSearch(testUser0002.Username, *testUser0002Auth)
if err != nil {
t.Error("Error occurred while search users", err.Error())
t.Log(err)
} else {
assert.Equal(200, code, "Search users status should be 200")
assert.Equal(1, len(users), "Search users record should be 1 ")
testUser0002ID = users[0].UserID
}
}
func TestUsersGetByID(t *testing.T) {
fmt.Println("Testing User GetByID")

View File

@ -45,6 +45,7 @@ func initRouters() {
beego.Router("/api/users/:id", &api.UserAPI{}, "get:Get;delete:Delete;put:Put")
beego.Router("/api/users", &api.UserAPI{}, "get:List;post:Post")
beego.Router("/api/users/search", &api.UserAPI{}, "get:Search")
beego.Router("/api/users/:id([0-9]+)/password", &api.UserAPI{}, "put:ChangePassword")
beego.Router("/api/users/:id/permissions", &api.UserAPI{}, "get:ListUserPermissions")
beego.Router("/api/users/:id/sysadmin", &api.UserAPI{}, "put:ToggleUserAdminRole")

View File

@ -54,6 +54,12 @@ type User struct {
UpdateTime string `json:"update_time,omitempty"`
}
// UserSearch the user search type
type UserSearch struct {
UserID int `json:"user_id,omitempty"`
Username string `json:"username,omitempty"`
}
// Permission the permission type
type Permission struct {
Resource string `json:"resource,omitempty"`