mirror of
https://github.com/goharbor/harbor.git
synced 2024-09-27 21:12:42 +02:00
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:
parent
949379f7bc
commit
af24a073dc
@ -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:
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 !ok {
|
||||||
|
p, err := rAPI.projectCtr.Get(ctx, projectNameOrID, project.Metadata(false))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rAPI.SendError(ctx, err)
|
log.Errorf("failed to get project %s: %v", projectNameOrID, err)
|
||||||
}
|
|
||||||
|
|
||||||
if projectID != 0 {
|
|
||||||
p, err := project.Ctl.Get(ctx, projectID)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("failed to get project %s: %v", projectName, 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user