From f138067242f11cd7208b7d9ba43f711783e32d36 Mon Sep 17 00:00:00 2001 From: stonezdj Date: Tue, 6 Feb 2018 10:59:49 +0800 Subject: [PATCH] Refactor project member --- make/photon/db/registry.sql | 31 ++++++++---- make/photon/db/registry_sqlite.sql | 31 ++++++++---- src/common/const.go | 2 + src/common/dao/base.go | 3 +- src/common/dao/dao_test.go | 23 ++++++--- src/common/dao/project.go | 10 ++-- src/common/dao/projectmember.go | 62 ++++++++++++++--------- src/common/dao/replication_job.go | 6 +-- src/common/dao/role.go | 4 +- src/common/models/member.go | 11 ++++ src/common/security/local/context.go | 4 +- src/common/security/local/context_test.go | 12 ++--- src/ui/api/api_test.go | 11 ++-- src/ui/api/harborapi_test.go | 2 +- src/ui/api/member.go | 30 ++++++----- src/ui/api/replication_policy_test.go | 9 ++-- src/ui/api/utils.go | 4 +- src/ui/router.go | 2 +- 18 files changed, 163 insertions(+), 94 deletions(-) diff --git a/make/photon/db/registry.sql b/make/photon/db/registry.sql index bf07a6a21..0ddc0087d 100644 --- a/make/photon/db/registry.sql +++ b/make/photon/db/registry.sql @@ -82,19 +82,19 @@ insert into project (owner_id, name, creation_time, update_time) values (1, 'library', NOW(), NOW()); create table project_member ( + id int not null AUTO_INCREMENT, project_id int NOT NULL, - user_id int NOT NULL, + entity_id int NOT NULL, + entity_type char NOT NULL, ## u for user, g for user group role int NOT NULL, - creation_time timestamp, - update_time timestamp, - PRIMARY KEY (project_id, user_id), - FOREIGN KEY (role) REFERENCES role(role_id), - FOREIGN KEY (project_id) REFERENCES project(project_id), - FOREIGN KEY (user_id) REFERENCES user(user_id) + creation_time timestamp default CURRENT_TIMESTAMP, + update_time timestamp default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, + PRIMARY KEY (id), + CONSTRAINT unique_project_entity_type UNIQUE (project_id, entity_id, entity_type) ); -insert into project_member (project_id, user_id, role, creation_time, update_time) values -(1, 1, 1, NOW(), NOW()); +insert into project_member (project_id, entity_id, role, entity_type) values +(1, 1, 1, 'u'); create table project_metadata ( id int NOT NULL AUTO_INCREMENT, @@ -112,6 +112,19 @@ create table project_metadata ( insert into project_metadata (id, project_id, name, value, creation_time, update_time, deleted) values (1, 1, 'public', 'true', NOW(), NOW(), 0); + + +create table user_group +( +id int NOT NULL AUTO_INCREMENT, +group_name varchar(255) NOT NULL, +group_type int default 0, +group_property varchar(512) NOT NULL, +creation_time timestamp default CURRENT_TIMESTAMP, +update_time timestamp default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, +PRIMARY KEY (id) +); + create table access_log ( log_id int NOT NULL AUTO_INCREMENT, username varchar (255) NOT NULL, diff --git a/make/photon/db/registry_sqlite.sql b/make/photon/db/registry_sqlite.sql index 58dde0ab2..fdf6d9e9a 100644 --- a/make/photon/db/registry_sqlite.sql +++ b/make/photon/db/registry_sqlite.sql @@ -59,7 +59,16 @@ create table user ( insert into user (username, email, password, realname, comment, deleted, sysadmin_flag, creation_time, update_time) values ('admin', 'admin@example.com', '', 'system admin', 'admin user',0, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), ('anonymous', 'anonymous@example.com', '', 'anonymous user', 'anonymous user', 1, 0, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); - + +create table user_group ( +id INTEGER PRIMARY KEY, +group_name varchar(255) NOT NULL, +group_type int default 0, +group_property varchar(512) NOT NULL, +creation_time timestamp default CURRENT_TIMESTAMP, +update_time timestamp default CURRENT_TIMESTAMP +); + create table project ( project_id INTEGER PRIMARY KEY, owner_id int NOT NULL, @@ -78,20 +87,21 @@ create table project ( insert into project (owner_id, name, creation_time, update_time) values (1, 'library', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); + + create table project_member ( + id INTEGER PRIMARY KEY, project_id int NOT NULL, - user_id int NOT NULL, + entity_id int NOT NULL, + entity_type char NOT NULL, role int NOT NULL, - creation_time timestamp, - update_time timestamp, - PRIMARY KEY (project_id, user_id), - FOREIGN KEY (role) REFERENCES role(role_id), - FOREIGN KEY (project_id) REFERENCES project(project_id), - FOREIGN KEY (user_id) REFERENCES user(user_id) + creation_time timestamp default CURRENT_TIMESTAMP, + update_time timestamp default CURRENT_TIMESTAMP, + UNIQUE (project_id, entity_id, entity_type) ); -insert into project_member (project_id, user_id, role, creation_time, update_time) values -(1, 1, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +insert into project_member (project_id, entity_id, role, entity_type) values +(1, 1, 1, 'u'); create table project_metadata ( id INTEGER PRIMARY KEY, @@ -235,3 +245,4 @@ create table alembic_version ( ); insert into alembic_version values ('1.4.0'); + diff --git a/src/common/const.go b/src/common/const.go index e629b5e71..a3c164307 100644 --- a/src/common/const.go +++ b/src/common/const.go @@ -84,4 +84,6 @@ const ( CfgDriverJSON = "json" NewHarborAdminName = "admin@harbor.local" RegistryStorageProviderName = "registry_storage_provider_name" + UserMember = "u" + GroupMember = "g" ) diff --git a/src/common/dao/base.go b/src/common/dao/base.go index 177336925..a22a338e5 100644 --- a/src/common/dao/base.go +++ b/src/common/dao/base.go @@ -133,7 +133,8 @@ func paginateForRawSQL(sql string, limit, offset int64) string { return fmt.Sprintf("%s limit %d offset %d", sql, limit, offset) } -func escape(str string) string { +//Escape .. +func Escape(str string) string { str = strings.Replace(str, `%`, `\%`, -1) str = strings.Replace(str, `_`, `\_`, -1) return str diff --git a/src/common/dao/dao_test.go b/src/common/dao/dao_test.go index 2ccb8739a..d83471608 100644 --- a/src/common/dao/dao_test.go +++ b/src/common/dao/dao_test.go @@ -49,7 +49,7 @@ func cleanByUser(username string) { err = execUpdate(o, `delete from project_member - where user_id = ( + where entity_id = ( select user_id from user where username = ? @@ -661,7 +661,7 @@ func TestGetUserByProject(t *testing.T) { } func TestGetUserProjectRoles(t *testing.T) { - r, err := GetUserProjectRoles(currentUser.UserID, currentProject.ProjectID) + r, err := GetUserProjectRoles(currentUser.UserID, currentProject.ProjectID, common.UserMember) if err != nil { t.Errorf("Error happened in GetUserProjectRole: %v, userID: %+v, project Id: %d", err, currentUser.UserID, currentProject.ProjectID) } @@ -701,12 +701,19 @@ func TestGetProjects(t *testing.T) { } func TestAddProjectMember(t *testing.T) { - err := AddProjectMember(currentProject.ProjectID, 1, models.DEVELOPER) + pmid, err := AddProjectMember(currentProject.ProjectID, 1, models.DEVELOPER, common.UserMember) if err != nil { t.Errorf("Error occurred in AddProjectMember: %v", err) } + if pmid == 0 { + t.Errorf("Error add project member, pmid=0") + } + pmid, err = AddProjectMember(currentProject.ProjectID, 1, models.DEVELOPER, "randomstring") + if err == nil { + t.Errorf("Should failed on adding project member when adding duplicated items") + } - roles, err := GetUserProjectRoles(1, currentProject.ProjectID) + roles, err := GetUserProjectRoles(1, currentProject.ProjectID, common.UserMember) if err != nil { t.Errorf("Error occurred in GetUserProjectRoles: %v", err) } @@ -725,11 +732,11 @@ func TestAddProjectMember(t *testing.T) { } func TestUpdateProjectMember(t *testing.T) { - err := UpdateProjectMember(currentProject.ProjectID, 1, models.GUEST) + err := UpdateProjectMember(currentProject.ProjectID, 1, models.GUEST, "randomstring") if err != nil { t.Errorf("Error occurred in UpdateProjectMember: %v", err) } - roles, err := GetUserProjectRoles(1, currentProject.ProjectID) + roles, err := GetUserProjectRoles(1, currentProject.ProjectID, common.UserMember) if err != nil { t.Errorf("Error occurred in GetUserProjectRoles: %v", err) } @@ -740,12 +747,12 @@ func TestUpdateProjectMember(t *testing.T) { } func TestDeleteProjectMember(t *testing.T) { - err := DeleteProjectMember(currentProject.ProjectID, 1) + err := DeleteProjectMember(currentProject.ProjectID, 1, "randomstring") if err != nil { t.Errorf("Error occurred in DeleteProjectMember: %v", err) } - roles, err := GetUserProjectRoles(1, currentProject.ProjectID) + roles, err := GetUserProjectRoles(1, currentProject.ProjectID, common.UserMember) if err != nil { t.Errorf("Error occurred in GetUserProjectRoles: %v", err) } diff --git a/src/common/dao/project.go b/src/common/dao/project.go index 7f1f139e0..9ec0b0361 100644 --- a/src/common/dao/project.go +++ b/src/common/dao/project.go @@ -20,7 +20,6 @@ import ( "fmt" "time" - //"github.com/vmware/harbor/src/common/utils/log" ) @@ -46,7 +45,10 @@ func AddProject(project models.Project) (int64, error) { return 0, err } - err = AddProjectMember(projectID, project.OwnerID, models.PROJECTADMIN) + pmID, err := AddProjectMember(projectID, project.OwnerID, models.PROJECTADMIN, common.UserMember) + if pmID == 0 { + return projectID, fmt.Errorf("Failed to add project member, pmid=0") + } return projectID, err } @@ -146,7 +148,7 @@ func projectQueryConditions(query *models.ProjectQueryParam) (string, []interfac sql += ` join project_member pm on p.project_id = pm.project_id join user u2 - on pm.user_id=u2.user_id` + on pm.entity_id=u2.user_id` } sql += ` where p.deleted=0` @@ -157,7 +159,7 @@ func projectQueryConditions(query *models.ProjectQueryParam) (string, []interfac if len(query.Name) != 0 { sql += ` and p.name like ?` - params = append(params, "%"+escape(query.Name)+"%") + params = append(params, "%"+Escape(query.Name)+"%") } if query.Member != nil && len(query.Member.Name) != 0 { diff --git a/src/common/dao/projectmember.go b/src/common/dao/projectmember.go index 4e8678493..1a8397156 100644 --- a/src/common/dao/projectmember.go +++ b/src/common/dao/projectmember.go @@ -15,25 +15,39 @@ package dao import ( + "github.com/vmware/harbor/src/common" "github.com/vmware/harbor/src/common/models" ) // AddProjectMember inserts a record to table project_member -func AddProjectMember(projectID int64, userID int, role int) error { +func AddProjectMember(projectID int64, userID int, role int, entityType string) (int, error) { o := GetOrmer() + if !(entityType == common.UserMember || entityType == common.GroupMember) { + entityType = common.UserMember + } + sql := `insert into project_member (project_id, entity_id , role, entity_type) values (?, ?, ?, ?)` + _, err := o.Raw(sql, projectID, userID, role, entityType).Exec() + if err != nil { + return 0, err + } + var pmid int + querySQL := `select id from project_member where project_id = ? and entity_id = ? and entity_type = ? limit 1` - sql := "insert into project_member (project_id, user_id , role) values (?, ?, ?)" - - _, err := o.Raw(sql, projectID, userID, role).Exec() - - return err + err = o.Raw(querySQL, projectID, userID, entityType).QueryRow(&pmid) + if err != nil { + return 0, err + } + return pmid, err } // UpdateProjectMember updates the record in table project_member -func UpdateProjectMember(projectID int64, userID int, role int) error { +func UpdateProjectMember(projectID int64, userID int, role int, entityType string) error { o := GetOrmer() + if !(entityType == common.UserMember || entityType == common.GroupMember) { + entityType = common.UserMember + } - sql := "update project_member set role = ? where project_id = ? and user_id = ?" + sql := `update project_member set role = ? where project_id = ? and entity_id = ?` _, err := o.Raw(sql, role, projectID, userID).Exec() @@ -41,12 +55,16 @@ func UpdateProjectMember(projectID int64, userID int, role int) error { } // DeleteProjectMember delete the record from table project_member -func DeleteProjectMember(projectID int64, userID int) error { +func DeleteProjectMember(projectID int64, userID int, entityType string) error { o := GetOrmer() - sql := "delete from project_member where project_id = ? and user_id = ?" + if !(entityType == common.UserMember || entityType == common.GroupMember) { + entityType = common.UserMember + } - if _, err := o.Raw(sql, projectID, userID).Exec(); err != nil { + sql := `delete from project_member where project_id = ? and entity_id = ? and entity_type = ?` + + if _, err := o.Raw(sql, projectID, userID, entityType).Exec(); err != nil { return err } @@ -54,27 +72,23 @@ func DeleteProjectMember(projectID int64, userID int) error { } // GetUserByProject gets all members of the project. -func GetUserByProject(projectID int64, queryUser models.User) ([]*models.Member, error) { +func GetUserByProject(projectID int64, queryUser models.User) ([]*models.UserMember, error) { o := GetOrmer() - sql := `select u.user_id, u.username, u.creation_time, u.update_time, r.name as rolename, - r.role_id as role - from user u - join project_member pm - on pm.project_id = ? and u.user_id = pm.user_id - join role r - on pm.role = r.role_id - where u.deleted = 0` + sql := `select pm.id as id, u.user_id, u.username, u.creation_time, u.update_time, r.name as rolename, + r.role_id as role, pm.entity_type as entity_type from user u join project_member pm + on pm.project_id = ? and u.user_id = pm.entity_id + join role r on pm.role = r.role_id where u.deleted = 0 and pm.entity_type = 'u' ` queryParam := make([]interface{}, 1) queryParam = append(queryParam, projectID) - if queryUser.Username != "" { - sql += " and u.username like ? " - queryParam = append(queryParam, "%"+escape(queryUser.Username)+"%") + if len(queryUser.Username) != 0 { + sql += ` and u.username like ? ` + queryParam = append(queryParam, `%`+Escape(queryUser.Username)+`%`) } sql += ` order by u.username ` - members := []*models.Member{} + members := []*models.UserMember{} _, err := o.Raw(sql, queryParam).QueryRows(&members) return members, err diff --git a/src/common/dao/replication_job.go b/src/common/dao/replication_job.go index a37a63f20..7b0c33f7e 100644 --- a/src/common/dao/replication_job.go +++ b/src/common/dao/replication_job.go @@ -90,7 +90,7 @@ func FilterRepTargets(name string) ([]*models.RepTarget, error) { sql := `select * from replication_target ` if len(name) != 0 { sql += `where name like ? ` - args = append(args, "%"+escape(name)+"%") + args = append(args, `%`+Escape(name)+`%`) } sql += `order by creation_time` @@ -173,11 +173,11 @@ func FilterRepPolicies(name string, projectID, page, pageSize int64) ([]*models. if len(name) != 0 && projectID != 0 { sql += `and rp.name like ? and rp.project_id = ? ` - args = append(args, "%"+escape(name)+"%") + args = append(args, `%`+Escape(name)+`%`) args = append(args, projectID) } else if len(name) != 0 { sql += `and rp.name like ? ` - args = append(args, "%"+escape(name)+"%") + args = append(args, `%`+Escape(name)+`%`) } else if projectID != 0 { sql += `and rp.project_id = ? ` args = append(args, projectID) diff --git a/src/common/dao/role.go b/src/common/dao/role.go index 71d64c1a8..a745fcb83 100644 --- a/src/common/dao/role.go +++ b/src/common/dao/role.go @@ -22,7 +22,7 @@ import ( ) // GetUserProjectRoles returns roles that the user has according to the project. -func GetUserProjectRoles(userID int, projectID int64) ([]models.Role, error) { +func GetUserProjectRoles(userID int, projectID int64, entityType string) ([]models.Role, error) { o := GetOrmer() @@ -32,7 +32,7 @@ func GetUserProjectRoles(userID int, projectID int64) ([]models.Role, error) { ( select role from project_member - where project_id = ? and user_id = ? + where project_id = ? and entity_id = ? and entity_type = 'u' )` var roleList []models.Role diff --git a/src/common/models/member.go b/src/common/models/member.go index 31686b020..a01a82a81 100644 --- a/src/common/models/member.go +++ b/src/common/models/member.go @@ -16,6 +16,17 @@ package models // Member holds the details of a member. type Member struct { + ID int `orm:"pk;column(id)" json:"id"` + ProjectID int64 `orm:"column(project_id)" json:"project_id"` + Entityname string `orm:"column(entity_name)" json:"entity_name"` + Rolename string `json:"role_name"` + Role int `json:"role_id"` + EntityID int `orm:"column(entity_id)" json:"entity_id"` + EntityType string `orm:"column(entity_type)" json:"entity_type"` +} + +// UserMember ... +type UserMember struct { ID int `orm:"pk;column(user_id)" json:"user_id"` Username string `json:"username"` Rolename string `json:"role_name"` diff --git a/src/common/security/local/context.go b/src/common/security/local/context.go index 8111423f2..2f1eddb62 100644 --- a/src/common/security/local/context.go +++ b/src/common/security/local/context.go @@ -175,7 +175,7 @@ func (s *SecurityContext) GetProjectRoles(projectIDOrName interface{}) []int { return roles } - roleList, err := dao.GetUserProjectRoles(user.UserID, project.ProjectID) + roleList, err := dao.GetUserProjectRoles(user.UserID, project.ProjectID, common.UserMember) if err != nil { log.Errorf("failed to get roles of user %d to project %d: %v", user.UserID, project.ProjectID, err) return roles @@ -192,5 +192,7 @@ func (s *SecurityContext) GetProjectRoles(projectIDOrName interface{}) []int { } } + //If len(roles)==0, Get Group Roles + return roles } diff --git a/src/common/security/local/context_test.go b/src/common/security/local/context_test.go index d3cb0724b..00f8e1517 100644 --- a/src/common/security/local/context_test.go +++ b/src/common/security/local/context_test.go @@ -123,23 +123,23 @@ func TestMain(m *testing.M) { defer dao.DeleteProject(id) // add project members - err = dao.AddProjectMember(private.ProjectID, projectAdminUser.UserID, common.RoleProjectAdmin) + _, err = dao.AddProjectMember(private.ProjectID, projectAdminUser.UserID, common.RoleProjectAdmin, common.UserMember) if err != nil { log.Fatalf("failed to add member: %v", err) } - defer dao.DeleteProjectMember(private.ProjectID, projectAdminUser.UserID) + defer dao.DeleteProjectMember(private.ProjectID, projectAdminUser.UserID, common.UserMember) - err = dao.AddProjectMember(private.ProjectID, developerUser.UserID, common.RoleDeveloper) + _, err = dao.AddProjectMember(private.ProjectID, developerUser.UserID, common.RoleDeveloper, common.UserMember) if err != nil { log.Fatalf("failed to add member: %v", err) } - defer dao.DeleteProjectMember(private.ProjectID, developerUser.UserID) + defer dao.DeleteProjectMember(private.ProjectID, developerUser.UserID, common.UserMember) - err = dao.AddProjectMember(private.ProjectID, guestUser.UserID, common.RoleGuest) + _, err = dao.AddProjectMember(private.ProjectID, guestUser.UserID, common.RoleGuest, common.UserMember) if err != nil { log.Fatalf("failed to add member: %v", err) } - defer dao.DeleteProjectMember(private.ProjectID, guestUser.UserID) + defer dao.DeleteProjectMember(private.ProjectID, guestUser.UserID, common.UserMember) os.Exit(m.Run()) } diff --git a/src/ui/api/api_test.go b/src/ui/api/api_test.go index bf07ed95f..f6d2911a5 100644 --- a/src/ui/api/api_test.go +++ b/src/ui/api/api_test.go @@ -24,6 +24,8 @@ import ( "strings" "testing" + "github.com/vmware/harbor/src/common" + "github.com/astaxie/beego" "github.com/dghubble/sling" "github.com/stretchr/testify/assert" @@ -224,7 +226,7 @@ func prepare() error { } projAdminID = int(id) - if err = dao.AddProjectMember(1, projAdminID, models.PROJECTADMIN); err != nil { + if _, err = dao.AddProjectMember(1, projAdminID, models.PROJECTADMIN, common.UserMember); err != nil { return err } @@ -239,7 +241,7 @@ func prepare() error { } projDeveloperID = int(id) - if err = dao.AddProjectMember(1, projDeveloperID, models.DEVELOPER); err != nil { + if _, err = dao.AddProjectMember(1, projDeveloperID, models.DEVELOPER, common.UserMember); err != nil { return err } @@ -254,13 +256,14 @@ func prepare() error { } projGuestID = int(id) - return dao.AddProjectMember(1, projGuestID, models.GUEST) + _, err = dao.AddProjectMember(1, projGuestID, models.GUEST, common.UserMember) + return err } func clean() { ids := []int{projAdminID, projDeveloperID, projGuestID} for _, id := range ids { - if err := dao.DeleteProjectMember(1, id); err != nil { + if err := dao.DeleteProjectMember(1, id, common.UserMember); err != nil { fmt.Printf("failed to clean up member %d from project library: %v", id, err) } } diff --git a/src/ui/api/harborapi_test.go b/src/ui/api/harborapi_test.go index accccec78..abca6f0e1 100644 --- a/src/ui/api/harborapi_test.go +++ b/src/ui/api/harborapi_test.go @@ -102,7 +102,7 @@ func init() { beego.Router("/api/users/:id/sysadmin", &UserAPI{}, "put:ToggleUserAdminRole") beego.Router("/api/projects/:id([0-9]+)/logs", &ProjectAPI{}, "get:Logs") beego.Router("/api/projects/:id([0-9]+)/_deletable", &ProjectAPI{}, "get:Deletable") - beego.Router("/api/projects/:pid([0-9]+)/members/?:mid", &ProjectMemberAPI{}, "get:Get;post:Post;delete:Delete;put:Put") + beego.Router("/api/projects/:pid([0-9]+)/members/?:mid", &ProjectUserMemberAPI{}, "get:Get;post:Post;delete:Delete;put:Put") beego.Router("/api/projects/:id([0-9]+)/metadatas/?:name", &MetadataAPI{}, "get:Get") beego.Router("/api/projects/:id([0-9]+)/metadatas/", &MetadataAPI{}, "post:Post") beego.Router("/api/projects/:id([0-9]+)/metadatas/:name", &MetadataAPI{}, "put:Put;delete:Delete") diff --git a/src/ui/api/member.go b/src/ui/api/member.go index a7c3ed778..e4855f72f 100644 --- a/src/ui/api/member.go +++ b/src/ui/api/member.go @@ -19,14 +19,16 @@ import ( "net/http" "strings" + "github.com/vmware/harbor/src/common" + "github.com/vmware/harbor/src/common/dao" "github.com/vmware/harbor/src/common/models" "github.com/vmware/harbor/src/common/utils/log" "github.com/vmware/harbor/src/ui/auth" ) -// ProjectMemberAPI handles request to /api/projects/{}/members/{} -type ProjectMemberAPI struct { +// ProjectUserMemberAPI handles request to /api/projects/{}/members/{} +type ProjectUserMemberAPI struct { BaseController memberID int currentUserID int @@ -40,7 +42,7 @@ type memberReq struct { } // Prepare validates the URL and parms -func (pma *ProjectMemberAPI) Prepare() { +func (pma *ProjectUserMemberAPI) Prepare() { pma.BaseController.Prepare() if !pma.SecurityCtx.IsAuthenticated() { @@ -116,7 +118,7 @@ func (pma *ProjectMemberAPI) Prepare() { } // Get ... -func (pma *ProjectMemberAPI) Get() { +func (pma *ProjectUserMemberAPI) Get() { pid := pma.project.ProjectID if pma.memberID == 0 { //member id not set return list of the members username := pma.GetString("username") @@ -129,7 +131,7 @@ func (pma *ProjectMemberAPI) Get() { } pma.Data["json"] = userList } else { //return detail of a member - roleList, err := listRoles(pma.memberID, pid) + roleList, err := listRoles(pma.memberID, pid, common.UserMember) if err != nil { log.Errorf("Error occurred in GetUserProjectRoles, error: %v", err) pma.CustomAbort(http.StatusInternalServerError, "Internal error.") @@ -155,7 +157,7 @@ func (pma *ProjectMemberAPI) Get() { } // Post ... -func (pma *ProjectMemberAPI) Post() { +func (pma *ProjectUserMemberAPI) Post() { projectID := pma.project.ProjectID var req memberReq @@ -193,7 +195,7 @@ func (pma *ProjectMemberAPI) Post() { userID = user.UserID } - rolelist, err := dao.GetUserProjectRoles(userID, projectID) + rolelist, err := dao.GetUserProjectRoles(userID, projectID, common.UserMember) if err != nil { log.Errorf("Error occurred in GetUserProjectRoles, error: %v", err) pma.CustomAbort(http.StatusInternalServerError, "Internal error.") @@ -215,7 +217,7 @@ func (pma *ProjectMemberAPI) Post() { pma.CustomAbort(http.StatusBadRequest, "invalid role") } - err = dao.AddProjectMember(projectID, userID, rid) + _, err = dao.AddProjectMember(projectID, userID, rid, common.UserMember) if err != nil { log.Errorf("Failed to update DB to add project user role, project id: %d, user id: %d, role id: %d", projectID, userID, rid) pma.RenderError(http.StatusInternalServerError, "Failed to update data in database") @@ -224,13 +226,13 @@ func (pma *ProjectMemberAPI) Post() { } // Put ... -func (pma *ProjectMemberAPI) Put() { +func (pma *ProjectUserMemberAPI) Put() { pid := pma.project.ProjectID mid := pma.memberID var req memberReq pma.DecodeJSONReq(&req) - roleList, err := dao.GetUserProjectRoles(mid, pid) + roleList, err := dao.GetUserProjectRoles(mid, pid, common.UserMember) if len(roleList) == 0 { log.Warningf("User is not in project, user id: %d, project id: %d", mid, pid) pma.RenderError(http.StatusNotFound, "user not exist in project") @@ -238,7 +240,7 @@ func (pma *ProjectMemberAPI) Put() { } //TODO: delete and insert should in one transaction //delete user project role record for the given user - err = dao.DeleteProjectMember(pid, mid) + err = dao.DeleteProjectMember(pid, mid, common.UserMember) if err != nil { log.Errorf("Failed to delete project roles for user, user id: %d, project id: %d, error: %v", mid, pid, err) pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB") @@ -246,7 +248,7 @@ func (pma *ProjectMemberAPI) Put() { } //insert roles in request for _, rid := range req.Roles { - err = dao.AddProjectMember(pid, mid, int(rid)) + _, err = dao.AddProjectMember(pid, mid, int(rid), common.UserMember) if err != nil { log.Errorf("Failed to update DB to add project user role, project id: %d, user id: %d, role id: %d", pid, mid, rid) pma.RenderError(http.StatusInternalServerError, "Failed to update data in database") @@ -256,11 +258,11 @@ func (pma *ProjectMemberAPI) Put() { } // Delete ... -func (pma *ProjectMemberAPI) Delete() { +func (pma *ProjectUserMemberAPI) Delete() { pid := pma.project.ProjectID mid := pma.memberID - err := dao.DeleteProjectMember(pid, mid) + err := dao.DeleteProjectMember(pid, mid, common.UserMember) if err != nil { log.Errorf("Failed to delete project roles for user, user id: %d, project id: %d, error: %v", mid, pid, err) pma.RenderError(http.StatusInternalServerError, "Failed to update data in DB") diff --git a/src/ui/api/replication_policy_test.go b/src/ui/api/replication_policy_test.go index d85376f47..74dd73069 100644 --- a/src/ui/api/replication_policy_test.go +++ b/src/ui/api/replication_policy_test.go @@ -21,6 +21,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/vmware/harbor/src/common" "github.com/vmware/harbor/src/common/dao" "github.com/vmware/harbor/src/common/models" "github.com/vmware/harbor/src/replication" @@ -320,10 +321,10 @@ func TestRepPolicyAPIList(t *testing.T) { } defer dao.DeleteUser(int(proAdminID)) - if err = dao.AddProjectMember(1, int(proAdminID), models.PROJECTADMIN); err != nil { + if _, err = dao.AddProjectMember(1, int(proAdminID), models.PROJECTADMIN, common.UserMember); err != nil { panic(err) } - defer dao.DeleteProjectMember(1, int(proAdminID)) + defer dao.DeleteProjectMember(1, int(proAdminID), common.UserMember) proDevID, err := dao.Register(projectDev) if err != nil { @@ -331,10 +332,10 @@ func TestRepPolicyAPIList(t *testing.T) { } defer dao.DeleteUser(int(proDevID)) - if err = dao.AddProjectMember(1, int(proDevID), models.DEVELOPER); err != nil { + if _, err = dao.AddProjectMember(1, int(proDevID), models.DEVELOPER, common.UserMember); err != nil { panic(err) } - defer dao.DeleteProjectMember(1, int(proDevID)) + defer dao.DeleteProjectMember(1, int(proDevID), common.UserMember) // 400: invalid project ID runCodeCheckingCases(t, &codeCheckingCase{ diff --git a/src/ui/api/utils.go b/src/ui/api/utils.go index 7f883109b..0f1c2acac 100644 --- a/src/ui/api/utils.go +++ b/src/ui/api/utils.go @@ -36,7 +36,7 @@ import ( ) //sysadmin has all privileges to all projects -func listRoles(userID int, projectID int64) ([]models.Role, error) { +func listRoles(userID int, projectID int64, entityType string) ([]models.Role, error) { roles := make([]models.Role, 0, 1) isSysAdmin, err := dao.IsAdminRole(userID) if err != nil { @@ -53,7 +53,7 @@ func listRoles(userID int, projectID int64) ([]models.Role, error) { return roles, nil } - rs, err := dao.GetUserProjectRoles(userID, projectID) + rs, err := dao.GetUserProjectRoles(userID, projectID, entityType) if err != nil { log.Errorf("failed to get user %d 's roles for project %d: %v", userID, projectID, err) return roles, err diff --git a/src/ui/router.go b/src/ui/router.go index 4e9152bfd..eaa511d29 100644 --- a/src/ui/router.go +++ b/src/ui/router.go @@ -45,7 +45,7 @@ func initRouters() { beego.Router("/sendEmail", &controllers.CommonController{}, "get:SendResetEmail") //API: - beego.Router("/api/projects/:pid([0-9]+)/members/?:mid", &api.ProjectMemberAPI{}) + beego.Router("/api/projects/:pid([0-9]+)/members/?:mid", &api.ProjectUserMemberAPI{}) beego.Router("/api/projects/", &api.ProjectAPI{}, "head:Head") beego.Router("/api/projects/:id([0-9]+)", &api.ProjectAPI{})