2018-10-18 18:01:31 +02:00
|
|
|
// Copyright 2018 Project Harbor Authors
|
2018-03-07 06:20:28 +01:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
2019-04-17 10:43:06 +02:00
|
|
|
"errors"
|
2018-03-07 06:20:28 +01:00
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"strconv"
|
|
|
|
|
2018-08-23 09:02:20 +02:00
|
|
|
"github.com/goharbor/harbor/src/common"
|
|
|
|
"github.com/goharbor/harbor/src/common/dao"
|
|
|
|
"github.com/goharbor/harbor/src/common/models"
|
2019-02-01 11:55:06 +01:00
|
|
|
"github.com/goharbor/harbor/src/common/rbac"
|
2018-03-07 06:20:28 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// LabelAPI handles requests for label management
|
|
|
|
type LabelAPI struct {
|
|
|
|
label *models.Label
|
|
|
|
BaseController
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare ...
|
|
|
|
func (l *LabelAPI) Prepare() {
|
|
|
|
l.BaseController.Prepare()
|
|
|
|
method := l.Ctx.Request.Method
|
|
|
|
if method == http.MethodGet {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// POST, PUT, DELETE need login first
|
|
|
|
if !l.SecurityCtx.IsAuthenticated() {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendUnAuthorizedError(errors.New("UnAuthorized"))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if method == http.MethodPut || method == http.MethodDelete {
|
|
|
|
id, err := l.GetInt64FromPath(":id")
|
|
|
|
if err != nil || id <= 0 {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendBadRequestError(errors.New("invalid lable ID"))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
label, err := dao.GetLabel(id)
|
|
|
|
if err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to get label %d: %v", id, err))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-07 10:05:50 +02:00
|
|
|
if label == nil || label.Deleted {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendNotFoundError(fmt.Errorf("label %d not found", id))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-02-01 11:55:06 +01:00
|
|
|
l.label = label
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *LabelAPI) requireAccess(label *models.Label, action rbac.Action, subresources ...rbac.Resource) bool {
|
|
|
|
var hasPermission bool
|
|
|
|
|
|
|
|
switch label.Scope {
|
|
|
|
case common.LabelScopeGlobal:
|
|
|
|
hasPermission = l.SecurityCtx.IsSysAdmin()
|
|
|
|
case common.LabelScopeProject:
|
|
|
|
if len(subresources) == 0 {
|
|
|
|
subresources = append(subresources, rbac.ResourceLabel)
|
|
|
|
}
|
|
|
|
resource := rbac.NewProjectNamespace(label.ProjectID).Resource(subresources...)
|
|
|
|
hasPermission = l.SecurityCtx.Can(action, resource)
|
|
|
|
}
|
|
|
|
|
|
|
|
if !hasPermission {
|
|
|
|
if !l.SecurityCtx.IsAuthenticated() {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendUnAuthorizedError(errors.New("UnAuthorized"))
|
2019-02-01 11:55:06 +01:00
|
|
|
} else {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendForbiddenError(errors.New(l.SecurityCtx.GetUsername()))
|
2018-03-07 06:20:28 +01:00
|
|
|
}
|
2019-02-01 11:55:06 +01:00
|
|
|
return false
|
2018-03-07 06:20:28 +01:00
|
|
|
}
|
2019-02-01 11:55:06 +01:00
|
|
|
|
|
|
|
return true
|
2018-03-07 06:20:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Post creates a label
|
|
|
|
func (l *LabelAPI) Post() {
|
|
|
|
label := &models.Label{}
|
2019-04-17 10:43:06 +02:00
|
|
|
isValid, err := l.DecodeJSONReqAndValidate(label)
|
|
|
|
if !isValid {
|
|
|
|
l.SendBadRequestError(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-03-07 06:20:28 +01:00
|
|
|
label.Level = common.LabelLevelUser
|
|
|
|
|
|
|
|
switch label.Scope {
|
|
|
|
case common.LabelScopeGlobal:
|
|
|
|
label.ProjectID = 0
|
|
|
|
case common.LabelScopeProject:
|
|
|
|
exist, err := l.ProjectMgr.Exists(label.ProjectID)
|
|
|
|
if err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to check the existence of project %d: %v",
|
2018-03-07 06:20:28 +01:00
|
|
|
label.ProjectID, err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if !exist {
|
2019-05-10 04:35:25 +02:00
|
|
|
l.SendBadRequestError(fmt.Errorf("project %d not found", label.ProjectID))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
2019-02-01 11:55:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if !l.requireAccess(label, rbac.ActionCreate) {
|
|
|
|
return
|
2018-03-07 06:20:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
labels, err := dao.ListLabels(&models.LabelQuery{
|
|
|
|
Name: label.Name,
|
|
|
|
Level: label.Level,
|
|
|
|
Scope: label.Scope,
|
|
|
|
ProjectID: label.ProjectID,
|
|
|
|
})
|
|
|
|
if err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to list labels: %v", err))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(labels) > 0 {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendConflictError(errors.New("conflict label"))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
id, err := dao.AddLabel(label)
|
|
|
|
if err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to create label: %v", err))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
l.Redirect(http.StatusCreated, strconv.FormatInt(id, 10))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the label specified by ID
|
|
|
|
func (l *LabelAPI) Get() {
|
|
|
|
id, err := l.GetInt64FromPath(":id")
|
|
|
|
if err != nil || id <= 0 {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendBadRequestError(fmt.Errorf("invalid label ID: %s", l.GetStringFromPath(":id")))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
label, err := dao.GetLabel(id)
|
|
|
|
if err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to get label %d: %v", id, err))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-07 10:05:50 +02:00
|
|
|
if label == nil || label.Deleted {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendNotFoundError(fmt.Errorf("label %d not found", id))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-02-01 11:55:06 +01:00
|
|
|
if !l.requireAccess(label, rbac.ActionRead) {
|
|
|
|
return
|
2018-03-07 06:20:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
l.Data["json"] = label
|
|
|
|
l.ServeJSON()
|
|
|
|
}
|
|
|
|
|
|
|
|
// List labels according to the query strings
|
|
|
|
func (l *LabelAPI) List() {
|
|
|
|
query := &models.LabelQuery{
|
2018-06-01 01:38:21 +02:00
|
|
|
Name: l.GetString("name"),
|
|
|
|
FuzzyMatchName: true,
|
|
|
|
Level: common.LabelLevelUser,
|
2018-03-07 06:20:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
scope := l.GetString("scope")
|
|
|
|
if scope != common.LabelScopeGlobal && scope != common.LabelScopeProject {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendBadRequestError(fmt.Errorf("invalid scope: %s", scope))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
query.Scope = scope
|
|
|
|
|
|
|
|
if scope == common.LabelScopeProject {
|
|
|
|
projectIDStr := l.GetString("project_id")
|
|
|
|
if len(projectIDStr) == 0 {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendBadRequestError(errors.New("project_id is required"))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
projectID, err := strconv.ParseInt(projectIDStr, 10, 64)
|
|
|
|
if err != nil || projectID <= 0 {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendBadRequestError(fmt.Errorf("invalid project_id: %s", projectIDStr))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-02-01 11:55:06 +01:00
|
|
|
resource := rbac.NewProjectNamespace(projectID).Resource(rbac.ResourceLabel)
|
|
|
|
if !l.SecurityCtx.Can(rbac.ActionList, resource) {
|
2018-03-07 06:20:28 +01:00
|
|
|
if !l.SecurityCtx.IsAuthenticated() {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendUnAuthorizedError(errors.New("UnAuthorized"))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendForbiddenError(errors.New(l.SecurityCtx.GetUsername()))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
query.ProjectID = projectID
|
|
|
|
}
|
|
|
|
|
|
|
|
total, err := dao.GetTotalOfLabels(query)
|
|
|
|
if err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to get total count of labels: %v", err))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-04-17 10:43:06 +02:00
|
|
|
query.Page, query.Size, err = l.GetPaginationParams()
|
|
|
|
if err != nil {
|
|
|
|
l.SendBadRequestError(err)
|
|
|
|
return
|
|
|
|
}
|
2018-03-07 06:20:28 +01:00
|
|
|
|
|
|
|
labels, err := dao.ListLabels(query)
|
|
|
|
if err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to list labels: %v", err))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
l.SetPaginationHeader(total, query.Page, query.Size)
|
|
|
|
l.Data["json"] = labels
|
|
|
|
l.ServeJSON()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Put updates the label
|
|
|
|
func (l *LabelAPI) Put() {
|
2019-02-01 11:55:06 +01:00
|
|
|
if !l.requireAccess(l.label, rbac.ActionUpdate) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-03-07 06:20:28 +01:00
|
|
|
label := &models.Label{}
|
2019-04-17 10:43:06 +02:00
|
|
|
if err := l.DecodeJSONReq(label); err != nil {
|
|
|
|
l.SendBadRequestError(err)
|
|
|
|
return
|
|
|
|
}
|
2018-03-07 06:20:28 +01:00
|
|
|
|
|
|
|
oldName := l.label.Name
|
|
|
|
|
|
|
|
// only name, description and color can be changed
|
|
|
|
l.label.Name = label.Name
|
|
|
|
l.label.Description = label.Description
|
|
|
|
l.label.Color = label.Color
|
|
|
|
|
2019-04-17 10:43:06 +02:00
|
|
|
isValidate, err := l.Validate(l.label)
|
|
|
|
if !isValidate {
|
|
|
|
if err != nil {
|
|
|
|
l.SendBadRequestError(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2018-03-07 06:20:28 +01:00
|
|
|
|
|
|
|
if l.label.Name != oldName {
|
|
|
|
labels, err := dao.ListLabels(&models.LabelQuery{
|
|
|
|
Name: l.label.Name,
|
|
|
|
Level: l.label.Level,
|
|
|
|
Scope: l.label.Scope,
|
|
|
|
ProjectID: l.label.ProjectID,
|
|
|
|
})
|
|
|
|
if err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to list labels: %v", err))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if len(labels) > 0 {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendConflictError(errors.New("conflict label"))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := dao.UpdateLabel(l.label); err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to update label %d: %v", l.label.ID, err))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete the label
|
|
|
|
func (l *LabelAPI) Delete() {
|
2019-02-01 11:55:06 +01:00
|
|
|
if !l.requireAccess(l.label, rbac.ActionDelete) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-03-07 06:20:28 +01:00
|
|
|
id := l.label.ID
|
2018-03-23 19:22:51 +01:00
|
|
|
if err := dao.DeleteResourceLabelByLabel(id); err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to delete resource label mappings of label %d: %v", id, err))
|
2018-03-23 19:22:51 +01:00
|
|
|
return
|
|
|
|
}
|
2018-03-07 06:20:28 +01:00
|
|
|
if err := dao.DeleteLabel(id); err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to delete label %d: %v", id, err))
|
2018-03-07 06:20:28 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2018-06-13 10:49:43 +02:00
|
|
|
|
|
|
|
// ListResources lists the resources that the label is referenced by
|
|
|
|
func (l *LabelAPI) ListResources() {
|
|
|
|
id, err := l.GetInt64FromPath(":id")
|
|
|
|
if err != nil || id <= 0 {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendBadRequestError(errors.New("invalid label ID"))
|
2018-06-13 10:49:43 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
label, err := dao.GetLabel(id)
|
|
|
|
if err != nil {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendInternalServerError(fmt.Errorf("failed to get label %d: %v", id, err))
|
2018-06-13 10:49:43 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if label == nil || label.Deleted {
|
2019-04-17 10:43:06 +02:00
|
|
|
l.SendNotFoundError(fmt.Errorf("label %d not found", id))
|
2018-06-13 10:49:43 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-02-01 11:55:06 +01:00
|
|
|
if !l.requireAccess(label, rbac.ActionList, rbac.ResourceLabelResource) {
|
2018-06-13 10:49:43 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-04-04 13:08:57 +02:00
|
|
|
/*
|
|
|
|
result, err := core.GlobalController.GetPolicies(rep_models.QueryParameter{})
|
|
|
|
if err != nil {
|
|
|
|
l.HandleInternalServerError(fmt.Sprintf("failed to get policies: %v", err))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
policies := []*rep_models.ReplicationPolicy{}
|
|
|
|
if result != nil {
|
|
|
|
for _, policy := range result.Policies {
|
|
|
|
for _, filter := range policy.Filters {
|
|
|
|
if filter.Kind != replication.FilterItemKindLabel {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if filter.Value.(int64) == label.ID {
|
|
|
|
policies = append(policies, policy)
|
|
|
|
}
|
2018-06-13 10:49:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-04-04 13:08:57 +02:00
|
|
|
*/
|
2018-06-13 10:49:43 +02:00
|
|
|
resources := map[string]interface{}{}
|
2019-04-04 13:08:57 +02:00
|
|
|
resources["replication_policies"] = nil
|
2018-06-13 10:49:43 +02:00
|
|
|
l.Data["json"] = resources
|
|
|
|
l.ServeJSON()
|
|
|
|
}
|