From 539c0375a1b43b10b873514b5f0a7733ca9cc010 Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Mon, 12 Jun 2017 17:49:18 +0800 Subject: [PATCH] support pagination --- docs/swagger.yaml | 17 ++++++++++ src/common/dao/dao_test.go | 6 ++-- src/common/dao/repository.go | 4 +++ src/common/dao/user.go | 42 ++++++++++++++++--------- src/common/models/user.go | 11 +++++-- src/ui/api/harborapi_test.go | 3 +- src/ui/api/user.go | 61 +++++++++++++++++++++++------------- src/ui/router.go | 3 +- 8 files changed, 104 insertions(+), 43 deletions(-) diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 421669902..26c4ba29f 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -491,6 +491,23 @@ paths: 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: diff --git a/src/common/dao/dao_test.go b/src/common/dao/dao_test.go index 7114f6a98..ff4ac2e63 100644 --- a/src/common/dao/dao_test.go +++ b/src/common/dao/dao_test.go @@ -407,14 +407,14 @@ func TestGetUser(t *testing.T) { } func TestListUsers(t *testing.T) { - users, err := ListUsers(models.User{}) + users, err := ListUsers(nil) if err != nil { t.Errorf("Error occurred in ListUsers: %v", err) } - if len(users) != 1 { + if len(users) != 2 { t.Errorf("Expect one user in list, but the acutal length is %d, the list: %+v", len(users), users) } - users2, err := ListUsers(models.User{Username: username}) + users2, err := ListUsers(&models.UserQuery{Username: username}) if len(users2) != 1 { t.Errorf("Expect one user in list, but the acutal length is %d, the list: %+v", len(users), users) } diff --git a/src/common/dao/repository.go b/src/common/dao/repository.go index 8e448edd8..d9f47ddd3 100644 --- a/src/common/dao/repository.go +++ b/src/common/dao/repository.go @@ -127,6 +127,10 @@ func GetTotalOfRepositories(name string) (int64, error) { // GetTotalOfRepositoriesByProject ... func GetTotalOfRepositoriesByProject(projectIDs []int64, name string) (int64, error) { + if len(projectIDs) == 0 { + return 0, nil + } + qs := GetOrmer().QueryTable(&models.RepoRecord{}). Filter("project_id__in", projectIDs) diff --git a/src/common/dao/user.go b/src/common/dao/user.go index 46f7fe29a..0a0a7fe81 100644 --- a/src/common/dao/user.go +++ b/src/common/dao/user.go @@ -19,6 +19,8 @@ import ( "errors" "fmt" + "github.com/astaxie/beego/orm" + "github.com/vmware/harbor/src/common/models" "github.com/vmware/harbor/src/common/utils" @@ -92,24 +94,36 @@ func LoginByDb(auth models.AuthModel) (*models.User, error) { return &user, nil } +// GetTotalOfUsers ... +func GetTotalOfUsers(query *models.UserQuery) (int64, error) { + return userQueryConditions(query).Count() +} + // ListUsers lists all users according to different conditions. -func ListUsers(query models.User) ([]models.User, error) { - o := GetOrmer() - u := []models.User{} - sql := `select user_id, username, email, realname, comment, reset_uuid, salt, - sysadmin_flag, creation_time, update_time - from user u - where u.deleted = 0 and u.user_id != 1 ` +func ListUsers(query *models.UserQuery) ([]models.User, error) { + users := []models.User{} + _, err := userQueryConditions(query). + OrderBy("username"). + All(&users) + return users, err +} - queryParam := make([]interface{}, 1) - if query.Username != "" { - sql += ` and username like ? ` - queryParam = append(queryParam, "%"+escape(query.Username)+"%") +func userQueryConditions(query *models.UserQuery) orm.QuerySeter { + qs := GetOrmer().QueryTable(&models.User{}).Filter("deleted", 0) + + if query == nil { + return qs } - sql += ` order by user_id desc ` - _, err := o.Raw(sql, queryParam).QueryRows(&u) - return u, err + if len(query.Username) > 0 { + qs = qs.Filter("username__contains", query.Username) + } + + if len(query.Email) > 0 { + qs = qs.Filter("email__contains", query.Email) + } + + return qs } // ToggleUserAdminRole gives a user admin role. diff --git a/src/common/models/user.go b/src/common/models/user.go index bdfcf5917..fff2725d5 100644 --- a/src/common/models/user.go +++ b/src/common/models/user.go @@ -27,10 +27,10 @@ type User struct { Realname string `orm:"column(realname)" json:"realname"` Comment string `orm:"column(comment)" json:"comment"` Deleted int `orm:"column(deleted)" json:"deleted"` - Rolename string `json:"role_name"` + Rolename string `orm:"-" json:"role_name"` //if this field is named as "RoleID", beego orm can not map role_id //to it. - Role int `json:"role_id"` + Role int `orm:"-" json:"role_id"` // RoleList []Role `json:"role_list"` HasAdminRole int `orm:"column(sysadmin_flag)" json:"has_admin_role"` ResetUUID string `orm:"column(reset_uuid)" json:"reset_uuid"` @@ -38,3 +38,10 @@ type User struct { CreationTime time.Time `orm:"creation_time" json:"creation_time"` UpdateTime time.Time `orm:"update_time" json:"update_time"` } + +// UserQuery ... +type UserQuery struct { + Username string + Email string + Pagination *Pagination +} diff --git a/src/ui/api/harborapi_test.go b/src/ui/api/harborapi_test.go index 7dd50f37c..29866c095 100644 --- a/src/ui/api/harborapi_test.go +++ b/src/ui/api/harborapi_test.go @@ -92,7 +92,8 @@ func init() { beego.Router("/api/search/", &SearchAPI{}) beego.Router("/api/projects/", &ProjectAPI{}, "get:List;post:Post;head:Head") beego.Router("/api/projects/:id", &ProjectAPI{}, "delete:Delete;get:Get") - beego.Router("/api/users/?:id", &UserAPI{}) + 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/:id([0-9]+)/password", &UserAPI{}, "put:ChangePassword") beego.Router("/api/users/:id/sysadmin", &UserAPI{}, "put:ToggleUserAdminRole") beego.Router("/api/projects/:id/publicity", &ProjectAPI{}, "put:ToggleProjectPublic") diff --git a/src/ui/api/user.go b/src/ui/api/user.go index 7ffc94f3a..11752cf53 100644 --- a/src/ui/api/user.go +++ b/src/ui/api/user.go @@ -106,26 +106,7 @@ func (ua *UserAPI) Prepare() { // Get ... func (ua *UserAPI) Get() { - if ua.userID == 0 { //list users - if !ua.IsAdmin { - log.Errorf("Current user, id: %d does not have admin role, can not list users", ua.currentUserID) - ua.RenderError(http.StatusForbidden, "User does not have admin role") - return - } - username := ua.GetString("username") - userQuery := models.User{} - if len(username) > 0 { - userQuery.Username = username - } - userList, err := dao.ListUsers(userQuery) - if err != nil { - log.Errorf("Failed to get data from database, error: %v", err) - ua.RenderError(http.StatusInternalServerError, "Failed to query from database") - return - } - ua.Data["json"] = userList - - } else if ua.userID == ua.currentUserID || ua.IsAdmin { + if ua.userID == ua.currentUserID || ua.IsAdmin { userQuery := models.User{UserID: ua.userID} u, err := dao.GetUser(userQuery) if err != nil { @@ -133,11 +114,47 @@ func (ua *UserAPI) Get() { ua.CustomAbort(http.StatusInternalServerError, "Internal error.") } ua.Data["json"] = u - } else { - log.Errorf("Current user, id: %d does not have admin role, can not view other user's detail", ua.currentUserID) + ua.ServeJSON() + return + } + + log.Errorf("Current user, id: %d does not have admin role, can not view other user's detail", ua.currentUserID) + ua.RenderError(http.StatusForbidden, "User does not have admin role") + return +} + +// List ... +func (ua *UserAPI) List() { + if !ua.IsAdmin { + log.Errorf("Current user, id: %d does not have admin role, can not list users", ua.currentUserID) ua.RenderError(http.StatusForbidden, "User does not have admin role") return } + + 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 + } + + ua.SetPaginationHeader(total, page, size) + ua.Data["json"] = users ua.ServeJSON() } diff --git a/src/ui/router.go b/src/ui/router.go index a2ae3b01e..4c3e98e53 100644 --- a/src/ui/router.go +++ b/src/ui/router.go @@ -68,7 +68,8 @@ func initRouters() { beego.Router("/api/projects/:id([0-9]+)/publicity", &api.ProjectAPI{}, "put:ToggleProjectPublic") beego.Router("/api/projects/:id([0-9]+)/logs", &api.ProjectAPI{}, "get:Logs") beego.Router("/api/statistics", &api.StatisticAPI{}) - beego.Router("/api/users/?:id", &api.UserAPI{}) + beego.Router("/api/users/:id", &api.UserAPI{}, "get:Get") + beego.Router("/api/users", &api.UserAPI{}, "get:List;post:Post;delete:Delete;put:Put") beego.Router("/api/users/:id([0-9]+)/password", &api.UserAPI{}, "put:ChangePassword") beego.Router("/api/internal/syncregistry", &api.InternalAPI{}, "post:SyncRegistry") beego.Router("/api/repositories", &api.RepositoryAPI{}, "get:Get")