3
0

Add template stuff to wf functions

This commit is contained in:
Tomaž Jerman
2021-03-08 17:29:07 +01:00
committed by Denis Arh
parent 7e78867733
commit 4fcc7750a6
7 changed files with 2033 additions and 1 deletions

View File

@@ -18,6 +18,250 @@ import (
var _ = context.Background
var _ = fmt.Errorf
// Document is an expression type, wrapper for *RenderedDocument type
type Document struct{ value *RenderedDocument }
// NewDocument creates new instance of Document expression type
func NewDocument(val interface{}) (*Document, error) {
if c, err := CastToDocument(val); err != nil {
return nil, fmt.Errorf("unable to create Document: %w", err)
} else {
return &Document{value: c}, nil
}
}
// Return underlying value on Document
func (t Document) Get() interface{} { return t.value }
// Return underlying value on Document
func (t Document) GetValue() *RenderedDocument { return t.value }
// Return type name
func (Document) Type() string { return "Document" }
// Convert value to *RenderedDocument
func (Document) Cast(val interface{}) (TypedValue, error) {
return NewDocument(val)
}
// Assign new value to Document
//
// value is first passed through CastToDocument
func (t *Document) Assign(val interface{}) error {
if c, err := CastToDocument(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
func (t *Document) AssignFieldValue(key string, val interface{}) error {
return assignToDocument(t.value, key, val)
}
// SelectGVal implements gval.Selector requirements
//
// It allows gval lib to access Document's underlying value (*RenderedDocument)
// and it's fields
//
func (t Document) SelectGVal(ctx context.Context, k string) (interface{}, error) {
return documentGValSelector(t.value, k)
}
// Select is field accessor for *RenderedDocument
//
// Similar to SelectGVal but returns typed values
func (t Document) Select(k string) (TypedValue, error) {
return documentTypedValueSelector(t.value, k)
}
func (t Document) Has(k string) bool {
switch k {
case "document":
return true
case "name":
return true
case "type":
return true
}
return false
}
// documentGValSelector is field accessor for *RenderedDocument
func documentGValSelector(res *RenderedDocument, k string) (interface{}, error) {
switch k {
case "document":
return res.Document, nil
case "name":
return res.Name, nil
case "type":
return res.Type, nil
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// documentTypedValueSelector is field accessor for *RenderedDocument
func documentTypedValueSelector(res *RenderedDocument, k string) (TypedValue, error) {
switch k {
case "document":
return NewReader(res.Document)
case "name":
return NewString(res.Name)
case "type":
return NewString(res.Type)
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// assignToDocument is field value setter for *RenderedDocument
func assignToDocument(res *RenderedDocument, k string, val interface{}) error {
switch k {
case "document":
aux, err := CastToReader(val)
if err != nil {
return err
}
res.Document = aux
return nil
case "name":
aux, err := CastToString(val)
if err != nil {
return err
}
res.Name = aux
return nil
case "type":
aux, err := CastToString(val)
if err != nil {
return err
}
res.Type = aux
return nil
}
return fmt.Errorf("unknown field '%s'", k)
}
// DocumentType is an expression type, wrapper for types.DocumentType type
type DocumentType struct{ value types.DocumentType }
// NewDocumentType creates new instance of DocumentType expression type
func NewDocumentType(val interface{}) (*DocumentType, error) {
if c, err := CastToDocumentType(val); err != nil {
return nil, fmt.Errorf("unable to create DocumentType: %w", err)
} else {
return &DocumentType{value: c}, nil
}
}
// Return underlying value on DocumentType
func (t DocumentType) Get() interface{} { return t.value }
// Return underlying value on DocumentType
func (t DocumentType) GetValue() types.DocumentType { return t.value }
// Return type name
func (DocumentType) Type() string { return "DocumentType" }
// Convert value to types.DocumentType
func (DocumentType) Cast(val interface{}) (TypedValue, error) {
return NewDocumentType(val)
}
// Assign new value to DocumentType
//
// value is first passed through CastToDocumentType
func (t *DocumentType) Assign(val interface{}) error {
if c, err := CastToDocumentType(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
// RenderOptions is an expression type, wrapper for map[string]string type
type RenderOptions struct{ value map[string]string }
// NewRenderOptions creates new instance of RenderOptions expression type
func NewRenderOptions(val interface{}) (*RenderOptions, error) {
if c, err := CastToRenderOptions(val); err != nil {
return nil, fmt.Errorf("unable to create RenderOptions: %w", err)
} else {
return &RenderOptions{value: c}, nil
}
}
// Return underlying value on RenderOptions
func (t RenderOptions) Get() interface{} { return t.value }
// Return underlying value on RenderOptions
func (t RenderOptions) GetValue() map[string]string { return t.value }
// Return type name
func (RenderOptions) Type() string { return "RenderOptions" }
// Convert value to map[string]string
func (RenderOptions) Cast(val interface{}) (TypedValue, error) {
return NewRenderOptions(val)
}
// Assign new value to RenderOptions
//
// value is first passed through CastToRenderOptions
func (t *RenderOptions) Assign(val interface{}) error {
if c, err := CastToRenderOptions(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
// RenderVariables is an expression type, wrapper for map[string]interface{} type
type RenderVariables struct{ value map[string]interface{} }
// NewRenderVariables creates new instance of RenderVariables expression type
func NewRenderVariables(val interface{}) (*RenderVariables, error) {
if c, err := CastToRenderVariables(val); err != nil {
return nil, fmt.Errorf("unable to create RenderVariables: %w", err)
} else {
return &RenderVariables{value: c}, nil
}
}
// Return underlying value on RenderVariables
func (t RenderVariables) Get() interface{} { return t.value }
// Return underlying value on RenderVariables
func (t RenderVariables) GetValue() map[string]interface{} { return t.value }
// Return type name
func (RenderVariables) Type() string { return "RenderVariables" }
// Convert value to map[string]interface{}
func (RenderVariables) Cast(val interface{}) (TypedValue, error) {
return NewRenderVariables(val)
}
// Assign new value to RenderVariables
//
// value is first passed through CastToRenderVariables
func (t *RenderVariables) Assign(val interface{}) error {
if c, err := CastToRenderVariables(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
// Role is an expression type, wrapper for *types.Role type
type Role struct{ value *types.Role }
@@ -188,6 +432,356 @@ func assignToRole(res *types.Role, k string, val interface{}) error {
return fmt.Errorf("unknown field '%s'", k)
}
// Template is an expression type, wrapper for *types.Template type
type Template struct{ value *types.Template }
// NewTemplate creates new instance of Template expression type
func NewTemplate(val interface{}) (*Template, error) {
if c, err := CastToTemplate(val); err != nil {
return nil, fmt.Errorf("unable to create Template: %w", err)
} else {
return &Template{value: c}, nil
}
}
// Return underlying value on Template
func (t Template) Get() interface{} { return t.value }
// Return underlying value on Template
func (t Template) GetValue() *types.Template { return t.value }
// Return type name
func (Template) Type() string { return "Template" }
// Convert value to *types.Template
func (Template) Cast(val interface{}) (TypedValue, error) {
return NewTemplate(val)
}
// Assign new value to Template
//
// value is first passed through CastToTemplate
func (t *Template) Assign(val interface{}) error {
if c, err := CastToTemplate(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
func (t *Template) AssignFieldValue(key string, val interface{}) error {
return assignToTemplate(t.value, key, val)
}
// SelectGVal implements gval.Selector requirements
//
// It allows gval lib to access Template's underlying value (*types.Template)
// and it's fields
//
func (t Template) SelectGVal(ctx context.Context, k string) (interface{}, error) {
return templateGValSelector(t.value, k)
}
// Select is field accessor for *types.Template
//
// Similar to SelectGVal but returns typed values
func (t Template) Select(k string) (TypedValue, error) {
return templateTypedValueSelector(t.value, k)
}
func (t Template) Has(k string) bool {
switch k {
case "ID":
return true
case "handle":
return true
case "language":
return true
case "type":
return true
case "partial":
return true
case "meta":
return true
case "template":
return true
case "labels":
return true
case "ownerID":
return true
case "createdAt":
return true
case "updatedAt":
return true
case "deletedAt":
return true
case "lastUsedAt":
return true
}
return false
}
// templateGValSelector is field accessor for *types.Template
func templateGValSelector(res *types.Template, k string) (interface{}, error) {
switch k {
case "ID":
return res.ID, nil
case "handle":
return res.Handle, nil
case "language":
return res.Language, nil
case "type":
return res.Type, nil
case "partial":
return res.Partial, nil
case "meta":
return res.Meta, nil
case "template":
return res.Template, nil
case "labels":
return res.Labels, nil
case "ownerID":
return res.OwnerID, nil
case "createdAt":
return res.CreatedAt, nil
case "updatedAt":
return res.UpdatedAt, nil
case "deletedAt":
return res.DeletedAt, nil
case "lastUsedAt":
return res.LastUsedAt, nil
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// templateTypedValueSelector is field accessor for *types.Template
func templateTypedValueSelector(res *types.Template, k string) (TypedValue, error) {
switch k {
case "ID":
return NewID(res.ID)
case "handle":
return NewHandle(res.Handle)
case "language":
return NewString(res.Language)
case "type":
return NewDocumentType(res.Type)
case "partial":
return NewBoolean(res.Partial)
case "meta":
return NewTemplateMeta(res.Meta)
case "template":
return NewString(res.Template)
case "labels":
return NewKV(res.Labels)
case "ownerID":
return NewID(res.OwnerID)
case "createdAt":
return NewDateTime(res.CreatedAt)
case "updatedAt":
return NewDateTime(res.UpdatedAt)
case "deletedAt":
return NewDateTime(res.DeletedAt)
case "lastUsedAt":
return NewDateTime(res.LastUsedAt)
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// assignToTemplate is field value setter for *types.Template
func assignToTemplate(res *types.Template, k string, val interface{}) error {
switch k {
case "ID":
return fmt.Errorf("field '%s' is read-only", k)
case "handle":
aux, err := CastToHandle(val)
if err != nil {
return err
}
res.Handle = aux
return nil
case "language":
aux, err := CastToString(val)
if err != nil {
return err
}
res.Language = aux
return nil
case "type":
aux, err := CastToDocumentType(val)
if err != nil {
return err
}
res.Type = aux
return nil
case "partial":
aux, err := CastToBoolean(val)
if err != nil {
return err
}
res.Partial = aux
return nil
case "meta":
aux, err := CastToTemplateMeta(val)
if err != nil {
return err
}
res.Meta = aux
return nil
case "template":
aux, err := CastToString(val)
if err != nil {
return err
}
res.Template = aux
return nil
case "labels":
aux, err := CastToKV(val)
if err != nil {
return err
}
res.Labels = aux
return nil
case "ownerID":
return fmt.Errorf("field '%s' is read-only", k)
case "createdAt":
return fmt.Errorf("field '%s' is read-only", k)
case "updatedAt":
return fmt.Errorf("field '%s' is read-only", k)
case "deletedAt":
return fmt.Errorf("field '%s' is read-only", k)
case "lastUsedAt":
return fmt.Errorf("field '%s' is read-only", k)
}
return fmt.Errorf("unknown field '%s'", k)
}
// TemplateMeta is an expression type, wrapper for types.TemplateMeta type
type TemplateMeta struct{ value types.TemplateMeta }
// NewTemplateMeta creates new instance of TemplateMeta expression type
func NewTemplateMeta(val interface{}) (*TemplateMeta, error) {
if c, err := CastToTemplateMeta(val); err != nil {
return nil, fmt.Errorf("unable to create TemplateMeta: %w", err)
} else {
return &TemplateMeta{value: c}, nil
}
}
// Return underlying value on TemplateMeta
func (t TemplateMeta) Get() interface{} { return t.value }
// Return underlying value on TemplateMeta
func (t TemplateMeta) GetValue() types.TemplateMeta { return t.value }
// Return type name
func (TemplateMeta) Type() string { return "TemplateMeta" }
// Convert value to types.TemplateMeta
func (TemplateMeta) Cast(val interface{}) (TypedValue, error) {
return NewTemplateMeta(val)
}
// Assign new value to TemplateMeta
//
// value is first passed through CastToTemplateMeta
func (t *TemplateMeta) Assign(val interface{}) error {
if c, err := CastToTemplateMeta(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
func (t *TemplateMeta) AssignFieldValue(key string, val interface{}) error {
return assignToTemplateMeta(t.value, key, val)
}
// SelectGVal implements gval.Selector requirements
//
// It allows gval lib to access TemplateMeta's underlying value (types.TemplateMeta)
// and it's fields
//
func (t TemplateMeta) SelectGVal(ctx context.Context, k string) (interface{}, error) {
return templateMetaGValSelector(t.value, k)
}
// Select is field accessor for types.TemplateMeta
//
// Similar to SelectGVal but returns typed values
func (t TemplateMeta) Select(k string) (TypedValue, error) {
return templateMetaTypedValueSelector(t.value, k)
}
func (t TemplateMeta) Has(k string) bool {
switch k {
case "short":
return true
case "description":
return true
}
return false
}
// templateMetaGValSelector is field accessor for types.TemplateMeta
func templateMetaGValSelector(res types.TemplateMeta, k string) (interface{}, error) {
switch k {
case "short":
return res.Short, nil
case "description":
return res.Description, nil
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// templateMetaTypedValueSelector is field accessor for types.TemplateMeta
func templateMetaTypedValueSelector(res types.TemplateMeta, k string) (TypedValue, error) {
switch k {
case "short":
return NewString(res.Short)
case "description":
return NewString(res.Description)
}
return nil, fmt.Errorf("unknown field '%s'", k)
}
// assignToTemplateMeta is field value setter for types.TemplateMeta
func assignToTemplateMeta(res types.TemplateMeta, k string, val interface{}) error {
switch k {
case "short":
aux, err := CastToString(val)
if err != nil {
return err
}
res.Short = aux
return nil
case "description":
aux, err := CastToString(val)
if err != nil {
return err
}
res.Description = aux
return nil
}
return fmt.Errorf("unknown field '%s'", k)
}
// User is an expression type, wrapper for *types.User type
type User struct{ value *types.User }

View File

@@ -2,8 +2,19 @@ package automation
import (
"fmt"
"io"
"github.com/cortezaproject/corteza-server/pkg/expr"
"github.com/cortezaproject/corteza-server/system/types"
"github.com/spf13/cast"
)
type (
RenderedDocument struct {
Document io.Reader
Name string
Type string
}
)
func CastToUser(val interface{}) (out *types.User, err error) {
@@ -39,3 +50,97 @@ func CastToRole(val interface{}) (out *types.Role, err error) {
return nil, fmt.Errorf("unable to cast type %T to %T", val, out)
}
}
func CastToTemplate(val interface{}) (out *types.Template, err error) {
switch val := val.(type) {
case expr.Iterator:
out = &types.Template{}
return out, val.Each(func(k string, v expr.TypedValue) error {
return assignToTemplate(out, k, v)
})
}
switch val := expr.UntypedValue(val).(type) {
case *types.Template:
return val, nil
case nil:
return &types.Template{}, nil
default:
return nil, fmt.Errorf("unable to cast type %T to %T", val, out)
}
}
func CastToTemplateMeta(val interface{}) (out types.TemplateMeta, err error) {
switch val := val.(type) {
case expr.Iterator:
out = types.TemplateMeta{}
return out, val.Each(func(k string, v expr.TypedValue) error {
return assignToTemplateMeta(out, k, v)
})
}
switch val := expr.UntypedValue(val).(type) {
case types.TemplateMeta:
return val, nil
default:
return types.TemplateMeta{}, fmt.Errorf("unable to cast type %T to %T", val, out)
}
}
func CastToDocument(val interface{}) (out *RenderedDocument, err error) {
switch val := val.(type) {
case expr.Iterator:
out = &RenderedDocument{}
return out, val.Each(func(k string, v expr.TypedValue) error {
return assignToDocument(out, k, v)
})
}
switch val := expr.UntypedValue(val).(type) {
case *RenderedDocument:
return val, nil
default:
return nil, fmt.Errorf("unable to cast type %T to %T", val, out)
}
}
func CastToDocumentType(val interface{}) (out types.DocumentType, err error) {
switch val := val.(type) {
case string:
return types.DocumentType(val), nil
case *expr.String:
return types.DocumentType(val.GetValue()), nil
default:
return "", fmt.Errorf("unable to cast type %T to %T", val, out)
}
}
func CastToRenderOptions(val interface{}) (out map[string]string, err error) {
switch val := expr.UntypedValue(val).(type) {
case map[string]string:
return val, nil
case nil:
return make(map[string]string), nil
default:
out, err = cast.ToStringMapStringE(val)
if err != nil {
return nil, fmt.Errorf("unable to cast type %T to %T", val, out)
}
return out, nil
}
}
func CastToRenderVariables(val interface{}) (out map[string]interface{}, err error) {
switch val := expr.UntypedValue(val).(type) {
case map[string]interface{}:
return val, nil
case nil:
return make(map[string]interface{}), nil
default:
out, err = cast.ToStringMapE(val)
if err != nil {
return nil, fmt.Errorf("unable to cast type %T to %T", val, out)
}
return out, nil
}
}

View File

@@ -3,6 +3,25 @@ imports:
- github.com/cortezaproject/corteza-server/system/types
types:
Template:
as: '*types.Template'
struct:
- { name: 'ID', exprType: 'ID', goType: 'uint64', mode: ro}
- { name: 'handle', exprType: 'Handle', goType: 'string' }
- { name: 'language', exprType: 'String', goType: 'string' }
- { name: 'type', exprType: 'DocumentType', goType: 'types.DocumentType' }
- { name: 'partial', exprType: 'Boolean', goType: 'bool' }
- { name: 'meta', exprType: 'TemplateMeta', goType: 'types.TemplateMeta' }
- { name: 'template', exprType: 'String', goType: 'string' }
- { name: 'labels', exprType: 'KV', goType: 'map[string]string' }
- { name: 'ownerID', exprType: 'ID', goType: 'uint64', mode: ro}
- { name: 'createdAt', exprType: 'DateTime', goType: 'time.Time', mode: ro}
- { name: 'updatedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
- { name: 'deletedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
- { name: 'lastUsedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
User:
as: '*types.User'
struct:
@@ -23,8 +42,26 @@ types:
- { name: 'ID', exprType: 'ID', goType: 'uint64', mode: ro }
- { name: 'name', exprType: 'String', goType: 'string' }
- { name: 'handle', exprType: 'Handle', goType: 'string' }
- { name: 'labels', exprType: 'KV', goType: 'map[string]''string' }
- { name: 'labels', exprType: 'KV', goType: 'map[string]string' }
- { name: 'createdAt', exprType: 'DateTime', goType: 'time.Time', mode: ro}
- { name: 'updatedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
- { name: 'archivedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
- { name: 'deletedAt', exprType: 'DateTime', goType: '*time.Time', mode: ro }
DocumentType:
as: 'types.DocumentType'
TemplateMeta:
as: 'types.TemplateMeta'
struct:
- { name: 'short', exprType: 'String', goType: 'string'}
- { name: 'description', exprType: 'String', goType: 'string'}
Document:
as: '*RenderedDocument'
struct:
- { name: 'document', exprType: 'Reader', goType: 'io.Reader' }
- { name: 'name', exprType: 'string', goType: 'string' }
- { name: 'type', exprType: 'string', goType: 'string' }
RenderVariables:
as: 'map[string]interface{}'
RenderOptions:
as: 'map[string]string'

View File

@@ -0,0 +1,879 @@
package automation
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
// Definitions file that controls how this file is generated:
// system/automation/templates_handler.yaml
import (
"context"
atypes "github.com/cortezaproject/corteza-server/automation/types"
"github.com/cortezaproject/corteza-server/pkg/expr"
"github.com/cortezaproject/corteza-server/pkg/wfexec"
"github.com/cortezaproject/corteza-server/system/types"
)
var _ wfexec.ExecResponse
type (
templatesHandlerRegistry interface {
AddFunctions(ff ...*atypes.Function)
Type(ref string) expr.Type
}
)
func (h templatesHandler) register() {
h.reg.AddFunctions(
h.Lookup(),
h.Search(),
h.Each(),
h.Create(),
h.Update(),
h.Delete(),
h.Recover(),
h.Render(),
)
}
type (
templatesLookupArgs struct {
hasLookup bool
Lookup interface{}
lookupID uint64
lookupHandle string
lookupRes *types.Template
}
templatesLookupResults struct {
Template *types.Template
}
)
func (a templatesLookupArgs) GetLookup() (bool, uint64, string, *types.Template) {
return a.hasLookup, a.lookupID, a.lookupHandle, a.lookupRes
}
// Lookup function Looks-up for template by ID
//
// expects implementation of lookup function:
// func (h templatesHandler) lookup(ctx context.Context, args *templatesLookupArgs) (results *templatesLookupResults, err error) {
// return
// }
func (h templatesHandler) Lookup() *atypes.Function {
return &atypes.Function{
Ref: "templatesLookup",
Kind: "function",
Labels: map[string]string{"templates": "step,workflow"},
Meta: &atypes.FunctionMeta{
Short: "Looks-up for template by ID",
},
Parameters: []*atypes.Param{
{
Name: "lookup",
Types: []string{"ID", "Handle", "Template"}, Required: true,
},
},
Results: []*atypes.Param{
{
Name: "template",
Types: []string{"Template"},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &templatesLookupArgs{
hasLookup: in.Has("lookup"),
}
)
if err = in.Decode(args); err != nil {
return
}
// Converting Lookup argument
if args.hasLookup {
aux := expr.Must(expr.Select(in, "lookup"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.lookupID = aux.Get().(uint64)
case h.reg.Type("Handle").Type():
args.lookupHandle = aux.Get().(string)
case h.reg.Type("Template").Type():
args.lookupRes = aux.Get().(*types.Template)
}
}
var results *templatesLookupResults
if results, err = h.lookup(ctx, args); err != nil {
return
}
out = &expr.Vars{}
{
// converting results.Template (*types.Template) to Template
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("Template").Cast(results.Template); err != nil {
return
} else if err = expr.Assign(out, "template", tval); err != nil {
return
}
}
return
},
}
}
type (
templatesSearchArgs struct {
hasHandle bool
Handle string
hasType bool
Type string
hasOwnerID bool
OwnerID uint64
hasPartial bool
Partial bool
hasLabels bool
Labels map[string]string
hasSort bool
Sort string
hasLimit bool
Limit uint64
hasIncTotal bool
IncTotal bool
hasIncPageNavigation bool
IncPageNavigation bool
hasPageCursor bool
PageCursor string
}
templatesSearchResults struct {
Templates []*types.Template
Total uint64
PageCursor string
}
)
// Search function Searches for templates and returns them
//
// expects implementation of search function:
// func (h templatesHandler) search(ctx context.Context, args *templatesSearchArgs) (results *templatesSearchResults, err error) {
// return
// }
func (h templatesHandler) Search() *atypes.Function {
return &atypes.Function{
Ref: "templatesSearch",
Kind: "function",
Labels: map[string]string{"templates": "step,workflow"},
Meta: &atypes.FunctionMeta{
Short: "Searches for templates and returns them",
},
Parameters: []*atypes.Param{
{
Name: "handle",
Types: []string{"String"},
},
{
Name: "type",
Types: []string{"String"},
},
{
Name: "ownerID",
Types: []string{"ID"},
},
{
Name: "partial",
Types: []string{"Boolean"},
},
{
Name: "labels",
Types: []string{"KV"},
},
{
Name: "sort",
Types: []string{"String"},
},
{
Name: "limit",
Types: []string{"UnsignedInteger"},
},
{
Name: "incTotal",
Types: []string{"Boolean"},
},
{
Name: "incPageNavigation",
Types: []string{"Boolean"},
},
{
Name: "pageCursor",
Types: []string{"String"},
},
},
Results: []*atypes.Param{
{
Name: "templates",
Types: []string{"Template"},
IsArray: true,
},
{
Name: "total",
Types: []string{"UnsignedInteger"},
},
{
Name: "pageCursor",
Types: []string{"String"},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &templatesSearchArgs{
hasHandle: in.Has("handle"),
hasType: in.Has("type"),
hasOwnerID: in.Has("ownerID"),
hasPartial: in.Has("partial"),
hasLabels: in.Has("labels"),
hasSort: in.Has("sort"),
hasLimit: in.Has("limit"),
hasIncTotal: in.Has("incTotal"),
hasIncPageNavigation: in.Has("incPageNavigation"),
hasPageCursor: in.Has("pageCursor"),
}
)
if err = in.Decode(args); err != nil {
return
}
var results *templatesSearchResults
if results, err = h.search(ctx, args); err != nil {
return
}
out = &expr.Vars{}
{
// converting results.Templates (*types.Template) to Array (of Template)
var (
tval expr.TypedValue
tarr = make([]expr.TypedValue, len(results.Templates))
)
for i := range results.Templates {
if tarr[i], err = h.reg.Type("Template").Cast(results.Templates[i]); err != nil {
return
}
}
if tval, err = expr.NewArray(tarr); err != nil {
return
} else if err = expr.Assign(out, "templates", tval); err != nil {
return
}
}
{
// converting results.Total (uint64) to UnsignedInteger
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("UnsignedInteger").Cast(results.Total); err != nil {
return
} else if err = expr.Assign(out, "total", tval); err != nil {
return
}
}
{
// converting results.PageCursor (string) to String
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("String").Cast(results.PageCursor); err != nil {
return
} else if err = expr.Assign(out, "pageCursor", tval); err != nil {
return
}
}
return
},
}
}
type (
templatesEachArgs struct {
hasHandle bool
Handle string
hasType bool
Type string
hasOwnerID bool
OwnerID uint64
hasPartial bool
Partial bool
hasLabels bool
Labels map[string]string
hasSort bool
Sort string
hasLimit bool
Limit uint64
hasIncTotal bool
IncTotal bool
hasIncPageNavigation bool
IncPageNavigation bool
hasPageCursor bool
PageCursor string
}
templatesEachResults struct {
Template *types.Template
Total uint64
}
)
// Each function Searches for templates and iterates over results
//
// expects implementation of each function:
// func (h templatesHandler) each(ctx context.Context, args *templatesEachArgs) (results *templatesEachResults, err error) {
// return
// }
func (h templatesHandler) Each() *atypes.Function {
return &atypes.Function{
Ref: "templatesEach",
Kind: "iterator",
Labels: map[string]string{"templates": "step,workflow"},
Meta: &atypes.FunctionMeta{
Short: "Searches for templates and iterates over results",
},
Parameters: []*atypes.Param{
{
Name: "handle",
Types: []string{"String"},
},
{
Name: "type",
Types: []string{"String"},
},
{
Name: "ownerID",
Types: []string{"ID"},
},
{
Name: "partial",
Types: []string{"Boolean"},
},
{
Name: "labels",
Types: []string{"KV"},
},
{
Name: "sort",
Types: []string{"String"},
},
{
Name: "limit",
Types: []string{"UnsignedInteger"},
},
{
Name: "incTotal",
Types: []string{"Boolean"},
},
{
Name: "incPageNavigation",
Types: []string{"Boolean"},
},
{
Name: "pageCursor",
Types: []string{"String"},
},
},
Results: []*atypes.Param{
{
Name: "template",
Types: []string{"Template"},
},
{
Name: "total",
Types: []string{"UnsignedInteger"},
},
},
Iterator: func(ctx context.Context, in *expr.Vars) (out wfexec.IteratorHandler, err error) {
var (
args = &templatesEachArgs{
hasHandle: in.Has("handle"),
hasType: in.Has("type"),
hasOwnerID: in.Has("ownerID"),
hasPartial: in.Has("partial"),
hasLabels: in.Has("labels"),
hasSort: in.Has("sort"),
hasLimit: in.Has("limit"),
hasIncTotal: in.Has("incTotal"),
hasIncPageNavigation: in.Has("incPageNavigation"),
hasPageCursor: in.Has("pageCursor"),
}
)
if err = in.Decode(args); err != nil {
return
}
return h.each(ctx, args)
},
}
}
type (
templatesCreateArgs struct {
hasTemplate bool
Template *types.Template
}
templatesCreateResults struct {
Template *types.Template
}
)
// Create function Creates new template
//
// expects implementation of create function:
// func (h templatesHandler) create(ctx context.Context, args *templatesCreateArgs) (results *templatesCreateResults, err error) {
// return
// }
func (h templatesHandler) Create() *atypes.Function {
return &atypes.Function{
Ref: "templatesCreate",
Kind: "function",
Labels: map[string]string{"templates": "step,workflow"},
Meta: &atypes.FunctionMeta{
Short: "Creates new template",
},
Parameters: []*atypes.Param{
{
Name: "template",
Types: []string{"Template"}, Required: true,
},
},
Results: []*atypes.Param{
{
Name: "template",
Types: []string{"Template"},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &templatesCreateArgs{
hasTemplate: in.Has("template"),
}
)
if err = in.Decode(args); err != nil {
return
}
var results *templatesCreateResults
if results, err = h.create(ctx, args); err != nil {
return
}
out = &expr.Vars{}
{
// converting results.Template (*types.Template) to Template
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("Template").Cast(results.Template); err != nil {
return
} else if err = expr.Assign(out, "template", tval); err != nil {
return
}
}
return
},
}
}
type (
templatesUpdateArgs struct {
hasTemplate bool
Template *types.Template
}
templatesUpdateResults struct {
Template *types.Template
}
)
// Update function Updates exiting template
//
// expects implementation of update function:
// func (h templatesHandler) update(ctx context.Context, args *templatesUpdateArgs) (results *templatesUpdateResults, err error) {
// return
// }
func (h templatesHandler) Update() *atypes.Function {
return &atypes.Function{
Ref: "templatesUpdate",
Kind: "function",
Labels: map[string]string{"templates": "step,workflow"},
Meta: &atypes.FunctionMeta{
Short: "Updates exiting template",
},
Parameters: []*atypes.Param{
{
Name: "template",
Types: []string{"Template"}, Required: true,
},
},
Results: []*atypes.Param{
{
Name: "template",
Types: []string{"Template"},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &templatesUpdateArgs{
hasTemplate: in.Has("template"),
}
)
if err = in.Decode(args); err != nil {
return
}
var results *templatesUpdateResults
if results, err = h.update(ctx, args); err != nil {
return
}
out = &expr.Vars{}
{
// converting results.Template (*types.Template) to Template
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("Template").Cast(results.Template); err != nil {
return
} else if err = expr.Assign(out, "template", tval); err != nil {
return
}
}
return
},
}
}
type (
templatesDeleteArgs struct {
hasLookup bool
Lookup interface{}
lookupID uint64
lookupHandle string
lookupRes *types.Template
}
)
func (a templatesDeleteArgs) GetLookup() (bool, uint64, string, *types.Template) {
return a.hasLookup, a.lookupID, a.lookupHandle, a.lookupRes
}
// Delete function Deletes template
//
// expects implementation of delete function:
// func (h templatesHandler) delete(ctx context.Context, args *templatesDeleteArgs) (err error) {
// return
// }
func (h templatesHandler) Delete() *atypes.Function {
return &atypes.Function{
Ref: "templatesDelete",
Kind: "function",
Labels: map[string]string{"delete": "step", "templates": "step,workflow"},
Meta: &atypes.FunctionMeta{
Short: "Deletes template",
},
Parameters: []*atypes.Param{
{
Name: "lookup",
Types: []string{"ID", "Handle", "Template"}, Required: true,
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &templatesDeleteArgs{
hasLookup: in.Has("lookup"),
}
)
if err = in.Decode(args); err != nil {
return
}
// Converting Lookup argument
if args.hasLookup {
aux := expr.Must(expr.Select(in, "lookup"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.lookupID = aux.Get().(uint64)
case h.reg.Type("Handle").Type():
args.lookupHandle = aux.Get().(string)
case h.reg.Type("Template").Type():
args.lookupRes = aux.Get().(*types.Template)
}
}
return out, h.delete(ctx, args)
},
}
}
type (
templatesRecoverArgs struct {
hasLookup bool
Lookup interface{}
lookupID uint64
lookupHandle string
lookupRes *types.Template
}
)
func (a templatesRecoverArgs) GetLookup() (bool, uint64, string, *types.Template) {
return a.hasLookup, a.lookupID, a.lookupHandle, a.lookupRes
}
// Recover function Recovers deleted template
//
// expects implementation of recover function:
// func (h templatesHandler) recover(ctx context.Context, args *templatesRecoverArgs) (err error) {
// return
// }
func (h templatesHandler) Recover() *atypes.Function {
return &atypes.Function{
Ref: "templatesRecover",
Kind: "function",
Labels: map[string]string{"recover": "step", "templates": "step,workflow"},
Meta: &atypes.FunctionMeta{
Short: "Recovers deleted template",
},
Parameters: []*atypes.Param{
{
Name: "lookup",
Types: []string{"ID", "Handle", "Template"}, Required: true,
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &templatesRecoverArgs{
hasLookup: in.Has("lookup"),
}
)
if err = in.Decode(args); err != nil {
return
}
// Converting Lookup argument
if args.hasLookup {
aux := expr.Must(expr.Select(in, "lookup"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.lookupID = aux.Get().(uint64)
case h.reg.Type("Handle").Type():
args.lookupHandle = aux.Get().(string)
case h.reg.Type("Template").Type():
args.lookupRes = aux.Get().(*types.Template)
}
}
return out, h.recover(ctx, args)
},
}
}
type (
templatesRenderArgs struct {
hasLookup bool
Lookup interface{}
lookupID uint64
lookupHandle string
lookupRes *types.Template
hasDocumentName bool
DocumentName string
hasDocumentType bool
DocumentType string
hasVariables bool
Variables map[string]interface{}
hasOptions bool
Options map[string]string
}
templatesRenderResults struct {
Document *RenderedDocument
}
)
func (a templatesRenderArgs) GetLookup() (bool, uint64, string, *types.Template) {
return a.hasLookup, a.lookupID, a.lookupHandle, a.lookupRes
}
// Render function Renders a document from template
//
// expects implementation of render function:
// func (h templatesHandler) render(ctx context.Context, args *templatesRenderArgs) (results *templatesRenderResults, err error) {
// return
// }
func (h templatesHandler) Render() *atypes.Function {
return &atypes.Function{
Ref: "templatesRender",
Kind: "function",
Labels: map[string]string{"render": "step", "templates": "step,workflow"},
Meta: &atypes.FunctionMeta{
Short: "Renders a document from template",
},
Parameters: []*atypes.Param{
{
Name: "lookup",
Types: []string{"ID", "Handle", "Template"}, Required: true,
},
{
Name: "documentName",
Types: []string{"String"},
},
{
Name: "documentType",
Types: []string{"String"},
},
{
Name: "variables",
Types: []string{"RenderVariables"},
},
{
Name: "options",
Types: []string{"RenderOptions"},
},
},
Results: []*atypes.Param{
{
Name: "document",
Types: []string{"Document"},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &templatesRenderArgs{
hasLookup: in.Has("lookup"),
hasDocumentName: in.Has("documentName"),
hasDocumentType: in.Has("documentType"),
hasVariables: in.Has("variables"),
hasOptions: in.Has("options"),
}
)
if err = in.Decode(args); err != nil {
return
}
// Converting Lookup argument
if args.hasLookup {
aux := expr.Must(expr.Select(in, "lookup"))
switch aux.Type() {
case h.reg.Type("ID").Type():
args.lookupID = aux.Get().(uint64)
case h.reg.Type("Handle").Type():
args.lookupHandle = aux.Get().(string)
case h.reg.Type("Template").Type():
args.lookupRes = aux.Get().(*types.Template)
}
}
var results *templatesRenderResults
if results, err = h.render(ctx, args); err != nil {
return
}
out = &expr.Vars{}
{
// converting results.Document (*RenderedDocument) to Document
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("Document").Cast(results.Document); err != nil {
return
} else if err = expr.Assign(out, "document", tval); err != nil {
return
}
}
return
},
}
}

View File

@@ -0,0 +1,247 @@
package automation
import (
"context"
"fmt"
"io"
. "github.com/cortezaproject/corteza-server/pkg/expr"
"github.com/cortezaproject/corteza-server/pkg/wfexec"
"github.com/cortezaproject/corteza-server/system/types"
"github.com/spf13/cast"
)
type (
templateService interface {
FindByID(ctx context.Context, ID uint64) (*types.Template, error)
FindByHandle(ct context.Context, handle string) (*types.Template, error)
FindByAny(ctx context.Context, identifier interface{}) (*types.Template, error)
Search(context.Context, types.TemplateFilter) (types.TemplateSet, types.TemplateFilter, error)
Create(ctx context.Context, tpl *types.Template) (*types.Template, error)
Update(ctx context.Context, tpl *types.Template) (*types.Template, error)
DeleteByID(ctx context.Context, ID uint64) error
UndeleteByID(ctx context.Context, ID uint64) error
Render(ctx context.Context, templateID uint64, dstType string, variables map[string]interface{}, options map[string]string) (io.ReadSeeker, error)
}
templatesHandler struct {
reg templatesHandlerRegistry
tSvc templateService
}
templateSetIterator struct {
ptr int
set types.TemplateSet
filter types.TemplateFilter
}
templateLookup interface {
GetLookup() (bool, uint64, string, *types.Template)
}
)
func TemplatesHandler(reg templatesHandlerRegistry, tSvc templateService) *templatesHandler {
h := &templatesHandler{
reg: reg,
tSvc: tSvc,
}
h.register()
return h
}
func (h templatesHandler) lookup(ctx context.Context, args *templatesLookupArgs) (results *templatesLookupResults, err error) {
results = &templatesLookupResults{}
results.Template, err = lookupTemplate(ctx, h.tSvc, args)
return
}
func (h templatesHandler) search(ctx context.Context, args *templatesSearchArgs) (results *templatesSearchResults, err error) {
results = &templatesSearchResults{}
var (
f = types.TemplateFilter{
Handle: args.Handle,
Type: args.Type,
OwnerID: args.OwnerID,
Partial: args.Partial,
Labels: args.Labels,
}
)
if args.hasSort {
if err = f.Sort.Set(args.Sort); err != nil {
return
}
}
if args.hasPageCursor {
if err = f.PageCursor.Decode(args.PageCursor); err != nil {
return
}
}
if args.hasLabels {
f.Labels = args.Labels
}
if args.hasLimit {
f.Limit = uint(args.Limit)
}
results.Templates, _, err = h.tSvc.Search(ctx, f)
return
}
func (h templatesHandler) each(ctx context.Context, args *templatesEachArgs) (out wfexec.IteratorHandler, err error) {
var (
i = &templateSetIterator{}
f = types.TemplateFilter{
Handle: args.Handle,
Type: args.Type,
OwnerID: args.OwnerID,
Partial: args.Partial,
Labels: args.Labels,
}
)
if args.hasSort {
if err = f.Sort.Set(args.Sort); err != nil {
return
}
}
if args.hasPageCursor {
if err = f.PageCursor.Decode(args.PageCursor); err != nil {
return
}
}
if args.hasLabels {
f.Labels = args.Labels
}
if args.hasLimit {
f.Limit = uint(args.Limit)
}
i.set, i.filter, err = h.tSvc.Search(ctx, f)
return i, err
}
func (h templatesHandler) create(ctx context.Context, args *templatesCreateArgs) (results *templatesCreateResults, err error) {
results = &templatesCreateResults{}
results.Template, err = h.tSvc.Create(ctx, args.Template)
return
}
func (h templatesHandler) update(ctx context.Context, args *templatesUpdateArgs) (results *templatesUpdateResults, err error) {
results = &templatesUpdateResults{}
results.Template, err = h.tSvc.Update(ctx, args.Template)
return
}
func (h templatesHandler) delete(ctx context.Context, args *templatesDeleteArgs) error {
if id, err := getTemplateID(ctx, h.tSvc, args); err != nil {
return err
} else {
return h.tSvc.DeleteByID(ctx, id)
}
}
func (h templatesHandler) recover(ctx context.Context, args *templatesRecoverArgs) error {
if id, err := getTemplateID(ctx, h.tSvc, args); err != nil {
return err
} else {
return h.tSvc.UndeleteByID(ctx, id)
}
}
func (h templatesHandler) render(ctx context.Context, args *templatesRenderArgs) (*templatesRenderResults, error) {
var err error
vars := make(map[string]interface{})
if args.hasVariables {
vars, err = cast.ToStringMapE(args.Variables)
if err != nil {
return nil, err
}
}
opts := make(map[string]string)
if args.hasOptions {
opts, err = cast.ToStringMapStringE(args.Options)
if err != nil {
return nil, err
}
}
tplID, err := getTemplateID(ctx, h.tSvc, args)
if err != nil {
return nil, err
}
doc, err := h.tSvc.Render(ctx, tplID, args.DocumentType, vars, opts)
if err != nil {
return nil, err
}
rr := &templatesRenderResults{
Document: &RenderedDocument{
Document: doc,
Name: args.DocumentName,
Type: args.DocumentType,
},
}
return rr, nil
}
func (i *templateSetIterator) More(context.Context, *Vars) (bool, error) {
return i.ptr < len(i.set), nil
}
func (i *templateSetIterator) Start(context.Context, *Vars) error { i.ptr = 0; return nil }
func (i *templateSetIterator) Next(context.Context, *Vars) (*Vars, error) {
out := RVars{
"template": Must(NewTemplate(i.set[i.ptr])),
"total": Must(NewUnsignedInteger(i.filter.Total)),
}
i.ptr++
return out.Vars(), nil
}
func lookupTemplate(ctx context.Context, svc templateService, args templateLookup) (*types.Template, error) {
_, ID, handle, template := args.GetLookup()
switch {
case template != nil:
return template, nil
case ID > 0:
return svc.FindByID(ctx, ID)
case len(handle) > 0:
return svc.FindByHandle(ctx, handle)
}
return nil, fmt.Errorf("empty lookup params")
}
func getTemplateID(ctx context.Context, svc templateService, args templateLookup) (uint64, error) {
_, ID, _, _ := args.GetLookup()
if ID > 0 {
return ID, nil
}
tpl, err := lookupTemplate(ctx, svc, args)
if err != nil {
return 0, err
}
return tpl.ID, nil
}

View File

@@ -0,0 +1,161 @@
imports:
- github.com/cortezaproject/corteza-server/system/types
snippets:
lookup: &lookup
required: true
types:
- { wf: ID }
- { wf: Handle }
- { wf: Template, suffix: res }
template: &template
types:
- { wf: Template }
rvTemplate: &rvTemplate
wf: Template
rvDocument: &rvDocument
wf: Document
rvTotal: &rvTotal
wf: UnsignedInteger
rvPageCursor: &rvPageCursor
wf: String
filterParams: &filterParams
handle:
types:
- { wf: String }
type:
types:
- { wf: String }
ownerID:
types:
- { wf: ID }
partial:
types:
- { wf: Boolean }
labels:
types:
- { wf: KV }
sort:
types:
- { wf: String }
limit:
types:
- { wf: UnsignedInteger }
incTotal:
types:
- { wf: Boolean }
incPageNavigation:
types:
- { wf: Boolean }
pageCursor:
types:
- { wf: String }
labels: &labels
templates: "step,workflow"
functions:
lookup:
meta:
short: Looks-up for template by ID
params:
lookup: *lookup
labels:
<<: *labels
results:
template: *rvTemplate
search:
meta:
short: Searches for templates and returns them
params: *filterParams
labels:
<<: *labels
results:
templates:
<<: *rvTemplate
isArray: true
total: *rvTotal
pageCursor: *rvPageCursor
each:
kind: iterator
meta:
short: Searches for templates and iterates over results
params: *filterParams
labels:
<<: *labels
results:
template: *rvTemplate
total: *rvTotal
create:
meta:
short: Creates new template
labels:
<<: *labels
params:
template:
<<: *template
required: true
results:
template: *rvTemplate
update:
meta:
short: Updates exiting template
labels:
<<: *labels
params:
template:
<<: *template
required: true
results:
template: *rvTemplate
delete:
labels:
<<: *labels
delete: "step"
meta:
short: Deletes template
params:
lookup: *lookup
recover:
meta:
short: Recovers deleted template
labels:
<<: *labels
recover: "step"
params:
lookup: *lookup
render:
meta:
short: Renders a document from template
labels:
<<: *labels
render: "step"
params:
lookup: *lookup
documentName:
types:
- { wf: String }
documentType:
types:
- { wf: String }
variables:
types:
- { wf: RenderVariables }
options:
types:
- { wf: RenderOptions }
results:
document: *rvDocument

View File

@@ -172,6 +172,10 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, c Config)
automationService.Registry().AddTypes(
automation.User{},
automation.Role{},
automation.Template{},
automation.RenderVariables{},
automation.RenderOptions{},
automation.Document{},
)
automation.UsersHandler(
@@ -179,6 +183,11 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, c Config)
DefaultUser,
)
automation.TemplatesHandler(
automationService.Registry(),
DefaultRenderer,
)
automation.RolesHandler(
automationService.Registry(),
DefaultRole,