From 64dc5122e65d635cc31fffdad55f7e596b1da8b1 Mon Sep 17 00:00:00 2001 From: Daniel Jiang Date: Sun, 10 Nov 2019 15:54:03 +0800 Subject: [PATCH] Add role list in project response This commit fixes #9771 It compares the roles to return the one with highest permission in the response of `GET /api/projects`. In addition to that, it adds the role list to the response, because a user can have multiple roles in a project. It also removes the togglable attribute as it's not used anywhere. Signed-off-by: Daniel Jiang --- API/harbor/swagger.yaml | 9 ++++++- src/common/models/project.go | 2 +- src/core/api/project.go | 34 +++++++++++++++++------ src/core/api/project_test.go | 52 ++++++++++++++++++++++++++++++++++++ src/core/api/search.go | 9 +------ 5 files changed, 88 insertions(+), 18 deletions(-) diff --git a/API/harbor/swagger.yaml b/API/harbor/swagger.yaml index 9f37296e6e..99b318f4c7 100644 --- a/API/harbor/swagger.yaml +++ b/API/harbor/swagger.yaml @@ -4871,7 +4871,14 @@ definitions: description: Correspond to the UI about whether the project's publicity is updatable (for UI) current_user_role_id: type: integer - description: The role ID of the current user who triggered the API (for UI) + description: The role ID with highest permission of the current user who triggered the API (for UI) + deprecated: true + current_user_role_ids: + type: array + items: + type: integer + format: int32 + description: The list of role ID of the current user who triggered the API (for UI) repo_count: type: integer description: The number of the repositories under this project. diff --git a/src/common/models/project.go b/src/common/models/project.go index 38e1622bba..7528a9bdc7 100644 --- a/src/common/models/project.go +++ b/src/common/models/project.go @@ -39,8 +39,8 @@ type Project struct { UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"` Deleted bool `orm:"column(deleted)" json:"deleted"` OwnerName string `orm:"-" json:"owner_name"` - Togglable bool `orm:"-" json:"togglable"` Role int `orm:"-" json:"current_user_role_id"` + RoleList []int `orm:"-" json:"current_user_role_ids"` RepoCount int64 `orm:"-" json:"repo_count"` ChartCount uint64 `orm:"-" json:"chart_count"` Metadata map[string]string `orm:"-" json:"metadata"` diff --git a/src/core/api/project.go b/src/core/api/project.go index 0028ccca76..c5f1eb0bc8 100644 --- a/src/core/api/project.go +++ b/src/core/api/project.go @@ -460,14 +460,8 @@ func (p *ProjectAPI) List() { func (p *ProjectAPI) populateProperties(project *models.Project) error { if p.SecurityCtx.IsAuthenticated() { roles := p.SecurityCtx.GetProjectRoles(project.ProjectID) - if len(roles) != 0 { - project.Role = roles[0] - } - - if project.Role == common.RoleProjectAdmin || - p.SecurityCtx.IsSysAdmin() { - project.Togglable = true - } + project.RoleList = roles + project.Role = highestRole(roles) } total, err := dao.GetTotalOfRepositories(&models.RepositoryQuery{ @@ -712,3 +706,27 @@ func getProjectMemberSummary(projectID int64, summary *models.ProjectSummary) { wg.Wait() } + +// Returns the highest role in the role list. +// This func should be removed once we deprecate the "current_user_role_id" in project API +// A user can have multiple roles and they may not have a strict ranking relationship +func highestRole(roles []int) int { + if roles == nil { + return 0 + } + rolePower := map[int]int{ + common.RoleProjectAdmin: 50, + common.RoleMaster: 40, + common.RoleDeveloper: 30, + common.RoleGuest: 20, + common.RoleLimitedGuest: 10, + } + var highest, highestPower int + for _, role := range roles { + if p, ok := rolePower[role]; ok && p > highestPower { + highest = role + highestPower = p + } + } + return highest +} diff --git a/src/core/api/project_test.go b/src/core/api/project_test.go index 9944fbcbbd..406b439f89 100644 --- a/src/core/api/project_test.go +++ b/src/core/api/project_test.go @@ -15,6 +15,7 @@ package api import ( "fmt" + "github.com/goharbor/harbor/src/common" "net/http" "strconv" "testing" @@ -529,3 +530,54 @@ func TestProjectSummary(t *testing.T) { fmt.Printf("\n") } + +func TestHighestRole(t *testing.T) { + cases := []struct { + input []int + expect int + }{ + { + []int{}, + 0, + }, + { + []int{ + common.RoleDeveloper, + common.RoleMaster, + common.RoleLimitedGuest, + }, + common.RoleMaster, + }, + { + []int{ + common.RoleProjectAdmin, + common.RoleMaster, + common.RoleMaster, + }, + common.RoleProjectAdmin, + }, + { + []int{ + 99, + 33, + common.RoleLimitedGuest, + }, + common.RoleLimitedGuest, + }, + { + []int{ + 99, + 99, + 99, + }, + 0, + }, + { + nil, + 0, + }, + } + for _, c := range cases { + assert.Equal(t, c.expect, highestRole(c.input)) + } +} diff --git a/src/core/api/search.go b/src/core/api/search.go index 4519de42ef..f4df859fe5 100644 --- a/src/core/api/search.go +++ b/src/core/api/search.go @@ -18,7 +18,6 @@ import ( "fmt" "strings" - "github.com/goharbor/harbor/src/common" "github.com/goharbor/harbor/src/common/dao" "github.com/goharbor/harbor/src/common/models" "github.com/goharbor/harbor/src/common/utils" @@ -96,13 +95,7 @@ func (s *SearchAPI) Get() { if isAuthenticated { roles := s.SecurityCtx.GetProjectRoles(p.ProjectID) - if len(roles) != 0 { - p.Role = roles[0] - } - - if p.Role == common.RoleProjectAdmin || isSysAdmin { - p.Togglable = true - } + p.Role = highestRole(roles) } total, err := dao.GetTotalOfRepositories(&models.RepositoryQuery{