feat(api): support project name in the path of apis (#13744)

Support project name in the path of projects and robotsV1 APIs.

Signed-off-by: He Weiwei <hweiwei@vmware.com>
This commit is contained in:
He Weiwei 2020-12-14 15:48:52 +08:00 committed by GitHub
parent 949379f7bc
commit af24a073dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 122 additions and 78 deletions

View File

@ -98,6 +98,7 @@ paths:
operationId: createProject operationId: createProject
parameters: parameters:
- $ref: '#/parameters/requestId' - $ref: '#/parameters/requestId'
- $ref: '#/parameters/resourceNameInLocation'
- name: project - name: project
in: body in: body
description: New created project. description: New created project.
@ -115,7 +116,7 @@ paths:
$ref: '#/responses/409' $ref: '#/responses/409'
'500': '500':
$ref: '#/responses/500' $ref: '#/responses/500'
'/projects/{project_id}': '/projects/{project_name_or_id}':
get: get:
summary: Return specific project detail information summary: Return specific project detail information
description: This endpoint returns specific project information by project ID. description: This endpoint returns specific project information by project ID.
@ -124,7 +125,8 @@ paths:
operationId: getProject operationId: getProject
parameters: parameters:
- $ref: '#/parameters/requestId' - $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectId' - $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
responses: responses:
'200': '200':
description: Return matched project information. description: Return matched project information.
@ -142,7 +144,8 @@ paths:
operationId: updateProject operationId: updateProject
parameters: parameters:
- $ref: '#/parameters/requestId' - $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectId' - $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
- name: project - name: project
in: body in: body
required: true required: true
@ -170,7 +173,8 @@ paths:
operationId: deleteProject operationId: deleteProject
parameters: parameters:
- $ref: '#/parameters/requestId' - $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectId' - $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
responses: responses:
'200': '200':
$ref: '#/responses/200' $ref: '#/responses/200'
@ -184,7 +188,7 @@ paths:
$ref: '#/responses/412' $ref: '#/responses/412'
'500': '500':
$ref: '#/responses/500' $ref: '#/responses/500'
/projects/{project_id}/_deletable: /projects/{project_name_or_id}/_deletable:
get: get:
summary: Get the deletable status of the project summary: Get the deletable status of the project
description: Get the deletable status of the project description: Get the deletable status of the project
@ -193,7 +197,8 @@ paths:
operationId: getProjectDeletable operationId: getProjectDeletable
parameters: parameters:
- $ref: '#/parameters/requestId' - $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectId' - $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
responses: responses:
'200': '200':
description: Return deletable status of the project. description: Return deletable status of the project.
@ -207,7 +212,7 @@ paths:
$ref: '#/responses/404' $ref: '#/responses/404'
'500': '500':
$ref: '#/responses/500' $ref: '#/responses/500'
'/projects/{project_id}/summary': '/projects/{project_name_or_id}/summary':
get: get:
summary: Get summary of the project. summary: Get summary of the project.
description: Get summary of the project. description: Get summary of the project.
@ -216,7 +221,8 @@ paths:
operationId: getProjectSummary operationId: getProjectSummary
parameters: parameters:
- $ref: '#/parameters/requestId' - $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectId' - $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
responses: responses:
'200': '200':
description: Get summary of the project successfully. description: Get summary of the project successfully.
@ -1416,13 +1422,14 @@ paths:
$ref: '#/responses/404' $ref: '#/responses/404'
'500': '500':
$ref: '#/responses/500' $ref: '#/responses/500'
/projects/{project_id_or_name}/robots: /projects/{project_name_or_id}/robots:
get: get:
summary: Get all robot accounts of specified project summary: Get all robot accounts of specified project
description: Get all robot accounts of specified project description: Get all robot accounts of specified project
parameters: parameters:
- $ref: '#/parameters/requestId' - $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectIDOrName' - $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
- $ref: '#/parameters/page' - $ref: '#/parameters/page'
- $ref: '#/parameters/pageSize' - $ref: '#/parameters/pageSize'
- $ref: '#/parameters/query' - $ref: '#/parameters/query'
@ -1457,7 +1464,8 @@ paths:
operationId: CreateRobotV1 operationId: CreateRobotV1
parameters: parameters:
- $ref: '#/parameters/requestId' - $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectIDOrName' - $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
- name: robot - name: robot
in: body in: body
description: The JSON object of a robot account. description: The JSON object of a robot account.
@ -1486,7 +1494,7 @@ paths:
$ref: '#/responses/404' $ref: '#/responses/404'
'500': '500':
$ref: '#/responses/500' $ref: '#/responses/500'
/projects/{project_id_or_name}/robots/{robot_id}: /projects/{project_name_or_id}/robots/{robot_id}:
get: get:
summary: Get a robot account summary: Get a robot account
description: This endpoint returns specific robot account information by robot ID. description: This endpoint returns specific robot account information by robot ID.
@ -1495,7 +1503,8 @@ paths:
operationId: GetRobotByIDV1 operationId: GetRobotByIDV1
parameters: parameters:
- $ref: '#/parameters/requestId' - $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectIDOrName' - $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
- $ref: '#/parameters/robotId' - $ref: '#/parameters/robotId'
responses: responses:
'200': '200':
@ -1518,7 +1527,8 @@ paths:
operationId: UpdateRobotV1 operationId: UpdateRobotV1
parameters: parameters:
- $ref: '#/parameters/requestId' - $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectIDOrName' - $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
- $ref: '#/parameters/robotId' - $ref: '#/parameters/robotId'
- name: robot - name: robot
in: body in: body
@ -1549,7 +1559,8 @@ paths:
operationId: DeleteRobotV1 operationId: DeleteRobotV1
parameters: parameters:
- $ref: '#/parameters/requestId' - $ref: '#/parameters/requestId'
- $ref: '#/parameters/projectIDOrName' - $ref: '#/parameters/isResourceName'
- $ref: '#/parameters/projectNameOrId'
- $ref: '#/parameters/robotId' - $ref: '#/parameters/robotId'
responses: responses:
'200': '200':
@ -2193,23 +2204,30 @@ parameters:
type: string type: string
required: false required: false
minLength: 1 minLength: 1
resourceNameInLocation:
name: X-Resource-Name-In-Location
description: The flag to indicate whether to return the name of the resource in Location. When X-Resource-Name-In-Location is true, the Location will return the name of the resource.
in: header
type: boolean
required: false
default: false
isResourceName:
name: X-Is-Resource-Name
description: The flag to indicate whether the parameter which supports both name and id in the path is the name of the resource. When the X-Is-Resource-Name is false and the parameter can be converted to an integer, the parameter will be as an id, otherwise, it will be as a name.
in: header
type: boolean
required: false
default: false
projectName: projectName:
name: project_name name: project_name
in: path in: path
description: The name of the project description: The name of the project
required: true required: true
type: string type: string
projectId: projectNameOrId:
name: project_id name: project_name_or_id
in: path in: path
description: The ID of the project description: The name or id of the project
required: true
type: integer
format: int64
projectIDOrName:
name: project_id_or_name
in: path
description: The id or name of the project
required: true required: true
type: string type: string
repositoryName: repositoryName:

View File

@ -183,16 +183,23 @@ func (a *projectAPI) CreateProject(ctx context.Context, params operation.CreateP
} }
} }
location := fmt.Sprintf("%s/%d", strings.TrimSuffix(params.HTTPRequest.URL.Path, "/"), projectID) var location string
if lib.BoolValue(params.XResourceNameInLocation) {
location = fmt.Sprintf("%s/%s", strings.TrimSuffix(params.HTTPRequest.URL.Path, "/"), req.ProjectName)
} else {
location = fmt.Sprintf("%s/%d", strings.TrimSuffix(params.HTTPRequest.URL.Path, "/"), projectID)
}
return operation.NewCreateProjectCreated().WithLocation(location) return operation.NewCreateProjectCreated().WithLocation(location)
} }
func (a *projectAPI) DeleteProject(ctx context.Context, params operation.DeleteProjectParams) middleware.Responder { func (a *projectAPI) DeleteProject(ctx context.Context, params operation.DeleteProjectParams) middleware.Responder {
if err := a.RequireProjectAccess(ctx, params.ProjectID, rbac.ActionDelete); err != nil { projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := a.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionDelete); err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
result, err := a.deletable(ctx, params.ProjectID) p, result, err := a.deletable(ctx, projectNameOrID)
if err != nil { if err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
@ -201,19 +208,19 @@ func (a *projectAPI) DeleteProject(ctx context.Context, params operation.DeleteP
return a.SendError(ctx, errors.PreconditionFailedError(errors.New(result.Message))) return a.SendError(ctx, errors.PreconditionFailedError(errors.New(result.Message)))
} }
if err := a.projectCtl.Delete(ctx, params.ProjectID); err != nil { if err := a.projectCtl.Delete(ctx, p.ProjectID); err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
// remove the robot associated with the project // remove the robot associated with the project
if err := a.robotMgr.DeleteByProjectID(ctx, params.ProjectID); err != nil { if err := a.robotMgr.DeleteByProjectID(ctx, p.ProjectID); err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
referenceID := quota.ReferenceID(params.ProjectID) referenceID := quota.ReferenceID(p.ProjectID)
q, err := a.quotaCtl.GetByRef(ctx, quota.ProjectReference, referenceID) q, err := a.quotaCtl.GetByRef(ctx, quota.ProjectReference, referenceID)
if err != nil { if err != nil {
log.Warningf("failed to get quota for project %d, error: %v", params.ProjectID, err) log.Warningf("failed to get quota for project %s, error: %v", projectNameOrID, err)
} else { } else {
if err := a.quotaCtl.Delete(ctx, q.ID); err != nil { if err := a.quotaCtl.Delete(ctx, q.ID); err != nil {
return a.SendError(ctx, fmt.Errorf("failed to delete quota for project: %v", err)) return a.SendError(ctx, fmt.Errorf("failed to delete quota for project: %v", err))
@ -221,7 +228,7 @@ func (a *projectAPI) DeleteProject(ctx context.Context, params operation.DeleteP
} }
// preheat policies under the project should be deleted after deleting the project // preheat policies under the project should be deleted after deleting the project
if err = a.preheatCtl.DeletePoliciesOfProject(ctx, params.ProjectID); err != nil { if err = a.preheatCtl.DeletePoliciesOfProject(ctx, p.ProjectID); err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
@ -269,11 +276,12 @@ func (a *projectAPI) GetLogs(ctx context.Context, params operation.GetLogsParams
} }
func (a *projectAPI) GetProject(ctx context.Context, params operation.GetProjectParams) middleware.Responder { func (a *projectAPI) GetProject(ctx context.Context, params operation.GetProjectParams) middleware.Responder {
if err := a.RequireProjectAccess(ctx, params.ProjectID, rbac.ActionRead); err != nil { projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := a.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionRead); err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
p, err := a.getProject(ctx, params.ProjectID, project.WithCVEAllowlist(), project.WithOwner()) p, err := a.getProject(ctx, projectNameOrID, project.WithCVEAllowlist(), project.WithOwner())
if err != nil { if err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
@ -282,11 +290,12 @@ func (a *projectAPI) GetProject(ctx context.Context, params operation.GetProject
} }
func (a *projectAPI) GetProjectDeletable(ctx context.Context, params operation.GetProjectDeletableParams) middleware.Responder { func (a *projectAPI) GetProjectDeletable(ctx context.Context, params operation.GetProjectDeletableParams) middleware.Responder {
if err := a.RequireProjectAccess(ctx, params.ProjectID, rbac.ActionDelete); err != nil { projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := a.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionDelete); err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
result, err := a.deletable(ctx, params.ProjectID) _, result, err := a.deletable(ctx, projectNameOrID)
if err != nil { if err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
@ -295,11 +304,12 @@ func (a *projectAPI) GetProjectDeletable(ctx context.Context, params operation.G
} }
func (a *projectAPI) GetProjectSummary(ctx context.Context, params operation.GetProjectSummaryParams) middleware.Responder { func (a *projectAPI) GetProjectSummary(ctx context.Context, params operation.GetProjectSummaryParams) middleware.Responder {
if err := a.RequireProjectAccess(ctx, params.ProjectID, rbac.ActionRead); err != nil { projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := a.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionRead); err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
p, err := a.getProject(ctx, params.ProjectID) p, err := a.getProject(ctx, projectNameOrID)
if err != nil { if err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
@ -440,11 +450,12 @@ func (a *projectAPI) ListProjects(ctx context.Context, params operation.ListProj
} }
func (a *projectAPI) UpdateProject(ctx context.Context, params operation.UpdateProjectParams) middleware.Responder { func (a *projectAPI) UpdateProject(ctx context.Context, params operation.UpdateProjectParams) middleware.Responder {
if err := a.RequireProjectAccess(ctx, params.ProjectID, rbac.ActionUpdate); err != nil { projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := a.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionUpdate); err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
p, err := a.projectCtl.Get(ctx, params.ProjectID, project.Metadata(false)) p, err := a.projectCtl.Get(ctx, projectNameOrID, project.Metadata(false))
if err != nil { if err != nil {
return a.SendError(ctx, err) return a.SendError(ctx, err)
} }
@ -452,10 +463,10 @@ func (a *projectAPI) UpdateProject(ctx context.Context, params operation.UpdateP
if params.Project.CVEAllowlist != nil { if params.Project.CVEAllowlist != nil {
if params.Project.CVEAllowlist.ProjectID == 0 { if params.Project.CVEAllowlist.ProjectID == 0 {
// project_id in cve_allowlist not provided or provided as 0, let it to be the id of the project which will be updating // project_id in cve_allowlist not provided or provided as 0, let it to be the id of the project which will be updating
params.Project.CVEAllowlist.ProjectID = params.ProjectID params.Project.CVEAllowlist.ProjectID = p.ProjectID
} else if params.Project.CVEAllowlist.ProjectID != params.ProjectID { } else if params.Project.CVEAllowlist.ProjectID != p.ProjectID {
return a.SendError(ctx, errors.BadRequestError(nil). return a.SendError(ctx, errors.BadRequestError(nil).
WithMessage("project_id in cve_allowlist must be %d but it's %d", params.ProjectID, params.Project.CVEAllowlist.ProjectID)) WithMessage("project_id in cve_allowlist must be %d but it's %d", p.ProjectID, params.Project.CVEAllowlist.ProjectID))
} }
if err := lib.JSONCopy(&p.CVEAllowlist, params.Project.CVEAllowlist); err != nil { if err := lib.JSONCopy(&p.CVEAllowlist, params.Project.CVEAllowlist); err != nil {
@ -477,26 +488,26 @@ func (a *projectAPI) UpdateProject(ctx context.Context, params operation.UpdateP
return operation.NewUpdateProjectOK() return operation.NewUpdateProjectOK()
} }
func (a *projectAPI) deletable(ctx context.Context, projectID int64) (*models.ProjectDeletable, error) { func (a *projectAPI) deletable(ctx context.Context, projectNameOrID interface{}) (*project.Project, *models.ProjectDeletable, error) {
proj, err := a.getProject(ctx, projectID) p, err := a.getProject(ctx, projectNameOrID)
if err != nil { if err != nil {
return nil, err return nil, nil, err
} }
result := &models.ProjectDeletable{Deletable: true} result := &models.ProjectDeletable{Deletable: true}
if proj.RepoCount > 0 { if p.RepoCount > 0 {
result.Deletable = false result.Deletable = false
result.Message = "the project contains repositories, can not be deleted" result.Message = "the project contains repositories, can not be deleted"
} else if proj.ChartCount > 0 { } else if p.ChartCount > 0 {
result.Deletable = false result.Deletable = false
result.Message = "the project contains helm charts, can not be deleted" result.Message = "the project contains helm charts, can not be deleted"
} }
return result, nil return p, result, nil
} }
func (a *projectAPI) getProject(ctx context.Context, projectID int64, options ...project.Option) (*project.Project, error) { func (a *projectAPI) getProject(ctx context.Context, projectNameOrID interface{}, options ...project.Option) (*project.Project, error) {
p, err := a.projectCtl.Get(ctx, projectID, options...) p, err := a.projectCtl.Get(ctx, projectNameOrID, options...)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -3,10 +3,12 @@ package handler
import ( import (
"context" "context"
"fmt" "fmt"
"regexp"
"strings"
"github.com/go-openapi/runtime/middleware" "github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt" "github.com/go-openapi/strfmt"
"github.com/goharbor/harbor/src/common/rbac" "github.com/goharbor/harbor/src/common/rbac"
"github.com/goharbor/harbor/src/common/utils"
"github.com/goharbor/harbor/src/controller/project" "github.com/goharbor/harbor/src/controller/project"
"github.com/goharbor/harbor/src/controller/robot" "github.com/goharbor/harbor/src/controller/robot"
"github.com/goharbor/harbor/src/core/config" "github.com/goharbor/harbor/src/core/config"
@ -20,8 +22,6 @@ import (
handler_model "github.com/goharbor/harbor/src/server/v2.0/handler/model" handler_model "github.com/goharbor/harbor/src/server/v2.0/handler/model"
"github.com/goharbor/harbor/src/server/v2.0/models" "github.com/goharbor/harbor/src/server/v2.0/models"
operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/robotv1" operation "github.com/goharbor/harbor/src/server/v2.0/restapi/operations/robotv1"
"regexp"
"strings"
) )
func newRobotV1API() *robotV1API { func newRobotV1API() *robotV1API {
@ -40,7 +40,8 @@ type robotV1API struct {
} }
func (rAPI *robotV1API) CreateRobotV1(ctx context.Context, params operation.CreateRobotV1Params) middleware.Responder { func (rAPI *robotV1API) CreateRobotV1(ctx context.Context, params operation.CreateRobotV1Params) middleware.Responder {
if err := rAPI.RequireProjectAccess(ctx, params.ProjectIDOrName, rbac.ActionCreate, rbac.ResourceRobot); err != nil { projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := rAPI.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionCreate, rbac.ResourceRobot); err != nil {
return rAPI.SendError(ctx, err) return rAPI.SendError(ctx, err)
} }
@ -57,19 +58,11 @@ func (rAPI *robotV1API) CreateRobotV1(ctx context.Context, params operation.Crea
Level: robot.LEVELPROJECT, Level: robot.LEVELPROJECT,
} }
projectID, projectName, err := utils.ParseProjectIDOrName(params.ProjectIDOrName) projectName, ok := projectNameOrID.(string)
if err != nil { if !ok {
return rAPI.SendError(ctx, err) p, err := rAPI.projectCtr.Get(ctx, projectNameOrID, project.Metadata(false))
}
if projectID != 0 {
p, err := project.Ctl.Get(ctx, projectID)
if err != nil { if err != nil {
log.Errorf("failed to get project %s: %v", projectName, err) log.Errorf("failed to get project %s: %v", projectNameOrID, err)
return rAPI.SendError(ctx, err)
}
if p == nil {
log.Warningf("project %s not found", projectName)
return rAPI.SendError(ctx, err) return rAPI.SendError(ctx, err)
} }
projectName = p.Name projectName = p.Name
@ -116,11 +109,12 @@ func (rAPI *robotV1API) CreateRobotV1(ctx context.Context, params operation.Crea
} }
func (rAPI *robotV1API) DeleteRobotV1(ctx context.Context, params operation.DeleteRobotV1Params) middleware.Responder { func (rAPI *robotV1API) DeleteRobotV1(ctx context.Context, params operation.DeleteRobotV1Params) middleware.Responder {
if err := rAPI.RequireProjectAccess(ctx, params.ProjectIDOrName, rbac.ActionDelete, rbac.ResourceRobot); err != nil { projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := rAPI.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionDelete, rbac.ResourceRobot); err != nil {
return rAPI.SendError(ctx, err) return rAPI.SendError(ctx, err)
} }
pro, err := rAPI.projectCtr.Get(ctx, params.ProjectIDOrName) pro, err := rAPI.projectCtr.Get(ctx, projectNameOrID)
if err != nil { if err != nil {
return rAPI.SendError(ctx, err) return rAPI.SendError(ctx, err)
} }
@ -142,7 +136,8 @@ func (rAPI *robotV1API) DeleteRobotV1(ctx context.Context, params operation.Dele
} }
func (rAPI *robotV1API) ListRobotV1(ctx context.Context, params operation.ListRobotV1Params) middleware.Responder { func (rAPI *robotV1API) ListRobotV1(ctx context.Context, params operation.ListRobotV1Params) middleware.Responder {
if err := rAPI.RequireProjectAccess(ctx, params.ProjectIDOrName, rbac.ActionList, rbac.ResourceRobot); err != nil { projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := rAPI.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionList, rbac.ResourceRobot); err != nil {
return rAPI.SendError(ctx, err) return rAPI.SendError(ctx, err)
} }
@ -151,7 +146,7 @@ func (rAPI *robotV1API) ListRobotV1(ctx context.Context, params operation.ListRo
return rAPI.SendError(ctx, err) return rAPI.SendError(ctx, err)
} }
pro, err := rAPI.projectCtr.Get(ctx, params.ProjectIDOrName) pro, err := rAPI.projectCtr.Get(ctx, projectNameOrID)
if err != nil { if err != nil {
return rAPI.SendError(ctx, err) return rAPI.SendError(ctx, err)
} }
@ -182,11 +177,12 @@ func (rAPI *robotV1API) ListRobotV1(ctx context.Context, params operation.ListRo
} }
func (rAPI *robotV1API) GetRobotByIDV1(ctx context.Context, params operation.GetRobotByIDV1Params) middleware.Responder { func (rAPI *robotV1API) GetRobotByIDV1(ctx context.Context, params operation.GetRobotByIDV1Params) middleware.Responder {
if err := rAPI.RequireProjectAccess(ctx, params.ProjectIDOrName, rbac.ActionRead, rbac.ResourceRobot); err != nil { projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := rAPI.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionRead, rbac.ResourceRobot); err != nil {
return rAPI.SendError(ctx, err) return rAPI.SendError(ctx, err)
} }
pro, err := rAPI.projectCtr.Get(ctx, params.ProjectIDOrName) pro, err := rAPI.projectCtr.Get(ctx, projectNameOrID)
if err != nil { if err != nil {
return rAPI.SendError(ctx, err) return rAPI.SendError(ctx, err)
} }
@ -205,11 +201,12 @@ func (rAPI *robotV1API) GetRobotByIDV1(ctx context.Context, params operation.Get
} }
func (rAPI *robotV1API) UpdateRobotV1(ctx context.Context, params operation.UpdateRobotV1Params) middleware.Responder { func (rAPI *robotV1API) UpdateRobotV1(ctx context.Context, params operation.UpdateRobotV1Params) middleware.Responder {
if err := rAPI.RequireProjectAccess(ctx, params.ProjectIDOrName, rbac.ActionUpdate, rbac.ResourceRobot); err != nil { projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
if err := rAPI.RequireProjectAccess(ctx, projectNameOrID, rbac.ActionUpdate, rbac.ResourceRobot); err != nil {
return rAPI.SendError(ctx, err) return rAPI.SendError(ctx, err)
} }
pro, err := rAPI.projectCtr.Get(ctx, params.ProjectIDOrName) pro, err := rAPI.projectCtr.Get(ctx, projectNameOrID)
if err != nil { if err != nil {
return rAPI.SendError(ctx, err) return rAPI.SendError(ctx, err)
} }
@ -251,7 +248,8 @@ func (rAPI *robotV1API) validate(ctx context.Context, params operation.CreateRob
return errors.New(nil).WithMessage("bad request no access").WithCode(errors.BadRequestCode) return errors.New(nil).WithMessage("bad request no access").WithCode(errors.BadRequestCode)
} }
pro, err := rAPI.projectCtr.Get(ctx, params.ProjectIDOrName) projectNameOrID := parseProjectNameOrID(params.ProjectNameOrID, params.XIsResourceName)
pro, err := rAPI.projectCtr.Get(ctx, projectNameOrID)
if err != nil { if err != nil {
return err return err
} }
@ -267,7 +265,7 @@ func (rAPI *robotV1API) validate(ctx context.Context, params operation.CreateRob
p := &types.Policy{} p := &types.Policy{}
lib.JSONCopy(p, policy) lib.JSONCopy(p, policy)
if !mp[p.String()] { if !mp[p.String()] {
return errors.New(nil).WithMessage("%s action of %s resource not exist in project %s", policy.Action, policy.Resource, params.ProjectIDOrName).WithCode(errors.BadRequestCode) return errors.New(nil).WithMessage("%s action of %s resource not exist in project %s", policy.Action, policy.Resource, projectNameOrID).WithCode(errors.BadRequestCode)
} }
} }

View File

@ -20,10 +20,12 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"reflect" "reflect"
"strconv"
"github.com/goharbor/harbor/src/controller/artifact" "github.com/goharbor/harbor/src/controller/artifact"
"github.com/goharbor/harbor/src/controller/artifact/processor" "github.com/goharbor/harbor/src/controller/artifact/processor"
"github.com/goharbor/harbor/src/controller/scan" "github.com/goharbor/harbor/src/controller/scan"
"github.com/goharbor/harbor/src/lib"
"github.com/goharbor/harbor/src/lib/log" "github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/pkg/scan/report" "github.com/goharbor/harbor/src/pkg/scan/report"
v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1" v1 "github.com/goharbor/harbor/src/pkg/scan/rest/v1"
@ -126,3 +128,18 @@ func unescapePathParams(params interface{}, fieldNames ...string) error {
return nil return nil
} }
func parseProjectNameOrID(str string, isResourceName *bool) interface{} {
if lib.BoolValue(isResourceName) {
// always as projectName
return str
}
v, err := strconv.ParseInt(str, 10, 64)
if err != nil {
// it's projectName
return str
}
return v // projectID
}