mirror of
https://github.com/goharbor/harbor.git
synced 2025-02-02 13:01:23 +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
|
package dao
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -32,6 +33,9 @@ const (
|
|||||||
ClairDBAlias = "clair-db"
|
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
|
// Database is an interface of different databases
|
||||||
type Database interface {
|
type Database interface {
|
||||||
// Name returns the name of database
|
// Name returns the name of database
|
||||||
|
@ -17,6 +17,7 @@ package dao
|
|||||||
import (
|
import (
|
||||||
"github.com/astaxie/beego/orm"
|
"github.com/astaxie/beego/orm"
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,7 +26,14 @@ func AddRobot(robot *models.Robot) (int64, error) {
|
|||||||
now := time.Now()
|
now := time.Now()
|
||||||
robot.CreationTime = now
|
robot.CreationTime = now
|
||||||
robot.UpdateTime = 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 ...
|
// GetRobotByID ...
|
||||||
@ -79,6 +87,11 @@ func getRobotQuerySetter(query *models.RobotQuery) orm.QuerySeter {
|
|||||||
return qs
|
return qs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CountRobot ...
|
||||||
|
func CountRobot(query *models.RobotQuery) (int64, error) {
|
||||||
|
return getRobotQuerySetter(query).Count()
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateRobot ...
|
// UpdateRobot ...
|
||||||
func UpdateRobot(robot *models.Robot) error {
|
func UpdateRobot(robot *models.Robot) error {
|
||||||
robot.UpdateTime = time.Now()
|
robot.UpdateTime = time.Now()
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/astaxie/beego/validation"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,7 +43,26 @@ type RobotQuery struct {
|
|||||||
Pagination
|
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 ...
|
// TableName ...
|
||||||
func (u *Robot) TableName() string {
|
func (r *Robot) TableName() string {
|
||||||
return RobotTable
|
return RobotTable
|
||||||
}
|
}
|
||||||
|
@ -20,3 +20,9 @@ type Token struct {
|
|||||||
ExpiresIn int `json:"expires_in"`
|
ExpiresIn int `json:"expires_in"`
|
||||||
IssuedAt string `json:"issued_at"`
|
IssuedAt string `json:"issued_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResourceActions ...
|
||||||
|
type ResourceActions struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Actions []string `json:"actions"`
|
||||||
|
}
|
||||||
|
@ -40,8 +40,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
nonSysAdminID, projAdminID, projDeveloperID, projGuestID int64
|
nonSysAdminID, projAdminID, projDeveloperID, projGuestID, projAdminRobotID int64
|
||||||
projAdminPMID, projDeveloperPMID, projGuestPMID int
|
projAdminPMID, projDeveloperPMID, projGuestPMID, projAdminRobotPMID int
|
||||||
// The following users/credentials are registered and assigned roles at the beginning of
|
// The following users/credentials are registered and assigned roles at the beginning of
|
||||||
// running testing and cleaned up at the end.
|
// running testing and cleaned up at the end.
|
||||||
// Do not try to change the system and project roles that the users have during
|
// Do not try to change the system and project roles that the users have during
|
||||||
@ -67,6 +67,10 @@ var (
|
|||||||
Name: "proj_guest",
|
Name: "proj_guest",
|
||||||
Passwd: "Harbor12345",
|
Passwd: "Harbor12345",
|
||||||
}
|
}
|
||||||
|
projAdmin4Robot = &usrInfo{
|
||||||
|
Name: "proj_admin_robot",
|
||||||
|
Passwd: "Harbor12345",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type testingRequest struct {
|
type testingRequest struct {
|
||||||
@ -240,6 +244,25 @@ func prepare() error {
|
|||||||
return err
|
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
|
// register projDeveloper and assign project developer role
|
||||||
projDeveloperID, err = dao.Register(models.User{
|
projDeveloperID, err = dao.Register(models.User{
|
||||||
Username: projDeveloper.Name,
|
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/:id([0-9]+)/log", &GCAPI{}, "get:GetLog")
|
||||||
beego.Router("/api/system/gc/schedule", &GCAPI{}, "get:Get;put:Put;post:Post")
|
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
|
// Charts are controlled under projects
|
||||||
chartRepositoryAPIType := &ChartRepositoryAPI{}
|
chartRepositoryAPIType := &ChartRepositoryAPI{}
|
||||||
beego.Router("/api/chartrepo/health", chartRepositoryAPIType, "get:GetHealthStatus")
|
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/?: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/", &api.MetadataAPI{}, "post:Post")
|
||||||
beego.Router("/api/projects/:id([0-9]+)/metadatas/:name", &api.MetadataAPI{}, "put:Put;delete:Delete")
|
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", &api.RepositoryAPI{}, "get:Get")
|
||||||
beego.Router("/api/repositories/scanAll", &api.RepositoryAPI{}, "post:ScanAll")
|
beego.Router("/api/repositories/scanAll", &api.RepositoryAPI{}, "post:ScanAll")
|
||||||
beego.Router("/api/repositories/*", &api.RepositoryAPI{}, "delete:Delete;put:Put")
|
beego.Router("/api/repositories/*", &api.RepositoryAPI{}, "delete:Delete;put:Put")
|
||||||
|
Loading…
Reference in New Issue
Block a user