mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-22 23:51:27 +01:00
Merge pull request #6756 from wy65701436/robot-api
Add API implementation of robot account
This commit is contained in:
commit
4b7997250a
@ -15,6 +15,7 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -32,6 +33,9 @@ const (
|
||||
ClairDBAlias = "clair-db"
|
||||
)
|
||||
|
||||
// ErrDupRows is returned by DAO when inserting failed with error "duplicate key value violates unique constraint"
|
||||
var ErrDupRows = errors.New("sql: duplicate row in DB")
|
||||
|
||||
// Database is an interface of different databases
|
||||
type Database interface {
|
||||
// Name returns the name of database
|
||||
|
@ -17,6 +17,7 @@ package dao
|
||||
import (
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -25,7 +26,14 @@ func AddRobot(robot *models.Robot) (int64, error) {
|
||||
now := time.Now()
|
||||
robot.CreationTime = now
|
||||
robot.UpdateTime = now
|
||||
return GetOrmer().Insert(robot)
|
||||
id, err := GetOrmer().Insert(robot)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "duplicate key value violates unique constraint") {
|
||||
return 0, ErrDupRows
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// GetRobotByID ...
|
||||
@ -79,6 +87,11 @@ func getRobotQuerySetter(query *models.RobotQuery) orm.QuerySeter {
|
||||
return qs
|
||||
}
|
||||
|
||||
// CountRobot ...
|
||||
func CountRobot(query *models.RobotQuery) (int64, error) {
|
||||
return getRobotQuerySetter(query).Count()
|
||||
}
|
||||
|
||||
// UpdateRobot ...
|
||||
func UpdateRobot(robot *models.Robot) error {
|
||||
robot.UpdateTime = time.Now()
|
||||
|
@ -15,6 +15,7 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego/validation"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -42,7 +43,26 @@ type RobotQuery struct {
|
||||
Pagination
|
||||
}
|
||||
|
||||
// RobotReq ...
|
||||
type RobotReq struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Disabled bool `json:"disabled"`
|
||||
Access []*ResourceActions `json:"access"`
|
||||
}
|
||||
|
||||
// Valid put request validation
|
||||
func (rq *RobotReq) Valid(v *validation.Validation) {
|
||||
// ToDo: add validation for access info.
|
||||
}
|
||||
|
||||
// RobotRep ...
|
||||
type RobotRep struct {
|
||||
Name string
|
||||
Token string
|
||||
}
|
||||
|
||||
// TableName ...
|
||||
func (u *Robot) TableName() string {
|
||||
func (r *Robot) TableName() string {
|
||||
return RobotTable
|
||||
}
|
||||
|
@ -20,3 +20,9 @@ type Token struct {
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
IssuedAt string `json:"issued_at"`
|
||||
}
|
||||
|
||||
// ResourceActions ...
|
||||
type ResourceActions struct {
|
||||
Name string `json:"name"`
|
||||
Actions []string `json:"actions"`
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
nonSysAdminID, projAdminID, projDeveloperID, projGuestID int64
|
||||
projAdminPMID, projDeveloperPMID, projGuestPMID int
|
||||
nonSysAdminID, projAdminID, projDeveloperID, projGuestID, projAdminRobotID int64
|
||||
projAdminPMID, projDeveloperPMID, projGuestPMID, projAdminRobotPMID int
|
||||
// The following users/credentials are registered and assigned roles at the beginning of
|
||||
// running testing and cleaned up at the end.
|
||||
// Do not try to change the system and project roles that the users have during
|
||||
@ -67,6 +67,10 @@ var (
|
||||
Name: "proj_guest",
|
||||
Passwd: "Harbor12345",
|
||||
}
|
||||
projAdmin4Robot = &usrInfo{
|
||||
Name: "proj_admin_robot",
|
||||
Passwd: "Harbor12345",
|
||||
}
|
||||
)
|
||||
|
||||
type testingRequest struct {
|
||||
@ -240,6 +244,25 @@ func prepare() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// register projAdminRobots and assign project admin role
|
||||
projAdminRobotID, err = dao.Register(models.User{
|
||||
Username: projAdmin4Robot.Name,
|
||||
Password: projAdmin4Robot.Passwd,
|
||||
Email: projAdmin4Robot.Name + "@test.com",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if projAdminRobotPMID, err = project.AddProjectMember(models.Member{
|
||||
ProjectID: 1,
|
||||
Role: models.PROJECTADMIN,
|
||||
EntityID: int(projAdminRobotID),
|
||||
EntityType: common.UserMember,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// register projDeveloper and assign project developer role
|
||||
projDeveloperID, err = dao.Register(models.User{
|
||||
Username: projDeveloper.Name,
|
||||
|
@ -153,6 +153,9 @@ func init() {
|
||||
beego.Router("/api/system/gc/:id([0-9]+)/log", &GCAPI{}, "get:GetLog")
|
||||
beego.Router("/api/system/gc/schedule", &GCAPI{}, "get:Get;put:Put;post:Post")
|
||||
|
||||
beego.Router("/api/projects/:pid([0-9]+)/robots/", &RobotAPI{}, "post:Post;get:List")
|
||||
beego.Router("/api/projects/:pid([0-9]+)/robots/:id([0-9]+)", &RobotAPI{}, "get:Get;put:Put;delete:Delete")
|
||||
|
||||
// Charts are controlled under projects
|
||||
chartRepositoryAPIType := &ChartRepositoryAPI{}
|
||||
beego.Router("/api/chartrepo/health", chartRepositoryAPIType, "get:GetHealthStatus")
|
||||
|
197
src/core/api/robot.go
Normal file
197
src/core/api/robot.go
Normal file
@ -0,0 +1,197 @@
|
||||
// Copyright 2018 Project Harbor Authors
|
||||
//
|
||||
// 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 (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// User this prefix to distinguish harbor user,
|
||||
// The prefix contains a specific character($), so it cannot be registered as a harbor user.
|
||||
const robotPrefix = "robot$"
|
||||
|
||||
// RobotAPI ...
|
||||
type RobotAPI struct {
|
||||
BaseController
|
||||
project *models.Project
|
||||
robot *models.Robot
|
||||
}
|
||||
|
||||
// Prepare ...
|
||||
func (r *RobotAPI) Prepare() {
|
||||
r.BaseController.Prepare()
|
||||
method := r.Ctx.Request.Method
|
||||
|
||||
if !r.SecurityCtx.IsAuthenticated() {
|
||||
r.HandleUnauthorized()
|
||||
return
|
||||
}
|
||||
|
||||
pid, err := r.GetInt64FromPath(":pid")
|
||||
if err != nil || pid <= 0 {
|
||||
var errMsg string
|
||||
if err != nil {
|
||||
errMsg = "failed to get project ID " + err.Error()
|
||||
} else {
|
||||
errMsg = "invalid project ID: " + fmt.Sprintf("%d", pid)
|
||||
}
|
||||
r.HandleBadRequest(errMsg)
|
||||
return
|
||||
}
|
||||
project, err := r.ProjectMgr.Get(pid)
|
||||
if err != nil {
|
||||
r.ParseAndHandleError(fmt.Sprintf("failed to get project %d", pid), err)
|
||||
return
|
||||
}
|
||||
if project == nil {
|
||||
r.HandleNotFound(fmt.Sprintf("project %d not found", pid))
|
||||
return
|
||||
}
|
||||
r.project = project
|
||||
|
||||
if method == http.MethodPut || method == http.MethodDelete {
|
||||
id, err := r.GetInt64FromPath(":id")
|
||||
if err != nil || id <= 0 {
|
||||
r.HandleBadRequest("invalid robot ID")
|
||||
return
|
||||
}
|
||||
|
||||
robot, err := dao.GetRobotByID(id)
|
||||
if err != nil {
|
||||
r.HandleInternalServerError(fmt.Sprintf("failed to get robot %d: %v", id, err))
|
||||
return
|
||||
}
|
||||
|
||||
if robot == nil {
|
||||
r.HandleNotFound(fmt.Sprintf("robot %d not found", id))
|
||||
return
|
||||
}
|
||||
|
||||
r.robot = robot
|
||||
}
|
||||
|
||||
if !(r.Ctx.Input.IsGet() && r.SecurityCtx.HasReadPerm(pid) ||
|
||||
r.SecurityCtx.HasAllPerm(pid)) {
|
||||
r.HandleForbidden(r.SecurityCtx.GetUsername())
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Post ...
|
||||
func (r *RobotAPI) Post() {
|
||||
var robotReq models.RobotReq
|
||||
r.DecodeJSONReq(&robotReq)
|
||||
|
||||
createdName := robotPrefix + robotReq.Name
|
||||
|
||||
robot := models.Robot{
|
||||
Name: createdName,
|
||||
Description: robotReq.Description,
|
||||
ProjectID: r.project.ProjectID,
|
||||
// TODO: use token service to generate token per access information
|
||||
Token: "this is a placeholder",
|
||||
}
|
||||
|
||||
id, err := dao.AddRobot(&robot)
|
||||
if err != nil {
|
||||
if err == dao.ErrDupRows {
|
||||
r.HandleConflict()
|
||||
return
|
||||
}
|
||||
r.HandleInternalServerError(fmt.Sprintf("failed to create robot account: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
robotRep := models.RobotRep{
|
||||
Name: robot.Name,
|
||||
Token: robot.Token,
|
||||
}
|
||||
|
||||
r.Redirect(http.StatusCreated, strconv.FormatInt(id, 10))
|
||||
r.Data["json"] = robotRep
|
||||
r.ServeJSON()
|
||||
}
|
||||
|
||||
// List list all the robots of a project
|
||||
func (r *RobotAPI) List() {
|
||||
query := models.RobotQuery{
|
||||
ProjectID: r.project.ProjectID,
|
||||
}
|
||||
|
||||
count, err := dao.CountRobot(&query)
|
||||
if err != nil {
|
||||
r.HandleInternalServerError(fmt.Sprintf("failed to list robots on project: %d, %v", r.project.ProjectID, err))
|
||||
return
|
||||
}
|
||||
query.Page, query.Size = r.GetPaginationParams()
|
||||
|
||||
robots, err := dao.ListRobots(&query)
|
||||
if err != nil {
|
||||
r.HandleInternalServerError(fmt.Sprintf("failed to get robots %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
r.SetPaginationHeader(count, query.Page, query.Size)
|
||||
r.Data["json"] = robots
|
||||
r.ServeJSON()
|
||||
}
|
||||
|
||||
// Get get robot by id
|
||||
func (r *RobotAPI) Get() {
|
||||
id, err := r.GetInt64FromPath(":id")
|
||||
if err != nil || id <= 0 {
|
||||
r.HandleBadRequest(fmt.Sprintf("invalid robot ID: %s", r.GetStringFromPath(":id")))
|
||||
return
|
||||
}
|
||||
|
||||
robot, err := dao.GetRobotByID(id)
|
||||
if err != nil {
|
||||
r.HandleInternalServerError(fmt.Sprintf("failed to get robot %d: %v", id, err))
|
||||
return
|
||||
}
|
||||
if robot == nil {
|
||||
r.HandleNotFound(fmt.Sprintf("robot %d not found", id))
|
||||
return
|
||||
}
|
||||
|
||||
r.Data["json"] = robot
|
||||
r.ServeJSON()
|
||||
}
|
||||
|
||||
// Put disable or enable a robot account
|
||||
func (r *RobotAPI) Put() {
|
||||
var robotReq models.RobotReq
|
||||
r.DecodeJSONReqAndValidate(&robotReq)
|
||||
r.robot.Disabled = robotReq.Disabled
|
||||
|
||||
if err := dao.UpdateRobot(r.robot); err != nil {
|
||||
r.HandleInternalServerError(fmt.Sprintf("failed to update robot %d: %v", r.robot.ID, err))
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Delete delete robot by id
|
||||
func (r *RobotAPI) Delete() {
|
||||
if err := dao.DeleteRobot(r.robot.ID); err != nil {
|
||||
r.HandleInternalServerError(fmt.Sprintf("failed to delete robot %d: %v", r.robot.ID, err))
|
||||
return
|
||||
}
|
||||
}
|
314
src/core/api/robot_test.go
Normal file
314
src/core/api/robot_test.go
Normal file
@ -0,0 +1,314 @@
|
||||
// Copyright 2018 Project Harbor Authors
|
||||
//
|
||||
// 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 (
|
||||
"fmt"
|
||||
"github.com/goharbor/harbor/src/common/models"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
robotPath = "/api/projects/1/robots"
|
||||
robotID int64
|
||||
)
|
||||
|
||||
func TestRobotAPIPost(t *testing.T) {
|
||||
cases := []*codeCheckingCase{
|
||||
// 401
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: robotPath,
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
|
||||
// 403
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: robotPath,
|
||||
bodyJSON: &models.Robot{},
|
||||
credential: nonSysAdmin,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
// 201
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: robotPath,
|
||||
bodyJSON: &models.Robot{
|
||||
Name: "test",
|
||||
Description: "test desc",
|
||||
},
|
||||
credential: projAdmin4Robot,
|
||||
},
|
||||
code: http.StatusCreated,
|
||||
},
|
||||
// 403 -- developer
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: robotPath,
|
||||
bodyJSON: &models.Robot{
|
||||
Name: "test2",
|
||||
Description: "test2 desc",
|
||||
},
|
||||
credential: projDeveloper,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
|
||||
// 409
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPost,
|
||||
url: robotPath,
|
||||
bodyJSON: &models.Robot{
|
||||
Name: "test",
|
||||
Description: "test desc",
|
||||
ProjectID: 1,
|
||||
},
|
||||
credential: projAdmin4Robot,
|
||||
},
|
||||
code: http.StatusConflict,
|
||||
},
|
||||
}
|
||||
runCodeCheckingCases(t, cases...)
|
||||
}
|
||||
|
||||
func TestRobotAPIGet(t *testing.T) {
|
||||
cases := []*codeCheckingCase{
|
||||
// 400
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 0),
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
|
||||
// 404
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 1000),
|
||||
credential: projDeveloper,
|
||||
},
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
|
||||
// 200
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 1),
|
||||
credential: projDeveloper,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
|
||||
// 200
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 1),
|
||||
credential: projAdmin4Robot,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
}
|
||||
runCodeCheckingCases(t, cases...)
|
||||
}
|
||||
|
||||
func TestRobotAPIList(t *testing.T) {
|
||||
cases := []*codeCheckingCase{
|
||||
// 401
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: robotPath,
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
|
||||
// 400
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: "/api/projects/0/robots",
|
||||
credential: projAdmin4Robot,
|
||||
},
|
||||
code: http.StatusBadRequest,
|
||||
},
|
||||
|
||||
// 200
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: robotPath,
|
||||
credential: projDeveloper,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
|
||||
// 200
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodGet,
|
||||
url: robotPath,
|
||||
credential: projAdmin4Robot,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
}
|
||||
runCodeCheckingCases(t, cases...)
|
||||
}
|
||||
|
||||
func TestRobotAPIPut(t *testing.T) {
|
||||
cases := []*codeCheckingCase{
|
||||
// 401
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 1),
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
|
||||
// 400
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 0),
|
||||
credential: projAdmin4Robot,
|
||||
},
|
||||
code: http.StatusBadRequest,
|
||||
},
|
||||
|
||||
// 404
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 10000),
|
||||
credential: projAdmin4Robot,
|
||||
},
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
|
||||
// 403 non-member user
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 1),
|
||||
credential: nonSysAdmin,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
|
||||
// 403 developer
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 1),
|
||||
credential: projDeveloper,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
|
||||
// 200
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodPut,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 1),
|
||||
bodyJSON: &models.Robot{
|
||||
Disabled: true,
|
||||
},
|
||||
credential: projAdmin4Robot,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
runCodeCheckingCases(t, cases...)
|
||||
}
|
||||
|
||||
func TestRobotAPIDelete(t *testing.T) {
|
||||
cases := []*codeCheckingCase{
|
||||
// 401
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodDelete,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 1),
|
||||
},
|
||||
code: http.StatusUnauthorized,
|
||||
},
|
||||
|
||||
// 400
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodDelete,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 0),
|
||||
credential: projAdmin4Robot,
|
||||
},
|
||||
code: http.StatusBadRequest,
|
||||
},
|
||||
|
||||
// 404
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodDelete,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 10000),
|
||||
credential: projAdmin4Robot,
|
||||
},
|
||||
code: http.StatusNotFound,
|
||||
},
|
||||
|
||||
// 403 non-member user
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodDelete,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 1),
|
||||
credential: nonSysAdmin,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
|
||||
// 403 developer
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodDelete,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 1),
|
||||
credential: projDeveloper,
|
||||
},
|
||||
code: http.StatusForbidden,
|
||||
},
|
||||
|
||||
// 200
|
||||
{
|
||||
request: &testingRequest{
|
||||
method: http.MethodDelete,
|
||||
url: fmt.Sprintf("%s/%d", robotPath, 1),
|
||||
credential: projAdmin4Robot,
|
||||
},
|
||||
code: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
runCodeCheckingCases(t, cases...)
|
||||
}
|
@ -65,6 +65,10 @@ func initRouters() {
|
||||
beego.Router("/api/projects/:id([0-9]+)/metadatas/?:name", &api.MetadataAPI{}, "get:Get")
|
||||
beego.Router("/api/projects/:id([0-9]+)/metadatas/", &api.MetadataAPI{}, "post:Post")
|
||||
beego.Router("/api/projects/:id([0-9]+)/metadatas/:name", &api.MetadataAPI{}, "put:Put;delete:Delete")
|
||||
|
||||
beego.Router("/api/projects/:pid([0-9]+)/robots", &api.RobotAPI{}, "post:Post;get:List")
|
||||
beego.Router("/api/projects/:pid([0-9]+)/robots/:id([0-9]+)", &api.RobotAPI{}, "get:Get;put:Put;delete:Delete")
|
||||
|
||||
beego.Router("/api/repositories", &api.RepositoryAPI{}, "get:Get")
|
||||
beego.Router("/api/repositories/scanAll", &api.RepositoryAPI{}, "post:ScanAll")
|
||||
beego.Router("/api/repositories/*", &api.RepositoryAPI{}, "delete:Delete;put:Put")
|
||||
|
Loading…
Reference in New Issue
Block a user