3
0
Files
corteza/compose/service/automation_trigger.go
2019-09-20 12:27:38 +02:00

145 lines
4.0 KiB
Go

package service
import (
"context"
"github.com/pkg/errors"
"go.uber.org/zap"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/automation"
)
type (
// Handles automation triggers storing and loading
automationTrigger struct {
logger *zap.Logger
triggerManager automationTriggerManager
mod ModuleService
ac automationTriggerAccessController
}
automationTriggerManager interface {
FindTriggerByID(context.Context, uint64) (*automation.Trigger, error)
FindTriggers(context.Context, automation.TriggerFilter) (automation.TriggerSet, automation.TriggerFilter, error)
CreateTrigger(context.Context, *automation.Script, *automation.Trigger) error
UpdateTrigger(context.Context, *automation.Script, *automation.Trigger) error
DeleteTrigger(context.Context, *automation.Trigger) error
}
automationTriggerAccessController interface {
CanUpdateAutomationScript(context.Context, *automation.Script) bool
CanManageAutomationTriggersOnModule(context.Context, *types.Module) bool
}
)
func AutomationTrigger(tm automationTriggerManager) automationTrigger {
var svc = automationTrigger{
triggerManager: tm,
logger: DefaultLogger.Named("automation-trigger"),
ac: DefaultAccessControl,
mod: DefaultModule,
}
return svc
}
func (svc automationTrigger) FindByID(ctx context.Context, triggerID uint64) (*automation.Trigger, error) {
// @todo security check - can user read this trigger?
return svc.triggerManager.FindTriggerByID(ctx, triggerID)
}
func (svc automationTrigger) Find(ctx context.Context, f automation.TriggerFilter) (automation.TriggerSet, automation.TriggerFilter, error) {
// @todo security check - can user read these triggers?
return svc.triggerManager.FindTriggers(ctx, f)
}
func (svc automationTrigger) Create(ctx context.Context, s *automation.Script, t *automation.Trigger) (err error) {
if err = svc.isValid(ctx, s, t); err != nil {
return
}
if !svc.ac.CanUpdateAutomationScript(ctx, s) {
return ErrNoTriggerManagementPermissions
}
return svc.triggerManager.CreateTrigger(ctx, s, t)
}
func (svc automationTrigger) Update(ctx context.Context, s *automation.Script, t *automation.Trigger) (err error) {
if err = svc.isValid(ctx, s, t); err != nil {
return
}
if !svc.ac.CanUpdateAutomationScript(ctx, s) {
return ErrNoTriggerManagementPermissions
}
return svc.triggerManager.UpdateTrigger(ctx, s, t)
}
func (svc automationTrigger) Delete(ctx context.Context, s *automation.Script, t *automation.Trigger) (err error) {
if err = svc.isValid(ctx, s, t); err != nil {
return
}
if !svc.ac.CanUpdateAutomationScript(ctx, s) {
return ErrNoTriggerManagementPermissions
}
return svc.triggerManager.DeleteTrigger(ctx, t)
}
// Validates trigger (in compose context)
func (svc automationTrigger) isValid(ctx context.Context, s *automation.Script, t *automation.Trigger) error {
if s == nil {
return errors.WithStack(automation.ErrAutomationScriptInvalid)
}
if !t.Enabled {
return nil
}
if t.Resource != "compose:record" {
// Accepting only compose:record resources
return errors.WithStack(automation.ErrAutomationTriggerInvalidResource)
}
if t.IsDeferred() {
// @todo validate condition for deferred triggers
return nil
}
switch t.Event {
case "manual",
"beforeCreate", "beforeUpdate", "beforeDelete",
"afterCreate", "afterUpdate", "afterDelete":
var moduleID = t.Uint64Condition()
if t.Event != "manual" && moduleID == 0 {
return errors.WithStack(automation.ErrAutomationTriggerInvalidCondition)
}
if moduleID > 0 {
if m, err := svc.mod.With(ctx).FindByID(s.NamespaceID, moduleID); err != nil {
return err
} else if !svc.ac.CanManageAutomationTriggersOnModule(ctx, m) {
return errors.WithStack(ErrNoTriggerManagementPermissions)
}
}
case "interval",
"deferred":
if s.RunAs == 0 {
return errors.WithStack(automation.ErrAutomationScriptMissingUser)
}
default:
return errors.WithStack(automation.ErrAutomationTriggerInvalidEvent)
}
return nil
}