3
0
corteza/compose/service/automation_script.go
2019-10-16 19:28:48 +02:00

179 lines
4.7 KiB
Go

package service
import (
"context"
"go.uber.org/zap"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/automation"
"github.com/cortezaproject/corteza-server/pkg/permissions"
)
type (
automationScript struct {
logger *zap.Logger
scriptManager automationScriptManager
ns NamespaceService
mod ModuleService
ac automationScriptAccessController
trg automationTrigger
}
automationScriptManager interface {
FindScriptByID(context.Context, uint64) (*automation.Script, error)
FindScripts(context.Context, automation.ScriptFilter) (automation.ScriptSet, automation.ScriptFilter, error)
CreateScript(context.Context, *automation.Script) error
UpdateScript(context.Context, *automation.Script) error
DeleteScript(context.Context, *automation.Script) error
}
automationScriptAccessController interface {
CanGrant(context.Context) bool
CanReadNamespace(context.Context, *types.Namespace) bool
CanCreateAutomationScript(context.Context, *types.Namespace) bool
CanReadAutomationScript(context.Context, *automation.Script) bool
CanUpdateAutomationScript(context.Context, *automation.Script) bool
CanDeleteAutomationScript(context.Context, *automation.Script) bool
FilterReadableScripts(ctx context.Context) *permissions.ResourceFilter
}
)
func AutomationScript(sm automationScriptManager) automationScript {
var svc = automationScript{
scriptManager: sm,
logger: DefaultLogger.Named("automation-script"),
ac: DefaultAccessControl,
mod: DefaultModule,
ns: DefaultNamespace,
trg: DefaultAutomationTriggerManager,
}
return svc
}
func (svc automationScript) FindByID(ctx context.Context, namespaceID, scriptID uint64) (*automation.Script, error) {
if _, s, err := svc.loadCombo(ctx, namespaceID, scriptID); err != nil {
return nil, err
} else if !svc.ac.CanReadAutomationScript(ctx, s) {
return nil, ErrNoReadPermissions
} else {
return s, nil
}
}
func (svc automationScript) Find(ctx context.Context, namespaceID uint64, f automation.ScriptFilter) (automation.ScriptSet, automation.ScriptFilter, error) {
if _, _, err := svc.loadCombo(ctx, namespaceID, 0); err != nil {
return nil, f, err
}
f.NamespaceID = namespaceID
f.IsReadable = svc.ac.FilterReadableScripts(ctx)
return svc.scriptManager.FindScripts(ctx, f)
}
func (svc automationScript) Create(ctx context.Context, namespaceID uint64, mod *automation.Script) (err error) {
var ns *types.Namespace
if ns, _, err = svc.loadCombo(ctx, namespaceID, 0); err != nil {
return err
}
if !svc.ac.CanCreateAutomationScript(ctx, ns) {
return ErrNoCreatePermissions.withStack()
}
if mod.RunAs > 0 {
if !svc.ac.CanGrant(ctx) {
return ErrNoGrantPermissions
}
}
err = mod.Triggers().Walk(func(t *automation.Trigger) error {
return svc.trg.isValid(ctx, mod, t)
})
if err != nil {
return
}
return svc.scriptManager.CreateScript(ctx, mod)
}
func (svc automationScript) Update(ctx context.Context, namespaceID uint64, mod *automation.Script) (err error) {
var s *automation.Script
if _, s, err = svc.loadCombo(ctx, namespaceID, mod.ID); err != nil {
return err
}
if !svc.ac.CanUpdateAutomationScript(ctx, s) {
return ErrNoUpdatePermissions.withStack()
}
// Users need to have grant privileges to
// set script runner
if mod.RunAs != s.RunAs {
if !svc.ac.CanGrant(ctx) {
return ErrNoGrantPermissions
}
}
s.Name = mod.Name
s.SourceRef = mod.SourceRef
s.Source = mod.Source
s.Async = mod.Async
s.RunAs = mod.RunAs
s.RunInUA = mod.RunInUA
s.Timeout = mod.Timeout
s.Critical = mod.Critical
s.Enabled = mod.Enabled
err = mod.Triggers().Walk(func(t *automation.Trigger) error {
return svc.trg.isValid(ctx, mod, t)
})
if err != nil {
return
}
s.AddTrigger(automation.STMS_UPDATE, mod.Triggers()...)
return svc.scriptManager.UpdateScript(ctx, s)
}
func (svc automationScript) Delete(ctx context.Context, namespaceID, scriptID uint64) (err error) {
if _, s, err := svc.loadCombo(ctx, namespaceID, scriptID); err != nil {
return err
} else if !svc.ac.CanDeleteAutomationScript(ctx, s) {
return ErrNoDeletePermissions.withStack()
} else {
return svc.scriptManager.DeleteScript(ctx, s)
}
}
func (svc automationScript) loadCombo(ctx context.Context, namespaceID, scriptID uint64) (ns *types.Namespace, s *automation.Script, err error) {
if namespaceID == 0 {
err = ErrNamespaceRequired.withStack()
return
}
if ns, err = svc.ns.With(ctx).FindByID(namespaceID); err != nil {
return
} else if !svc.ac.CanReadNamespace(ctx, ns) {
err = ErrNoReadPermissions.withStack()
return
}
if scriptID > 0 {
if s, err = svc.scriptManager.FindScriptByID(ctx, scriptID); err != nil {
return
}
}
return
}