Skip to content

Commit

Permalink
Merge pull request #314 from actiontech/support_issue_288
Browse files Browse the repository at this point in the history
support workflow operation permission
  • Loading branch information
jessun authored Feb 18, 2022
2 parents 612abf7 + b615edc commit 945eece
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 18 deletions.
14 changes: 11 additions & 3 deletions sqle/api/controller/v1/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,18 @@ func checkCurrentUserCanAccessTask(c echo.Context, task *model.Task) error {
if err != nil {
return err
}
if !access {
return ErrTaskNoAccess
if access {
return nil
}

ok, err := s.CheckUserHasOpToInstance(user, task.Instance, []uint{model.OP_WORKFLOW_VIEW_OTHERS})
if err != nil {
return err
}
if ok {
return nil
}
return nil
return ErrTaskNoAccess
}

// @Summary 获取Sql审核任务信息
Expand Down
40 changes: 27 additions & 13 deletions sqle/api/controller/v1/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package v1

import (
"fmt"
"github.com/actiontech/sqle/sqle/driver"
"net/http"
"strconv"
"time"

"github.com/actiontech/sqle/sqle/driver"

"github.com/actiontech/sqle/sqle/api/controller"
"github.com/actiontech/sqle/sqle/errors"
"github.com/actiontech/sqle/sqle/log"
Expand Down Expand Up @@ -609,7 +610,7 @@ type WorkflowStepResV1 struct {
Reason string `json:"reason,omitempty"`
}

func checkCurrentUserCanAccessWorkflow(c echo.Context, workflow *model.Workflow) error {
func checkCurrentUserCanAccessWorkflow(c echo.Context, workflow *model.Workflow, ops []uint) error {
if controller.GetUserName(c) == model.DefaultAdminUser {
return nil
}
Expand All @@ -622,10 +623,23 @@ func checkCurrentUserCanAccessWorkflow(c echo.Context, workflow *model.Workflow)
if err != nil {
return err
}
if !access {
return ErrWorkflowNoAccess
if access {
return nil
}
return nil
if len(ops) > 0 {
instance, err := s.GetInstanceByWorkflowID(workflow.ID)
if err != nil {
return err
}
ok, err := s.CheckUserHasOpToInstance(user, instance, ops)
if err != nil {
return err
}
if ok {
return nil
}
}
return ErrWorkflowNoAccess
}

func convertWorkflowToRes(workflow *model.Workflow, task *model.Task) *WorkflowResV1 {
Expand Down Expand Up @@ -763,7 +777,7 @@ func GetWorkflow(c echo.Context) error {
}
err = checkCurrentUserCanAccessWorkflow(c, &model.Workflow{
Model: model.Model{ID: uint(id)},
})
}, []uint{model.OP_WORKFLOW_VIEW_OTHERS})
if err != nil {
return controller.JSONBaseErrorReq(c, err)
}
Expand Down Expand Up @@ -904,7 +918,7 @@ func GetWorkflows(c echo.Context) error {
"offset": offset,
}
s := model.GetStorage()
workflows, count, err := s.GetWorkflowsByReq(data)
workflows, count, err := s.GetWorkflowsByReq(data, user)
if err != nil {
return controller.JSONBaseErrorReq(c, err)
}
Expand Down Expand Up @@ -970,7 +984,7 @@ func ApproveWorkflow(c echo.Context) error {
}
err = checkCurrentUserCanAccessWorkflow(c, &model.Workflow{
Model: model.Model{ID: uint(id)},
})
}, []uint{})
if err != nil {
return controller.JSONBaseErrorReq(c, err)
}
Expand Down Expand Up @@ -1052,7 +1066,7 @@ func RejectWorkflow(c echo.Context) error {
}
err = checkCurrentUserCanAccessWorkflow(c, &model.Workflow{
Model: model.Model{ID: uint(id)},
})
}, []uint{})
if err != nil {
return controller.JSONBaseErrorReq(c, err)
}
Expand Down Expand Up @@ -1116,7 +1130,7 @@ func CancelWorkflow(c echo.Context) error {
}
err = checkCurrentUserCanAccessWorkflow(c, &model.Workflow{
Model: model.Model{ID: uint(id)},
})
}, []uint{})
if err != nil {
return controller.JSONBaseErrorReq(c, err)
}
Expand Down Expand Up @@ -1227,7 +1241,7 @@ func UpdateWorkflow(c echo.Context) error {
}
err = checkCurrentUserCanAccessWorkflow(c, &model.Workflow{
Model: model.Model{ID: uint(id)},
})
}, []uint{})
if err != nil {
return controller.JSONBaseErrorReq(c, err)
}
Expand Down Expand Up @@ -1354,7 +1368,7 @@ func UpdateWorkflowSchedule(c echo.Context) error {
}
err = checkCurrentUserCanAccessWorkflow(c, &model.Workflow{
Model: model.Model{ID: uint(id)},
})
}, []uint{})
if err != nil {
return controller.JSONBaseErrorReq(c, err)
}
Expand Down Expand Up @@ -1415,7 +1429,7 @@ func ExecuteTaskOnWorkflow(c echo.Context) error {
}
err = checkCurrentUserCanAccessWorkflow(c, &model.Workflow{
Model: model.Model{ID: uint(id)},
})
}, []uint{})
if err != nil {
return controller.JSONBaseErrorReq(c, err)
}
Expand Down
6 changes: 6 additions & 0 deletions sqle/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const (

HttpRequestFormatError ErrorCode = 2001

ErrAccessDeniedError ErrorCode = 3001

LoginAuthFail ErrorCode = 4001
UserDisabled ErrorCode = 4005
TaskNotExist ErrorCode = 4006
Expand Down Expand Up @@ -94,3 +96,7 @@ func HttpRequestFormatErrWrapper(err error) error {
func ConnectStorageErrWrapper(err error) error {
return New(ConnectStorageError, err)
}

func NewAccessDeniedErr(format string, a ...interface{}) error {
return New(ErrAccessDeniedError, fmt.Errorf(format, a...))
}
143 changes: 143 additions & 0 deletions sqle/model/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,146 @@ func (s *Storage) GetInstanceNamesByWorkflowTemplateId(id uint) ([]string, error
}
return names, nil
}

func (s *Storage) CheckUserHasOpToInstance(user *User, instance *Instance, ops []uint) (bool, error) {
query := `
SELECT instances.id
FROM instances
LEFT JOIN instance_role ON instance_role.instance_id = instances.id
LEFT JOIN roles ON roles.id = instance_role.role_id AND roles.deleted_at IS NULL AND roles.stat = 0
LEFT JOIN role_operations ON role_operations.role_id = roles.id
LEFT JOIN user_role ON user_role.role_id = roles.id
LEFT JOIN users ON users.id = user_role.user_id AND users.stat = 0
WHERE
instances.deleted_at IS NULL
AND instances.id = ?
AND users.id = ?
AND role_operations.op_code IN (?)
GROUP BY instances.id
UNION
SELECT instances.id
FROM instances
LEFT JOIN instance_role ON instance_role.instance_id = instances.id
LEFT JOIN roles ON roles.id = instance_role.role_id AND roles.deleted_at IS NULL AND roles.stat = 0
LEFT JOIN role_operations ON role_operations.role_id = roles.id
JOIN user_group_roles ON roles.id = user_group_roles.role_id
JOIN user_groups ON user_groups.id = user_group_roles.user_group_id AND user_groups.deleted_at IS NULL
JOIN user_group_users ON user_groups.id = user_group_users.user_group_id
JOIN users ON users.id = user_group_users.user_id AND users.deleted_at IS NULL AND users.stat=0
WHERE
instances.deleted_at IS NULL
AND instances.id = ?
AND users.id = ?
AND role_operations.op_code IN (?)
GROUP BY instances.id
`
var instances []*Instance
err := s.db.Raw(query, instance.ID, user.ID, ops, instance.ID, user.ID, ops).Scan(&instances).Error
if err != nil {
return false, errors.ConnectStorageErrWrapper(err)
}
return len(instances) > 0, nil
}

func (s *Storage) GetUserCanOpInstances(user *User, ops []uint) (instances []*Instance, err error) {
query := `
SELECT instances.id
FROM instances
LEFT JOIN instance_role ON instance_role.instance_id = instances.id
LEFT JOIN roles ON roles.id = instance_role.role_id AND roles.deleted_at IS NULL AND roles.stat = 0
LEFT JOIN role_operations ON role_operations.role_id = roles.id
LEFT JOIN user_role ON user_role.role_id = roles.id
LEFT JOIN users ON users.id = user_role.user_id AND users.stat = 0
WHERE
instances.deleted_at IS NULL
AND users.id = ?
AND role_operations.op_code IN (?)
GROUP BY instances.id
UNION
SELECT instances.id
FROM instances
LEFT JOIN instance_role ON instance_role.instance_id = instances.id
LEFT JOIN roles ON roles.id = instance_role.role_id AND roles.deleted_at IS NULL AND roles.stat = 0
LEFT JOIN role_operations ON role_operations.role_id = roles.id
JOIN user_group_roles ON roles.id = user_group_roles.role_id
JOIN user_groups ON user_groups.id = user_group_roles.user_group_id AND user_groups.deleted_at IS NULL
JOIN user_group_users ON user_groups.id = user_group_users.user_group_id
JOIN users ON users.id = user_group_users.user_id AND users.deleted_at IS NULL AND users.stat=0
WHERE
instances.deleted_at IS NULL
AND users.id = ?
AND role_operations.op_code IN (?)
GROUP BY instances.id
`
err = s.db.Raw(query, user.ID, ops, user.ID, ops).Scan(&instances).Error
if err != nil {
return nil, errors.ConnectStorageErrWrapper(err)
}
return
}

func getInstanceIDsFromInstances(instances []*Instance) (ids []uint) {
ids = make([]uint, len(instances))
for i := range instances {
ids[i] = instances[i].ID
}
return ids
}

//SELECT instances.id
//FROM instances
//LEFT JOIN instance_role ON instance_role.instance_id = instances.id
//LEFT JOIN roles ON roles.id = instance_role.role_id AND roles.deleted_at IS NULL AND roles.stat = 0
//LEFT JOIN role_operations ON role_operations.role_id = roles.id
//LEFT JOIN user_role ON user_role.role_id = roles.id
//LEFT JOIN users ON users.id = user_role.user_id AND users.stat = 0
//WHERE
//instances.deleted_at IS NULL
//AND users.id = 5
//AND role_operations.op_code IN (20200)
//GROUP BY instances.id
//UNION
//SELECT instances.id
//FROM instances
//LEFT JOIN instance_role ON instance_role.instance_id = instances.id
//LEFT JOIN roles ON roles.id = instance_role.role_id AND roles.deleted_at IS NULL AND roles.stat = 0
//LEFT JOIN role_operations ON role_operations.role_id = roles.id
//JOIN user_group_roles ON roles.id = user_group_roles.role_id
//JOIN user_groups ON user_groups.id = user_group_roles.user_group_id AND user_groups.deleted_at IS NULL
//JOIN user_group_users ON user_groups.id = user_group_users.user_group_id
//JOIN users ON users.id = user_group_users.user_id AND users.deleted_at IS NULL AND users.stat=0
//WHERE
//instances.deleted_at IS NULL
//AND users.id = 5
//AND role_operations.op_code IN (20200)
//GROUP BY instances.id

//SELECT instances.id
//FROM instances
//LEFT JOIN instance_role ON instance_role.instance_id = instances.id
//LEFT JOIN roles ON roles.id = instance_role.role_id AND roles.deleted_at IS NULL AND roles.stat = 0
//LEFT JOIN role_operations ON role_operations.role_id = roles.id
//LEFT JOIN user_role ON user_role.role_id = roles.id
//LEFT JOIN users ON users.id = user_role.user_id AND users.stat = 0
//WHERE
//instances.deleted_at IS NULL
//AND instances.id = 5
//AND users.id = 4
//AND role_operations.op_code IN (20200)
//GROUP BY instances.id
//UNION
//SELECT instances.id
//FROM instances
//LEFT JOIN instance_role ON instance_role.instance_id = instances.id
//LEFT JOIN roles ON roles.id = instance_role.role_id AND roles.deleted_at IS NULL AND roles.stat = 0
//LEFT JOIN role_operations ON role_operations.role_id = roles.id
//JOIN user_group_roles ON roles.id = user_group_roles.role_id
//JOIN user_groups ON user_groups.id = user_group_roles.user_group_id AND user_groups.deleted_at IS NULL
//JOIN user_group_users ON user_groups.id = user_group_users.user_group_id
//JOIN users ON users.id = user_group_users.user_id AND users.deleted_at IS NULL AND users.stat=0
//WHERE
//instances.deleted_at IS NULL
//AND instances.id = 5
//AND users.id = 4
//AND role_operations.op_code IN (20200)
//GROUP BY instances.id
18 changes: 18 additions & 0 deletions sqle/model/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -601,3 +601,21 @@ func (s *Storage) TaskWorkflowIsRunning(taskIds []uint) (bool, error) {
err := s.db.Where("status = ? AND task_id IN (?)", WorkflowStatusRunning, taskIds).Find(&workflowRecords).Error
return len(workflowRecords) > 0, errors.New(errors.ConnectStorageError, err)
}

func (s *Storage) GetInstanceByWorkflowID(workflowID uint) (*Instance, error) {
query := `
SELECT instances.id
FROM workflows AS w
LEFT JOIN workflow_records AS wr ON wr.id = w.workflow_record_id
LEFT JOIN tasks ON tasks.id = wr.task_id
LEFT JOIN instances ON instances.id = tasks.instance_id
WHERE
w.id = ?
LIMIT 1`
instance := &Instance{}
err := s.db.Raw(query, workflowID).Scan(instance).Error
if err != nil {
return nil, errors.ConnectStorageErrWrapper(err)
}
return instance, err
}
25 changes: 23 additions & 2 deletions sqle/model/workflow_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package model
import (
"database/sql"
"time"

"github.com/actiontech/sqle/sqle/utils"
)

type WorkflowListDetail struct {
Expand Down Expand Up @@ -68,9 +70,15 @@ WHERE
w.deleted_at IS NULL
{{- if .check_user_can_access }}
AND (w.create_user_id = :current_user_id
AND (
w.create_user_id = :current_user_id
OR curr_ass_user.id = :current_user_id
OR all_ass_user.id = :current_user_id
{{- if .viewable_instance_ids }}
OR inst.id IN (:viewable_instance_ids)
{{- end }}
)
{{- end }}
Expand Down Expand Up @@ -121,9 +129,22 @@ AND inst.name = :filter_task_instance_name
`

func (s *Storage) GetWorkflowsByReq(data map[string]interface{}) (
func (s *Storage) GetWorkflowsByReq(data map[string]interface{}, user *User) (
result []*WorkflowListDetail, count uint64, err error) {

// get workflow ids only for user can access by OP_WORKFLOW_VIEW_OTHERS
var ids []uint
{
instances, err := s.GetUserCanOpInstances(user, []uint{OP_WORKFLOW_VIEW_OTHERS})
if err != nil {
return result, 0, err
}
ids = getInstanceIDsFromInstances(instances)
}
if len(ids) > 0 {
data["viewable_instance_ids"] = utils.JoinUintSliceToString(ids, ", ")
}

err = s.getListResult(workflowsQueryBodyTpl, workflowsQueryTpl, data, &result)
if err != nil {
return result, 0, err
Expand Down

0 comments on commit 945eece

Please sign in to comment.