diff --git a/constant/const.go b/constant/const.go
index 5e6e70cd7feb4fd5b20b80cfdb2cbd75f028ea78..7ecd791f6d96e12232192b26ef28ad678a3eaa0f 100644
--- a/constant/const.go
+++ b/constant/const.go
@@ -20,14 +20,11 @@ package constant
const (
SystemGroup = "system"
SystemAdminRole = "admin"
+ DevAdminRole = "devManager"
SystemMemberRole = "developer"
SystemAdminUser = "admin"
AdminDefaultPassword = "123456"
- // SysDevManager = "devManager"
- // TODO: change to sys devmanger
- CompanyAdminRole = "devManager"
-
StepBuild = "build"
StepSubTaskCheckout = "checkout"
diff --git a/controllers/role.go b/controllers/role.go
index 38ba48a74421eb0973db654e3c2b5cbe6300387d..2035650baffcb4a9d2539d952afb0dbd85c53eff 100644
--- a/controllers/role.go
+++ b/controllers/role.go
@@ -28,11 +28,7 @@ type RoleController struct {
// RoleList ..
func (r *RoleController) RoleList() {
- groupName := r.GetStringFromPath(":group")
- if groupName == "" {
- groupName = "system"
- }
- rsp, err := dao.GroupRoleList(groupName)
+ rsp, err := dao.GroupRoleList("system")
if err != nil {
r.HandleInternalServerError(err.Error())
log.Log.Error("Get role list error: %s", err.Error())
@@ -43,10 +39,9 @@ func (r *RoleController) RoleList() {
}
func (r *RoleController) GetRole() {
- groupName := r.GetStringFromPath(":group")
roleName := r.GetStringFromPath(":role")
- rsp, err := dao.GetGroupRoleByName(groupName, roleName)
+ rsp, err := dao.GetGroupRoleByName("system", roleName)
if err != nil {
r.HandleInternalServerError(err.Error())
log.Log.Error("Get role error: %s", err.Error())
@@ -80,11 +75,10 @@ func (r *RoleController) CreateRole() {
}
func (r *RoleController) UpdateRole() {
- groupName := r.GetStringFromPath(":group")
roleName := r.GetStringFromPath(":role")
var req models.GroupRoleReq
r.DecodeJSONReq(&req)
- req.Group = groupName
+ req.Group = "system"
req.Role = roleName
if err := req.Verify(); err != nil {
@@ -104,10 +98,8 @@ func (r *RoleController) UpdateRole() {
}
func (r *RoleController) DeleteRole() {
- groupName := r.GetStringFromPath(":group")
roleName := r.GetStringFromPath(":role")
-
- if err := dao.DeleteGroupRole(groupName, roleName); err != nil {
+ if err := dao.DeleteGroupRole("system", roleName); err != nil {
r.HandleInternalServerError(err.Error())
log.Log.Error("Delete role error: %s", err.Error())
return
@@ -166,26 +158,40 @@ func (r *RoleController) RoleUnbundling() {
r.ServeJSON()
}
-func (r *RoleController) RolePolicyList() {
- // groupName := r.GetStringFromPath(":group")
- // roleName := r.GetStringFromPath(":role")
- // TODO: need change role resources list
- rsp := []string{}
+func (r *RoleController) RoleOperationList() {
+ roleName := r.GetStringFromPath(":role")
+ rolesOperations, err := dao.GetRoleOperationsByRoleName(roleName)
+ if err != nil {
+ r.HandleInternalServerError(err.Error())
+ log.Log.Error("get role operations by role name error: %s", err.Error())
+ return
+ }
+ resIDs := []int64{}
+ for _, item := range rolesOperations {
+ resIDs = append(resIDs, item.OperationID)
+ }
+ rsp, err := dao.GetResourceOperationByIDs(resIDs)
+ if err != nil {
+ r.HandleInternalServerError(err.Error())
+ log.Log.Error("get role operations by ids error: %s", err.Error())
+ return
+ }
+
r.Data["json"] = NewResult(true, rsp, "")
r.ServeJSON()
}
-func (r *RoleController) AddRolePolicy() {
- groupName := r.GetStringFromPath(":group")
+func (r *RoleController) AddRoleOperation() {
+
roleName := r.GetStringFromPath(":role")
var req models.GroupRolePolicyReq
r.DecodeJSONReq(&req)
- req.Group = groupName
+ req.Group = "system"
req.Role = roleName
if err := dao.AddRoleOperation(&req); err != nil {
r.HandleInternalServerError(err.Error())
- log.Log.Error("Add role policy error: %s", err.Error())
+ log.Log.Error("Add role operation error: %s", err.Error())
return
}
@@ -193,13 +199,12 @@ func (r *RoleController) AddRolePolicy() {
r.ServeJSON()
}
-func (r *RoleController) RemoveRolePolicy() {
- groupName := r.GetStringFromPath(":group")
+func (r *RoleController) RemoveRoleOperation() {
roleName := r.GetStringFromPath(":role")
- var req models.GroupRolePolicyReq
- r.DecodeJSONReq(&req)
- req.Group = groupName
+ operationID, _ := r.GetInt64FromPath(":operationID")
+ req := models.GroupRolePolicyReq{}
req.Role = roleName
+ req.Operations = []int64{operationID}
if err := dao.DeleteGroupRolePolicy(&req); err != nil {
r.HandleInternalServerError(err.Error())
diff --git a/dao/resource.go b/dao/resource.go
index 6f8dcc14a5c83e6c4e7e751cc4844fd034113c2d..fa42a2a9e703f43f2cf0e1eea762eedcaf33339a 100644
--- a/dao/resource.go
+++ b/dao/resource.go
@@ -94,10 +94,6 @@ func BatchCreateResourceType(req models.BatchResourceTypeReq) error {
if _, err := GetOrmer().Raw(sql, resourceType, resource.ResourceType.Description).Exec(); err != nil {
return err
}
- sql = `insert ignore into sys_resource_operation(resource_type,resource_operation,description) values(?,'*','所有操作')`
- if _, err := GetOrmer().Raw(sql, resourceType).Exec(); err != nil {
- return err
- }
if len(resource.ResourceOperations) > 0 {
values := ""
@@ -137,9 +133,7 @@ func CreateResourceType(resourceType, description string) (*models.ResourceType,
if _, err := GetOrmer().Raw(sql, resourceType, description).Exec(); err != nil {
return nil, err
}
- if err := AddResourceOperation(resourceType, "*", "所有操作"); err != nil {
- return nil, err
- }
+
res, err := GetResourceTypeDetail(resourceType, []string{}, []string{})
if err != nil {
return nil, err
@@ -194,6 +188,36 @@ func GetResourceOperation(resourceType, resourceOperation string) (*models.Resou
return &op, nil
}
+func GetResourceOperationByResourceTypes(resourceTypes []string) ([]*models.ResourceOperation, error) {
+ var resItems []*models.ResourceOperation
+ if _, err := GetOrmer().QueryTable("sys_resource_operation").
+ Filter("resource_type__in", resourceTypes).
+ All(&resItems); err != nil {
+ return nil, err
+ }
+ return resItems, nil
+}
+
+func GetResourceOperationByResourceOperations(resourceOperations []string) ([]*models.ResourceOperation, error) {
+ var resItems []*models.ResourceOperation
+ if _, err := GetOrmer().QueryTable("sys_resource_operation").
+ Filter("resource_operation__in", resourceOperations).
+ All(&resItems); err != nil {
+ return nil, err
+ }
+ return resItems, nil
+}
+
+func GetResourceOperationByIDs(resourceItemIDs []int64) ([]*models.ResourceOperation, error) {
+ var resItems []*models.ResourceOperation
+ if _, err := GetOrmer().QueryTable("sys_resource_operation").
+ Filter("id__in", resourceItemIDs).
+ All(&resItems); err != nil {
+ return nil, err
+ }
+ return resItems, nil
+}
+
func AddResourceOperation(resourceType, resourceOperation, description string) error {
sql := `insert into sys_resource_operation(resource_type,resource_operation,description) values(?,?,?)`
if _, err := GetOrmer().Raw(sql, resourceType, resourceOperation, description).Exec(); err != nil {
@@ -266,11 +290,7 @@ func GetUserConstraintByKey(user string, constraintKey []string) (map[string][]s
}
res := map[string][]string{}
for _, con := range constraints {
- if _, ok := res[con.Constraint]; ok {
- res[con.Constraint] = append(res[con.Constraint], con.Value)
- } else {
- res[con.Constraint] = []string{con.Value}
- }
+ res[con.Constraint] = append(res[con.Constraint], con.Value)
}
return res, nil
}
diff --git a/dao/resource_router.go b/dao/resource_router.go
index 1d7f8a237b1baa5fb542cf8d1a7f2897a421f920..95688fce2f36d6b19ec6db9763001eb7f5f588a6 100644
--- a/dao/resource_router.go
+++ b/dao/resource_router.go
@@ -21,6 +21,7 @@ import (
"strings"
"github.com/go-atomci/atomci/models"
+ "github.com/isbrick/tools"
)
func CreateGatewayRoute(router, method, backend, resourceType, resourceOperation string) error {
@@ -32,11 +33,15 @@ func CreateGatewayRoute(router, method, backend, resourceType, resourceOperation
}
// GetResourceRouterItems ..
-func GetResourceRouterItems(resourceOperations []string) ([]models.GatewayRouter, error) {
+func GetResourceRouterItems(resourceType string, resourceOperations []string) ([]models.GatewayRouter, error) {
routerItems := []models.GatewayRouter{}
query := GetOrmer().QueryTable("sys_resource_router")
if len(resourceOperations) > 0 {
- query = query.Filter("resource_operation__in", resourceOperations)
+ if tools.IsSliceContainsStr(resourceOperations, "*") {
+ query = query.Filter("resource_type", resourceType)
+ } else {
+ query = query.Filter("resource_operation__in", resourceOperations)
+ }
}
if _, err := query.All(&routerItems); err != nil {
return nil, err
diff --git a/dao/role.go b/dao/role.go
index d517f025c755cc08b4a7b6375a434ecb058b37b1..8ecdd60bdd4e8971e935e4e23af8c16adffc2b6e 100644
--- a/dao/role.go
+++ b/dao/role.go
@@ -50,6 +50,17 @@ func GetGroupRoleByName(group, role string) (*models.GroupRole, error) {
return &groupRole, nil
}
+func GetRoleOperationsByRoleName(role string) ([]*models.GroupRoleOperation, error) {
+ roleOperations := []*models.GroupRoleOperation{}
+ if _, err := GetOrmer().QueryTable("sys_group_role_operation").
+ Filter("group", "system").
+ Filter("role", role).
+ All(&roleOperations); err != nil {
+ return nil, err
+ }
+ return roleOperations, nil
+}
+
func CreateGroupRole(req *models.GroupRoleReq) (*models.GroupRole, error) {
role, _ := GetGroupRoleByName(req.Group, req.Role)
if role == nil {
@@ -70,12 +81,23 @@ func CreateGroupRole(req *models.GroupRoleReq) (*models.GroupRole, error) {
// TODO: generate casbin rules rely on req.Operations
log.Log.Debug("req operations length: %v", len(req.Operations))
- resourceRouterItems, err := GetResourceRouterItems(req.Operations)
+ resOperationItems, err := GetResourceOperationByIDs(req.Operations)
if err != nil {
- log.Log.Error("when create group role, get resource router items error: %s", err.Error())
+ log.Log.Error("when get resource operation by ids occur error: %s", err.Error())
return nil, err
}
+ resTypeOperationsMapping := orderByResourceType(resOperationItems)
+ resourceRouterItems := []models.GatewayRouter{}
+ for key, item := range resTypeOperationsMapping {
+ resRouterItems, err := GetResourceRouterItems(key, item)
+ if err != nil {
+ log.Log.Error("when create group role, get resource router items error: %s", err.Error())
+ continue
+ }
+ resourceRouterItems = append(resourceRouterItems, resRouterItems...)
+ }
+
if len(resourceRouterItems) > 0 {
casbinRules := generateCasbinRules(resourceRouterItems, req.Role)
e, err := mycasbin.NewCasbin()
@@ -171,14 +193,14 @@ func GroupRoleUnbundling(req *models.GroupRoleBundlingReq) error {
func AddRoleOperation(req *models.GroupRolePolicyReq) error {
if len(req.Operations) > 0 {
values := ""
- for index, policy := range req.Operations {
+ for index, operationID := range req.Operations {
if index == 0 {
- values = fmt.Sprintf("('%v','%v','%v')", req.Group, req.Role, policy)
+ values = fmt.Sprintf("('%v','%v',%v)", req.Group, req.Role, operationID)
} else {
- values = values + "," + fmt.Sprintf("('%v','%v','%v')", req.Group, req.Role, policy)
+ values = values + "," + fmt.Sprintf("('%v','%v',%v)", req.Group, req.Role, operationID)
}
}
- sql := `insert ignore into sys_group_role_operation(` + "`group`" + `,role,policy_name) values` + values
+ sql := `insert ignore into sys_group_role_operation(` + "`group`" + `,role, operation_id) values` + values
if _, err := GetOrmer().Raw(sql).Exec(); err != nil {
return err
}
@@ -196,10 +218,20 @@ func DeleteGroupRolePolicy(req *models.GroupRolePolicyReq) error {
values = values + "," + fmt.Sprintf("'%v'", police)
}
}
- sql := `delete from sys_group_role_operation where ` + "`group`" + `=? and role=? and policy_name in (` + values + `)`
- if _, err := GetOrmer().Raw(sql, req.Group, req.Role).Exec(); err != nil {
+ sql := `delete from sys_group_role_operation where ` + `role=? and operation_id in (` + values + `)`
+ if _, err := GetOrmer().Raw(sql, req.Role).Exec(); err != nil {
return err
}
+
+ // TODO: clean casbin item
}
return nil
}
+
+func orderByResourceType(res []*models.ResourceOperation) map[string][]string {
+ resMap := map[string][]string{}
+ for _, item := range res {
+ resMap[item.ResourceType] = append(resMap[item.ResourceType], item.ResourceOperation)
+ }
+ return resMap
+}
diff --git a/dao/user.go b/dao/user.go
index f2016860a2f3b44ee8d8f20b3b8433171c2122b1..57b02ff7e104b0414717f0bd5a4b3c54af79605e 100644
--- a/dao/user.go
+++ b/dao/user.go
@@ -99,7 +99,7 @@ func GetUserDetail(userName string) (*models.User, error) {
user.GroupAdmin = 1
break
}
- if role.Role == constant.CompanyAdminRole {
+ if role.Role == constant.DevAdminRole {
user.GroupAdmin = 1
}
}
diff --git a/deploy/release/sql/v1.2.2_00.sql b/deploy/release/sql/v1.2.2_00.sql
new file mode 100644
index 0000000000000000000000000000000000000000..a071300c7537ed6eb492d1c407d2309ebfaa32f6
--- /dev/null
+++ b/deploy/release/sql/v1.2.2_00.sql
@@ -0,0 +1,3 @@
+ALTER TABLE atomci.sys_group_role_operation DROP KEY `group`;
+
+ALTER TABLE atomci.sys_group_role_operation ADD CONSTRAINT roleOperation UNIQUE (role, operation_id);
\ No newline at end of file
diff --git a/go.mod b/go.mod
index ea139a9f4238eef4fcb7e909092d2d5b4f006e88..b119c8ba76c781477faad9f43625fc040bea6870 100644
--- a/go.mod
+++ b/go.mod
@@ -43,6 +43,7 @@ require (
github.com/google/go-cmp v0.5.5 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/gorilla/websocket v1.4.2
+ github.com/isbrick/tools v0.0.0-20211027093338-a3a0ded37175
github.com/kr/text v0.2.0 // indirect
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
diff --git a/go.sum b/go.sum
index 3561bb226647aba46962189da00e54c448ef326a..b0fea008f2fef5fcc74cf693698a46488c5330c2 100644
--- a/go.sum
+++ b/go.sum
@@ -416,6 +416,8 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/isbrick/http-client v0.0.0-20210321135403-0a5df00fdb84 h1:f+X6/PyYYWQx2LQEUwCEdZiLxYHrpc4b87KFBHrZBnE=
github.com/isbrick/http-client v0.0.0-20210321135403-0a5df00fdb84/go.mod h1:ILI7SGUToE8ebBaVw9+tdlWlj2naGFmnMU+FrQj+6ro=
+github.com/isbrick/tools v0.0.0-20211027093338-a3a0ded37175 h1:HnZgYkC7M0z/0Ll+qXQS2jizZgWjSkC90j6HDmr/SuM=
+github.com/isbrick/tools v0.0.0-20211027093338-a3a0ded37175/go.mod h1:3jxvSrtFqeDL15wHztv4lLjQqB1YiPU3jAewh3LwUW0=
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
diff --git a/initialize/init_system_user.go b/initialize/init_system_user.go
index 0be0ed60b24fce1083b46d119ff46d3d12bdaa62..3446920b155f01470a0cdd6eb8e147b540b973af 100644
--- a/initialize/init_system_user.go
+++ b/initialize/init_system_user.go
@@ -93,26 +93,83 @@ func initAdminUser() (int64, error) {
// 初始化系统角色和管理员用户
func initSystemRole() error {
+ adminResourceItem, err := dao.GetResourceOperation("*", "*")
+ if err != nil {
+ return err
+ }
+ memberResourceOperationIDs := []int64{}
+ devAdminResourceOperationIDs := []int64{}
+
+ devAdminResourceOperations, err := dao.GetResourceOperationByResourceTypes([]string{"pipeline", "project", "publish"})
+ if err != nil {
+ return err
+ }
+ for _, item := range devAdminResourceOperations {
+ devAdminResourceOperationIDs = append(devAdminResourceOperationIDs, item.ID)
+ }
+
+ sysMemberResourceOperations, err := dao.GetResourceOperationByResourceOperations([]string{
+ "ProjectList",
+ "CreateProject",
+ "UpdateProject",
+ "GetProject",
+ "CreateProjectApp",
+ "UpdateProjectApp",
+ "GetProjectApps",
+ "GetProjectApp",
+ "GetAppsByPagination",
+ "GetArrange",
+ "SetArrange",
+ "GetAppBranches",
+ "SyncAppBranches",
+ "SwitchProjectBranch",
+ "DeleteProjectApp",
+
+ "PublishList",
+ "CreatePublishOrder",
+ "GetPublish",
+ "ClosePublish",
+ "DeletePublish",
+ "GetCanAddedApps",
+ "AddPublishApp",
+ "DeletePublishApp",
+ "GetOpertaionLogByPagination",
+ "GetBackTo",
+ "TriggerBackTo",
+ "GetNextStage",
+ "TriggerNextStage",
+ "GetStepInfo",
+ "RunStep",
+ "RunStepCallback",
+ })
+ if err != nil {
+ return err
+ }
+
+ for _, item := range sysMemberResourceOperations {
+ memberResourceOperationIDs = append(memberResourceOperationIDs, item.ID)
+ }
+
roles := []models.GroupRoleReq{
{
Group: constant.SystemGroup,
Role: constant.SystemAdminRole,
Description: "超级管理员",
- Operations: []string{"*"},
+ Operations: []int64{adminResourceItem.ID},
},
{
Group: constant.SystemGroup,
Role: constant.SystemMemberRole,
Description: "普通成员",
// TODO: change to real resouce operation
- Operations: []string{"CreateProject"},
+ Operations: memberResourceOperationIDs,
},
{
Group: constant.SystemGroup,
- Role: constant.CompanyAdminRole,
+ Role: constant.DevAdminRole,
Description: "项目管理员",
// TODO: change to real resouce operation
- Operations: []string{"CreateProject"},
+ Operations: devAdminResourceOperationIDs,
},
}
for _, role := range roles {
diff --git a/models/models.go b/models/models.go
index 350c238a4eb2f2fb8f27721d730891112981a637..eae429e5876e815727f6ab059d61601ecb10f4f1 100644
--- a/models/models.go
+++ b/models/models.go
@@ -166,7 +166,7 @@ func initOrm() {
new(GroupRoleUser),
new(GroupUserConstraint),
new(GroupRole),
- new(GroupRolePolicy),
+ new(GroupRoleOperation),
new(Audit),
new(GatewayRouter),
diff --git a/models/role.go b/models/role.go
index da605843faa8a8ce14809a49832aa41c54095fcc..5d9a91059fcf0019ae6d3f5596b5a8d57c2bd70d 100644
--- a/models/role.go
+++ b/models/role.go
@@ -51,10 +51,10 @@ func (t *GroupRole) TableUnique() [][]string {
// GroupRoleReq ..
type GroupRoleReq struct {
- Group string `json:"group"`
- Role string `json:"role"`
- Description string `json:"description"`
- Operations []string `json:"operations"`
+ Group string `json:"group"`
+ Role string `json:"role"`
+ Description string `json:"description"`
+ Operations []int64 `json:"operations"`
}
// Verify ..
@@ -76,37 +76,38 @@ type RoleRsp struct {
Description string `json:"description"`
}
-type GroupRolePolicy struct {
+type GroupRoleOperation struct {
Addons
- Group string `orm:"column(group)" json:"group"`
- Role string `orm:"column(role)" json:"role"`
- PolicyName string `orm:"column(policy_name)" json:"policy_name"`
+ Group string `orm:"column(group)" json:"group"`
+ Role string `orm:"column(role)" json:"role"`
+ PolicyName string `orm:"column(policy_name)" json:"policy_name"`
+ OperationID int64 `orm:"column(operation_id)" json:"operation_id"`
}
// TableName ..
-func (t *GroupRolePolicy) TableName() string {
+func (t *GroupRoleOperation) TableName() string {
return "sys_group_role_operation"
}
// TableIndex ..
-func (t *GroupRolePolicy) TableIndex() [][]string {
+func (t *GroupRoleOperation) TableIndex() [][]string {
return [][]string{
{"Group", "Role"},
}
}
// TableUnique ..
-func (t *GroupRolePolicy) TableUnique() [][]string {
+func (t *GroupRoleOperation) TableUnique() [][]string {
return [][]string{
- {"Group", "Role", "PolicyName"},
+ {"Group", "Role", "OperationID"},
}
}
// GroupRolePolicyReq ..
type GroupRolePolicyReq struct {
- Group string `json:"group"`
- Role string `json:"role"`
- Operations []string `json:"operations"`
+ Group string `json:"group"`
+ Role string `json:"role"`
+ Operations []int64 `json:"operations"`
}
type GroupRoleBundlingUser struct {
diff --git a/routers/routers.go b/routers/routers.go
index 634fddef56242d08860b8ff33054e8e4d27bf532..680d7f099db369e1ab727cffad192e850e70b96f 100644
--- a/routers/routers.go
+++ b/routers/routers.go
@@ -73,9 +73,10 @@ func init() {
beego.NSRouter("/roles", &controllers.RoleController{}, "get:RoleList;post:CreateRole"),
- beego.NSRouter("/groups/:group/roles", &controllers.RoleController{}, "get:RoleList;post:CreateRole"),
- beego.NSRouter("/groups/:group/roles/:role", &controllers.RoleController{}, "get:GetRole;put:UpdateRole;delete:DeleteRole"),
- beego.NSRouter("/groups/:group/roles/:role/policies", &controllers.RoleController{}, "get:RolePolicyList;post:AddRolePolicy;delete:RemoveRolePolicy"),
+ beego.NSRouter("/roles", &controllers.RoleController{}, "get:RoleList;post:CreateRole"),
+ beego.NSRouter("/roles/:role", &controllers.RoleController{}, "get:GetRole;put:UpdateRole;delete:DeleteRole"),
+ beego.NSRouter("/roles/:role/operations", &controllers.RoleController{}, "get:RoleOperationList;post:AddRoleOperation"),
+ beego.NSRouter("/roles/:role/operations/:operationID", &controllers.RoleController{}, "delete:RemoveRoleOperation"),
beego.NSRouter("/groups/:group/roles/:role/bundling", &controllers.RoleController{}, "get:RoleBundlingList;post:RoleBundling;delete:RoleUnbundling"),
// PipelineStage
diff --git a/vendor/github.com/isbrick/tools/.gitignore b/vendor/github.com/isbrick/tools/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..722d5e71d93ca0aa0db6fd22452e46be5604a84d
--- /dev/null
+++ b/vendor/github.com/isbrick/tools/.gitignore
@@ -0,0 +1 @@
+.vscode
diff --git a/vendor/github.com/isbrick/tools/LICENSE b/vendor/github.com/isbrick/tools/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..534b464b1ac2ded70322085f2ed043a6a144c2be
--- /dev/null
+++ b/vendor/github.com/isbrick/tools/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2020 colynn.liu
+
+ 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.
\ No newline at end of file
diff --git a/vendor/github.com/isbrick/tools/README.md b/vendor/github.com/isbrick/tools/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..add39e32ae4fef737b547b80ba270c1f17daf331
--- /dev/null
+++ b/vendor/github.com/isbrick/tools/README.md
@@ -0,0 +1,6 @@
+## tools
+
+![Go](https://github.com/isbrick/tools/workflows/Go/badge.svg)
+[![codecov](https://codecov.io/gh/isbrick/tools/branch/master/graph/badge.svg)](https://codecov.io/gh/isbrick/tools)
+[![Go Report Card](https://goreportcard.com/badge/github.com/isbrick/tools)](https://goreportcard.com/report/github.com/isbrick/tools)
+[![GoDoc](https://godoc.org/github.com/isbrick/tools?status.svg)](https://pkg.go.dev/github.com/isbrick/tools?tab=doc)
\ No newline at end of file
diff --git a/vendor/github.com/isbrick/tools/absolute-path.go b/vendor/github.com/isbrick/tools/absolute-path.go
new file mode 100644
index 0000000000000000000000000000000000000000..8a9c04779a3edaed27d29ff02b4b3d5c44a9f741
--- /dev/null
+++ b/vendor/github.com/isbrick/tools/absolute-path.go
@@ -0,0 +1,68 @@
+// Copyright 2020 tools 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 tools
+
+import (
+ "os"
+ "os/exec"
+ "path/filepath"
+ "sync"
+)
+
+// EnsureAbs prepends the WorkDir to the given path if it is not an absolute path.
+func EnsureAbs(path string) string {
+ if filepath.IsAbs(path) {
+ return path
+ }
+ return filepath.Join(WorkDir(), path)
+}
+
+var (
+ workDir string
+ workDirOnce sync.Once
+)
+
+// WorkDir returns the absolute path of work directory. It reads the value of envrionment
+// variable GOGS_WORK_DIR. When not set, it uses the directory where the application's
+// binary is located.
+func WorkDir() string {
+ workDirOnce.Do(func() {
+ workDir = filepath.Dir(AppPath())
+ })
+
+ return workDir
+}
+
+var (
+ appPath string
+ appPathOnce sync.Once
+)
+
+// AppPath returns the absolute path of the application's binary.
+func AppPath() string {
+ appPathOnce.Do(func() {
+ var err error
+ appPath, err = exec.LookPath(os.Args[0])
+ if err != nil {
+ panic("look executable path: " + err.Error())
+ }
+ appPath, err = filepath.Abs(appPath)
+ if err != nil {
+ panic("get absolute executable path: " + err.Error())
+ }
+ })
+
+ return appPath
+}
diff --git a/vendor/github.com/isbrick/tools/convert.go b/vendor/github.com/isbrick/tools/convert.go
new file mode 100644
index 0000000000000000000000000000000000000000..03bf3abfa4591a9f9e200244923c6802953d6097
--- /dev/null
+++ b/vendor/github.com/isbrick/tools/convert.go
@@ -0,0 +1,59 @@
+package tools
+
+import (
+ "strconv"
+)
+
+// Convert string to specify type.
+type StrTo string
+
+func (f StrTo) Exist() bool {
+ return string(f) != string(rune(0x1E))
+}
+
+func (f StrTo) Uint8() (uint8, error) {
+ v, err := strconv.ParseUint(f.String(), 10, 8)
+ return uint8(v), err
+}
+
+func (f StrTo) Int() (int, error) {
+ v, err := strconv.ParseInt(f.String(), 10, 0)
+ return int(v), err
+}
+
+func (f StrTo) Int64() (int64, error) {
+ v, err := strconv.ParseInt(f.String(), 10, 64)
+ return int64(v), err
+}
+
+func (f StrTo) Float64() (float64, error) {
+ v, err := strconv.ParseFloat(f.String(), 64)
+ return float64(v), err
+}
+
+func (f StrTo) MustUint8() uint8 {
+ v, _ := f.Uint8()
+ return v
+}
+
+func (f StrTo) MustInt() int {
+ v, _ := f.Int()
+ return v
+}
+
+func (f StrTo) MustInt64() int64 {
+ v, _ := f.Int64()
+ return v
+}
+
+func (f StrTo) MustFloat64() float64 {
+ v, _ := f.Float64()
+ return v
+}
+
+func (f StrTo) String() string {
+ if f.Exist() {
+ return string(f)
+ }
+ return ""
+}
diff --git a/vendor/github.com/isbrick/tools/go.mod b/vendor/github.com/isbrick/tools/go.mod
new file mode 100644
index 0000000000000000000000000000000000000000..763df47419169a95246504e4da7efd47533d084f
--- /dev/null
+++ b/vendor/github.com/isbrick/tools/go.mod
@@ -0,0 +1,5 @@
+module github.com/isbrick/tools
+
+go 1.14
+
+require github.com/stretchr/testify v1.6.1
diff --git a/vendor/github.com/isbrick/tools/go.sum b/vendor/github.com/isbrick/tools/go.sum
new file mode 100644
index 0000000000000000000000000000000000000000..afe7890c9a1cf745e7e67ad82a70884ee4e206f0
--- /dev/null
+++ b/vendor/github.com/isbrick/tools/go.sum
@@ -0,0 +1,11 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/vendor/github.com/isbrick/tools/slice.go b/vendor/github.com/isbrick/tools/slice.go
new file mode 100644
index 0000000000000000000000000000000000000000..e3c9168cd8f6bd3b9d7d0b31f48bb3002ec6ceaf
--- /dev/null
+++ b/vendor/github.com/isbrick/tools/slice.go
@@ -0,0 +1,99 @@
+// Copyright 2020 tools 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 tools
+
+import "strings"
+
+// IsSliceContainsStr returns true if the string exists in given slice, ignore case.
+func IsSliceContainsStr(sl []string, str string) bool {
+ str = strings.ToLower(str)
+ for _, s := range sl {
+ if strings.ToLower(s) == str {
+ return true
+ }
+ }
+ return false
+}
+
+// IsSliceContainsInt64 returns true if the int64 exists in given slice.
+func IsSliceContainsInt64(sl []int64, i int64) bool {
+ for _, s := range sl {
+ if s == i {
+ return true
+ }
+ }
+ return false
+}
+
+// IsSliceContainsInt returns true if the int exists in given slice.
+func IsSliceContainsInt(sl []int, i int) bool {
+ for _, s := range sl {
+ if s == i {
+ return true
+ }
+ }
+ return false
+}
+
+// IntSliceDifference int slice difference
+func IntSliceDifference(slice1, slice2 []int) []int {
+ m := make(map[int]int)
+ nn := make([]int, 0)
+ inter := IntSliceIntersect(slice1, slice2)
+ for _, v := range inter {
+ m[v]++
+ }
+
+ for _, value := range slice1 {
+ times, _ := m[value]
+ if times == 0 {
+ nn = append(nn, value)
+ }
+ }
+ return nn
+}
+
+// IntSliceIntersect ..
+func IntSliceIntersect(slice1, slice2 []int) []int {
+ m := make(map[int]int)
+ nn := make([]int, 0)
+ for _, v := range slice1 {
+ m[v]++
+ }
+
+ for _, v := range slice2 {
+ times, _ := m[v]
+ if times == 1 {
+ nn = append(nn, v)
+ }
+ }
+ return nn
+}
+
+// IntSliceUnion ..
+func IntSliceUnion(slice1, slice2 []int) []int {
+ m := make(map[int]int)
+ for _, v := range slice1 {
+ m[v]++
+ }
+
+ for _, v := range slice2 {
+ times, _ := m[v]
+ if times == 0 {
+ slice1 = append(slice1, v)
+ }
+ }
+ return slice1
+}
diff --git a/vendor/github.com/isbrick/tools/string.go b/vendor/github.com/isbrick/tools/string.go
new file mode 100644
index 0000000000000000000000000000000000000000..2d2aef337f899108d1d84c0c9cc0d834daba0e35
--- /dev/null
+++ b/vendor/github.com/isbrick/tools/string.go
@@ -0,0 +1,15 @@
+// Copyright 2020 tools 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 tools
diff --git a/vendor/github.com/isbrick/tools/time.go b/vendor/github.com/isbrick/tools/time.go
new file mode 100644
index 0000000000000000000000000000000000000000..a9ece8aec92c041f9a526c8ab7927e5e2a6f5c90
--- /dev/null
+++ b/vendor/github.com/isbrick/tools/time.go
@@ -0,0 +1,145 @@
+// Copyright 2020 tools 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 tools
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// Date Format unix time int64 to string
+// eg format: YYYY-MM-DD HH:mm:SS
+func Date(ti int64, format string) string {
+ t := time.Unix(int64(ti), 0)
+ return DateT(t, format)
+}
+
+// DateS Format unix time string to string
+func DateS(ts string, format string) string {
+ i, _ := strconv.ParseInt(ts, 10, 64)
+ return Date(i, format)
+}
+
+// DateT ..
+// Format time.Time struct to string
+// MM - month - 01
+// M - month - 1, single bit
+// DD - day - 02
+// D - day 2
+// YYYY - year - 2006
+// YY - year - 06
+// HH - 24 hours - 03
+// H - 24 hours - 3
+// hh - 12 hours - 03
+// h - 12 hours - 3
+// mm - minute - 04
+// m - minute - 4
+// ss - second - 05
+// s - second = 5
+func DateT(t time.Time, format string) string {
+ res := strings.Replace(format, "MM", t.Format("01"), -1)
+ res = strings.Replace(res, "M", t.Format("1"), -1)
+ res = strings.Replace(res, "DD", t.Format("02"), -1)
+ res = strings.Replace(res, "D", t.Format("2"), -1)
+ res = strings.Replace(res, "YYYY", t.Format("2006"), -1)
+ res = strings.Replace(res, "YY", t.Format("06"), -1)
+ res = strings.Replace(res, "HH", fmt.Sprintf("%02d", t.Hour()), -1)
+ res = strings.Replace(res, "H", fmt.Sprintf("%d", t.Hour()), -1)
+ res = strings.Replace(res, "hh", t.Format("03"), -1)
+ res = strings.Replace(res, "h", t.Format("3"), -1)
+ res = strings.Replace(res, "mm", t.Format("04"), -1)
+ res = strings.Replace(res, "m", t.Format("4"), -1)
+ res = strings.Replace(res, "ss", t.Format("05"), -1)
+ res = strings.Replace(res, "s", t.Format("5"), -1)
+ return res
+}
+
+// ParseStrToDate ..
+// timeStr
+// format
+// locationName, when locationName is "", defaultLocation rely on system env.
+func ParseStrToDate(timestr, format, locationName string) (time.Time, error) {
+ timeFormat := timeFormatParse(format)
+ loc := gettimeLocation(locationName)
+ timeValue, err := time.ParseInLocation(timeFormat, timestr, loc)
+ return timeValue, err
+}
+
+// ParseDateToStr ..
+// MM - month - 01
+// M - month - 1, single bit
+// DD - day - 02
+// D - day 2
+// YYYY - year - 2006
+// YY - year - 06
+// HH - 24 hours - 03
+// H - 24 hours - 3
+// hh - 12 hours - 03
+// h - 12 hours - 3
+// mm - minute - 04
+// m - minute - 4
+// ss - second - 05
+// s - second = 5
+func ParseDateToStr(timeValue time.Time, format string) string {
+ formatStr := timeFormatParse(format)
+ return timeValue.Format(formatStr)
+}
+
+// TimeComparison time
+// 0 equal,
+// 1 time1 greater than time2
+// 2 time1 less than time2
+func TimeComparison(time1, time2 time.Time) int {
+ subSeconds := time1.Sub(time2).Seconds()
+ if subSeconds == 0 {
+ return 0
+ } else if subSeconds > 0 {
+ return 1
+ } else {
+ return 2
+ }
+}
+
+// timeFormatParse ..
+func timeFormatParse(formatStr string) string {
+ res := strings.Replace(formatStr, "MM", "01", -1)
+ res = strings.Replace(res, "M", "1", -1)
+ res = strings.Replace(res, "DD", "02", -1)
+ res = strings.Replace(res, "D", "2", -1)
+ res = strings.Replace(res, "YYYY", "2006", -1)
+ res = strings.Replace(res, "YY", "06", -1)
+ res = strings.Replace(res, "HH", "15", -1)
+ res = strings.Replace(res, "H", "15", -1)
+ res = strings.Replace(res, "hh", "03", -1)
+ res = strings.Replace(res, "h", "3", -1)
+ res = strings.Replace(res, "mm", "04", -1)
+ res = strings.Replace(res, "m", "4", -1)
+ res = strings.Replace(res, "ss", "05", -1)
+ res = strings.Replace(res, "s", "5", -1)
+ return res
+}
+
+// gettimeLocation
+func gettimeLocation(locationName string) *time.Location {
+ var loc *time.Location
+ if locationName == "" {
+ loc = time.Now().Location()
+ } else {
+ loc, _ = time.LoadLocation(locationName)
+ }
+ return loc
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 936a199b0bd2f7b2d865944a71aeb646876e6e71..63a4e94efbc933155626aaa904bbc034b94ea70e 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -94,6 +94,9 @@ github.com/imdario/mergo
github.com/inconshreveable/mousetrap
# github.com/isbrick/http-client v0.0.0-20210321135403-0a5df00fdb84
github.com/isbrick/http-client
+# github.com/isbrick/tools v0.0.0-20211027093338-a3a0ded37175
+## explicit
+github.com/isbrick/tools
# github.com/json-iterator/go v1.1.8
github.com/json-iterator/go
# github.com/kr/text v0.2.0
diff --git a/web/src/api/backend.js b/web/src/api/backend.js
index eb070937bcd1b7a326799d5bc164a910042b6280..f1aa359f6b1d1dae9bea0c3930f9643e54a88310 100644
--- a/web/src/api/backend.js
+++ b/web/src/api/backend.js
@@ -494,10 +494,6 @@ const backendAPI = {
Package.httpMethods('delete', `/atomci/api/v1/groups/${group}/users/${user}`, cb);
},
// 删除用户组权限 - 角色
- delGroupRole(group, role, cb) {
- Package.httpMethods('delete', `/atomci/api/v1/groups/${group}/roles/${role}`, cb);
- },
- // 删除用户组权限 - 角色
delGroupConstraints(group, constraints, cb) {
Package.httpMethods(
'delete',
@@ -672,12 +668,17 @@ const backendAPI = {
},
// 查询角色列表
- getGroupRoleList(group, cb) {
- Package.httpMethods('get', `/atomci/api/v1/groups/${group}/roles`, cb);
+ getGroupRoleList(cb) {
+ Package.httpMethods('get', `/atomci/api/v1/roles`, cb);
},
// 更新组角色
- updateGroupRole(group, role, body, cb) {
- Package.httpMethods('put', `/atomci/api/v1/groups/${group}/roles/${role}`, cb, body);
+ updateGroupRole(role, body, cb) {
+ Package.httpMethods('put', `/atomci/api/v1/roles/${role}`, cb, body);
+ },
+
+ // 删除用户组权限 - 角色
+ delGroupRole(group, role, cb) {
+ Package.httpMethods('delete', `/atomci/api/v1/roles/${role}`, cb);
},
// 资源操作
@@ -723,17 +724,25 @@ const backendAPI = {
Package.httpMethods('get', `/atomci/api/v1/groups/${group}/users`, cb);
},
// 查询角色详情
- getGroupRoleDetail(group, role, cb) {
- Package.httpMethods('get', `/atomci/api/v1/groups/${group}/roles/${role}`, cb);
+ getGroupRoleDetail(role, cb) {
+ Package.httpMethods('get', `/atomci/api/v1/roles/${role}`, cb);
+ },
+
+ // 查询角色操作
+ getRoleOperations(role, cb) {
+ Package.httpMethods('get', `/atomci/api/v1/roles/${role}/operations`, cb);
+ },
+
+ // 删除角色操作
+ deleteRoleOperation(role, operationID, cb) {
+ Package.httpMethods('delete', `/atomci/api/v1/roles/${role}/operations/${operationID}`, cb);
},
+
// 添加角色权限策略
addRolePolicies(group, role, body, cb) {
Package.httpMethods('post', `/atomci/api/v1/groups/${group}/roles/${role}/policies`, cb, body);
},
- // 删除角色权限策略
- deleteRolePolicies(body, group, role, cb) {
- Package.httpMethods('delete', `/atomci/api/v1/groups/${group}/roles/${role}/policies`, cb, body);
- },
+
// 添加角色绑定用户
addRoleBindUser(group, role, body, cb) {
Package.httpMethods('post', `/atomci/api/v1/groups/${group}/roles/${role}/bundling`, cb, body);
diff --git a/web/src/components/utils/user/RoleCreate.vue b/web/src/components/utils/user/RoleCreate.vue
index 981843e45dcf19fd466a4a4b0ae60458b4c6ab96..ba7e37d82c5e7fd347701c7652e9e7acbf8138d2 100644
--- a/web/src/components/utils/user/RoleCreate.vue
+++ b/web/src/components/utils/user/RoleCreate.vue
@@ -24,7 +24,7 @@
-
+
@@ -38,9 +38,9 @@