From 20556aebd2e347ce85f71b6ddf9d9c4231f99297 Mon Sep 17 00:00:00 2001 From: He Weiwei Date: Thu, 7 Mar 2019 12:47:26 +0800 Subject: [PATCH] Add users search API Signed-off-by: He Weiwei --- docs/swagger.yaml | 48 ++++++++++++++++++++++++++++++++++ src/core/api/harborapi_test.go | 20 ++++++++++++++ src/core/api/user.go | 39 +++++++++++++++++++++++++++ src/core/api/user_test.go | 29 ++++++++++++++++++++ src/core/router.go | 1 + tests/apitests/apilib/user.go | 6 +++++ 6 files changed, 143 insertions(+) diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 247006946..c03540222 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -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: diff --git a/src/core/api/harborapi_test.go b/src/core/api/harborapi_test.go index 7fb2a33f9..f6a071102 100644 --- a/src/core/api/harborapi_test.go +++ b/src/core/api/harborapi_test.go @@ -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) diff --git a/src/core/api/user.go b/src/core/api/user.go index fb1cfebce..f797096dd 100644 --- a/src/core/api/user.go +++ b/src/core/api/user.go @@ -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() { diff --git a/src/core/api/user_test.go b/src/core/api/user_test.go index 00cdfa234..75d324322 100644 --- a/src/core/api/user_test.go +++ b/src/core/api/user_test.go @@ -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") diff --git a/src/core/router.go b/src/core/router.go index 06a986f2c..01a11d36d 100644 --- a/src/core/router.go +++ b/src/core/router.go @@ -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") diff --git a/tests/apitests/apilib/user.go b/tests/apitests/apilib/user.go index 8fc12ae69..62a93aae0 100644 --- a/tests/apitests/apilib/user.go +++ b/tests/apitests/apilib/user.go @@ -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"`