3
0

Implement email sending wf functions

This commit is contained in:
Denis Arh
2021-03-15 22:26:39 +01:00
parent fe23867965
commit 8ce11a3376
10 changed files with 1504 additions and 6 deletions
+993
View File
@@ -0,0 +1,993 @@
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:
// automation/automation/email_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"
sysTypes "github.com/cortezaproject/corteza-server/system/types"
"io"
)
var _ wfexec.ExecResponse
type (
emailHandlerRegistry interface {
AddFunctions(ff ...*atypes.Function)
Type(ref string) expr.Type
}
)
func (h emailHandler) register() {
h.reg.AddFunctions(
h.Send(),
h.Message(),
h.SendMessage(),
h.SetSubject(),
h.SetHeaders(),
h.SetHeader(),
h.SetAddress(),
h.Attach(),
h.Embed(),
)
}
type (
emailSendArgs struct {
hasSubject bool
Subject string
hasReplyTo bool
ReplyTo interface{}
replyToString string
replyToUser *sysTypes.User
hasFrom bool
From interface{}
fromString string
fromUser *sysTypes.User
hasTo bool
To interface{}
toString string
toKV map[string]string
toUser *sysTypes.User
hasCc bool
Cc interface{}
ccString string
ccKV map[string]string
ccUser *sysTypes.User
hasHtml bool
Html interface{}
htmlString string
htmlStream io.Reader
hasPlain bool
Plain interface{}
plainString string
plainStream io.Reader
}
)
func (a emailSendArgs) GetReplyTo() (bool, string, *sysTypes.User) {
return a.hasReplyTo, a.replyToString, a.replyToUser
}
func (a emailSendArgs) GetFrom() (bool, string, *sysTypes.User) {
return a.hasFrom, a.fromString, a.fromUser
}
func (a emailSendArgs) GetTo() (bool, string, map[string]string, *sysTypes.User) {
return a.hasTo, a.toString, a.toKV, a.toUser
}
func (a emailSendArgs) GetCc() (bool, string, map[string]string, *sysTypes.User) {
return a.hasCc, a.ccString, a.ccKV, a.ccUser
}
func (a emailSendArgs) GetHtml() (bool, string, io.Reader) {
return a.hasHtml, a.htmlString, a.htmlStream
}
func (a emailSendArgs) GetPlain() (bool, string, io.Reader) {
return a.hasPlain, a.plainString, a.plainStream
}
// Send function Sends email message with basic parameters
//
// expects implementation of send function:
// func (h emailHandler) send(ctx context.Context, args *emailSendArgs) (err error) {
// return
// }
func (h emailHandler) Send() *atypes.Function {
return &atypes.Function{
Ref: "emailSend",
Kind: "function",
Labels: map[string]string(nil),
Meta: &atypes.FunctionMeta{
Short: "Sends email message with basic parameters",
},
Parameters: []*atypes.Param{
{
Name: "subject",
Types: []string{"String"},
Meta: &atypes.ParamMeta{
Label: "Subject",
},
},
{
Name: "replyTo",
Types: []string{"String", "User"},
Meta: &atypes.ParamMeta{
Label: "Reply to",
},
},
{
Name: "from",
Types: []string{"String", "User"},
Meta: &atypes.ParamMeta{
Label: "Sender",
},
},
{
Name: "to",
Types: []string{"String", "KV", "User"},
Meta: &atypes.ParamMeta{
Label: "Recipients",
},
},
{
Name: "cc",
Types: []string{"String", "KV", "User"},
Meta: &atypes.ParamMeta{
Label: "CC",
},
},
{
Name: "html",
Types: []string{"String", "Reader"},
Meta: &atypes.ParamMeta{
Label: "HTML message body",
},
},
{
Name: "plain",
Types: []string{"String", "Reader"},
Meta: &atypes.ParamMeta{
Label: "Plain text message body",
},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &emailSendArgs{
hasSubject: in.Has("subject"),
hasReplyTo: in.Has("replyTo"),
hasFrom: in.Has("from"),
hasTo: in.Has("to"),
hasCc: in.Has("cc"),
hasHtml: in.Has("html"),
hasPlain: in.Has("plain"),
}
)
if err = in.Decode(args); err != nil {
return
}
// Converting ReplyTo argument
if args.hasReplyTo {
aux := expr.Must(expr.Select(in, "replyTo"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.replyToString = aux.Get().(string)
case h.reg.Type("User").Type():
args.replyToUser = aux.Get().(*sysTypes.User)
}
}
// Converting From argument
if args.hasFrom {
aux := expr.Must(expr.Select(in, "from"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.fromString = aux.Get().(string)
case h.reg.Type("User").Type():
args.fromUser = aux.Get().(*sysTypes.User)
}
}
// Converting To argument
if args.hasTo {
aux := expr.Must(expr.Select(in, "to"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.toString = aux.Get().(string)
case h.reg.Type("KV").Type():
args.toKV = aux.Get().(map[string]string)
case h.reg.Type("User").Type():
args.toUser = aux.Get().(*sysTypes.User)
}
}
// Converting Cc argument
if args.hasCc {
aux := expr.Must(expr.Select(in, "cc"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.ccString = aux.Get().(string)
case h.reg.Type("KV").Type():
args.ccKV = aux.Get().(map[string]string)
case h.reg.Type("User").Type():
args.ccUser = aux.Get().(*sysTypes.User)
}
}
// Converting Html argument
if args.hasHtml {
aux := expr.Must(expr.Select(in, "html"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.htmlString = aux.Get().(string)
case h.reg.Type("Reader").Type():
args.htmlStream = aux.Get().(io.Reader)
}
}
// Converting Plain argument
if args.hasPlain {
aux := expr.Must(expr.Select(in, "plain"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.plainString = aux.Get().(string)
case h.reg.Type("Reader").Type():
args.plainStream = aux.Get().(io.Reader)
}
}
return out, h.send(ctx, args)
},
}
}
type (
emailMessageArgs struct {
hasSubject bool
Subject string
hasReplyTo bool
ReplyTo interface{}
replyToString string
replyToUser *sysTypes.User
hasFrom bool
From interface{}
fromString string
fromUser *sysTypes.User
hasTo bool
To interface{}
toString string
toKV map[string]string
toUser *sysTypes.User
hasCc bool
Cc interface{}
ccString string
ccKV map[string]string
ccUser *sysTypes.User
hasHtml bool
Html interface{}
htmlString string
htmlStream io.Reader
hasPlain bool
Plain interface{}
plainString string
plainStream io.Reader
}
emailMessageResults struct {
Message *emailMessage
}
)
func (a emailMessageArgs) GetReplyTo() (bool, string, *sysTypes.User) {
return a.hasReplyTo, a.replyToString, a.replyToUser
}
func (a emailMessageArgs) GetFrom() (bool, string, *sysTypes.User) {
return a.hasFrom, a.fromString, a.fromUser
}
func (a emailMessageArgs) GetTo() (bool, string, map[string]string, *sysTypes.User) {
return a.hasTo, a.toString, a.toKV, a.toUser
}
func (a emailMessageArgs) GetCc() (bool, string, map[string]string, *sysTypes.User) {
return a.hasCc, a.ccString, a.ccKV, a.ccUser
}
func (a emailMessageArgs) GetHtml() (bool, string, io.Reader) {
return a.hasHtml, a.htmlString, a.htmlStream
}
func (a emailMessageArgs) GetPlain() (bool, string, io.Reader) {
return a.hasPlain, a.plainString, a.plainStream
}
// Message function Constructs new email message
//
// expects implementation of message function:
// func (h emailHandler) message(ctx context.Context, args *emailMessageArgs) (results *emailMessageResults, err error) {
// return
// }
func (h emailHandler) Message() *atypes.Function {
return &atypes.Function{
Ref: "emailMessage",
Kind: "function",
Labels: map[string]string(nil),
Meta: &atypes.FunctionMeta{
Short: "Constructs new email message",
},
Parameters: []*atypes.Param{
{
Name: "subject",
Types: []string{"String"},
Meta: &atypes.ParamMeta{
Label: "Subject",
},
},
{
Name: "replyTo",
Types: []string{"String", "User"},
Meta: &atypes.ParamMeta{
Label: "Reply to",
},
},
{
Name: "from",
Types: []string{"String", "User"},
Meta: &atypes.ParamMeta{
Label: "Sender",
},
},
{
Name: "to",
Types: []string{"String", "KV", "User"},
Meta: &atypes.ParamMeta{
Label: "Recipients",
},
},
{
Name: "cc",
Types: []string{"String", "KV", "User"},
Meta: &atypes.ParamMeta{
Label: "CC",
},
},
{
Name: "html",
Types: []string{"String", "Reader"},
Meta: &atypes.ParamMeta{
Label: "HTML message body",
},
},
{
Name: "plain",
Types: []string{"String", "Reader"},
Meta: &atypes.ParamMeta{
Label: "Plain text message body",
},
},
},
Results: []*atypes.Param{
{
Name: "message",
Types: []string{"EmailMessage"},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &emailMessageArgs{
hasSubject: in.Has("subject"),
hasReplyTo: in.Has("replyTo"),
hasFrom: in.Has("from"),
hasTo: in.Has("to"),
hasCc: in.Has("cc"),
hasHtml: in.Has("html"),
hasPlain: in.Has("plain"),
}
)
if err = in.Decode(args); err != nil {
return
}
// Converting ReplyTo argument
if args.hasReplyTo {
aux := expr.Must(expr.Select(in, "replyTo"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.replyToString = aux.Get().(string)
case h.reg.Type("User").Type():
args.replyToUser = aux.Get().(*sysTypes.User)
}
}
// Converting From argument
if args.hasFrom {
aux := expr.Must(expr.Select(in, "from"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.fromString = aux.Get().(string)
case h.reg.Type("User").Type():
args.fromUser = aux.Get().(*sysTypes.User)
}
}
// Converting To argument
if args.hasTo {
aux := expr.Must(expr.Select(in, "to"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.toString = aux.Get().(string)
case h.reg.Type("KV").Type():
args.toKV = aux.Get().(map[string]string)
case h.reg.Type("User").Type():
args.toUser = aux.Get().(*sysTypes.User)
}
}
// Converting Cc argument
if args.hasCc {
aux := expr.Must(expr.Select(in, "cc"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.ccString = aux.Get().(string)
case h.reg.Type("KV").Type():
args.ccKV = aux.Get().(map[string]string)
case h.reg.Type("User").Type():
args.ccUser = aux.Get().(*sysTypes.User)
}
}
// Converting Html argument
if args.hasHtml {
aux := expr.Must(expr.Select(in, "html"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.htmlString = aux.Get().(string)
case h.reg.Type("Reader").Type():
args.htmlStream = aux.Get().(io.Reader)
}
}
// Converting Plain argument
if args.hasPlain {
aux := expr.Must(expr.Select(in, "plain"))
switch aux.Type() {
case h.reg.Type("String").Type():
args.plainString = aux.Get().(string)
case h.reg.Type("Reader").Type():
args.plainStream = aux.Get().(io.Reader)
}
}
var results *emailMessageResults
if results, err = h.message(ctx, args); err != nil {
return
}
out = &expr.Vars{}
{
// converting results.Message (*emailMessage) to EmailMessage
var (
tval expr.TypedValue
)
if tval, err = h.reg.Type("EmailMessage").Cast(results.Message); err != nil {
return
} else if err = expr.Assign(out, "message", tval); err != nil {
return
}
}
return
},
}
}
type (
emailSendMessageArgs struct {
hasMessage bool
Message *emailMessage
}
)
// SendMessage function Sends email message
//
// expects implementation of sendMessage function:
// func (h emailHandler) sendMessage(ctx context.Context, args *emailSendMessageArgs) (err error) {
// return
// }
func (h emailHandler) SendMessage() *atypes.Function {
return &atypes.Function{
Ref: "emailSendMessage",
Kind: "function",
Labels: map[string]string(nil),
Meta: &atypes.FunctionMeta{
Short: "Sends email message",
},
Parameters: []*atypes.Param{
{
Name: "message",
Types: []string{"EmailMessage"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Message to be sent",
},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &emailSendMessageArgs{
hasMessage: in.Has("message"),
}
)
if err = in.Decode(args); err != nil {
return
}
return out, h.sendMessage(ctx, args)
},
}
}
type (
emailSetSubjectArgs struct {
hasMessage bool
Message *emailMessage
hasSubject bool
Subject string
}
)
// SetSubject function Sets message subject
//
// expects implementation of setSubject function:
// func (h emailHandler) setSubject(ctx context.Context, args *emailSetSubjectArgs) (err error) {
// return
// }
func (h emailHandler) SetSubject() *atypes.Function {
return &atypes.Function{
Ref: "emailSetSubject",
Kind: "function",
Labels: map[string]string(nil),
Meta: &atypes.FunctionMeta{
Short: "Sets message subject",
},
Parameters: []*atypes.Param{
{
Name: "message",
Types: []string{"EmailMessage"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Message to be sent",
},
},
{
Name: "subject",
Types: []string{"String"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Subject",
},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &emailSetSubjectArgs{
hasMessage: in.Has("message"),
hasSubject: in.Has("subject"),
}
)
if err = in.Decode(args); err != nil {
return
}
return out, h.setSubject(ctx, args)
},
}
}
type (
emailSetHeadersArgs struct {
hasMessage bool
Message *emailMessage
hasHeaders bool
Headers map[string][]string
}
)
// SetHeaders function Sets message headers (overrides any existing headers, subject, recipients)
//
// expects implementation of setHeaders function:
// func (h emailHandler) setHeaders(ctx context.Context, args *emailSetHeadersArgs) (err error) {
// return
// }
func (h emailHandler) SetHeaders() *atypes.Function {
return &atypes.Function{
Ref: "emailSetHeaders",
Kind: "function",
Labels: map[string]string(nil),
Meta: &atypes.FunctionMeta{
Short: "Sets message headers (overrides any existing headers, subject, recipients)",
},
Parameters: []*atypes.Param{
{
Name: "message",
Types: []string{"EmailMessage"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Message to be sent",
},
},
{
Name: "headers",
Types: []string{"KVV"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Headers",
},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &emailSetHeadersArgs{
hasMessage: in.Has("message"),
hasHeaders: in.Has("headers"),
}
)
if err = in.Decode(args); err != nil {
return
}
return out, h.setHeaders(ctx, args)
},
}
}
type (
emailSetHeaderArgs struct {
hasMessage bool
Message *emailMessage
hasName bool
Name string
hasValue bool
Value string
}
)
// SetHeader function Appends value or removes specific header,
//
// expects implementation of setHeader function:
// func (h emailHandler) setHeader(ctx context.Context, args *emailSetHeaderArgs) (err error) {
// return
// }
func (h emailHandler) SetHeader() *atypes.Function {
return &atypes.Function{
Ref: "emailSetHeader",
Kind: "function",
Labels: map[string]string(nil),
Meta: &atypes.FunctionMeta{
Short: "Appends value or removes specific header,",
},
Parameters: []*atypes.Param{
{
Name: "message",
Types: []string{"EmailMessage"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Message to be sent",
},
},
{
Name: "name",
Types: []string{"String"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Value",
},
},
{
Name: "value",
Types: []string{"String"},
Meta: &atypes.ParamMeta{
Label: "Value",
Description: "Raw header value. Omiting value will remove header.",
},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &emailSetHeaderArgs{
hasMessage: in.Has("message"),
hasName: in.Has("name"),
hasValue: in.Has("value"),
}
)
if err = in.Decode(args); err != nil {
return
}
return out, h.setHeader(ctx, args)
},
}
}
type (
emailSetAddressArgs struct {
hasMessage bool
Message *emailMessage
hasType bool
Type string
hasAddress bool
Address string
hasName bool
Name string
}
)
// SetAddress function Adds new recipient, sender or reply-to address
//
// expects implementation of setAddress function:
// func (h emailHandler) setAddress(ctx context.Context, args *emailSetAddressArgs) (err error) {
// return
// }
func (h emailHandler) SetAddress() *atypes.Function {
return &atypes.Function{
Ref: "emailSetAddress",
Kind: "function",
Labels: map[string]string(nil),
Meta: &atypes.FunctionMeta{
Short: "Adds new recipient, sender or reply-to address",
},
Parameters: []*atypes.Param{
{
Name: "message",
Types: []string{"EmailMessage"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Message to be sent",
},
},
{
Name: "type",
Types: []string{"String"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Type",
Description: "One of From",
},
},
{
Name: "address",
Types: []string{"String"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Address",
},
},
{
Name: "name",
Types: []string{"String"},
Meta: &atypes.ParamMeta{
Label: "Name",
},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &emailSetAddressArgs{
hasMessage: in.Has("message"),
hasType: in.Has("type"),
hasAddress: in.Has("address"),
hasName: in.Has("name"),
}
)
if err = in.Decode(args); err != nil {
return
}
return out, h.setAddress(ctx, args)
},
}
}
type (
emailAttachArgs struct {
hasMessage bool
Message *emailMessage
hasContent bool
Content interface{}
contentStream io.Reader
contentString string
hasName bool
Name string
}
)
func (a emailAttachArgs) GetContent() (bool, io.Reader, string) {
return a.hasContent, a.contentStream, a.contentString
}
// Attach function Attach content to an email message
//
// expects implementation of attach function:
// func (h emailHandler) attach(ctx context.Context, args *emailAttachArgs) (err error) {
// return
// }
func (h emailHandler) Attach() *atypes.Function {
return &atypes.Function{
Ref: "emailAttach",
Kind: "function",
Labels: map[string]string(nil),
Meta: &atypes.FunctionMeta{
Short: "Attach content to an email message",
},
Parameters: []*atypes.Param{
{
Name: "message",
Types: []string{"EmailMessage"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Message to be sent",
},
},
{
Name: "content",
Types: []string{"Reader", "String"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Content",
},
},
{
Name: "name",
Types: []string{"String"},
Meta: &atypes.ParamMeta{
Label: "Name",
},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &emailAttachArgs{
hasMessage: in.Has("message"),
hasContent: in.Has("content"),
hasName: in.Has("name"),
}
)
if err = in.Decode(args); err != nil {
return
}
// Converting Content argument
if args.hasContent {
aux := expr.Must(expr.Select(in, "content"))
switch aux.Type() {
case h.reg.Type("Reader").Type():
args.contentStream = aux.Get().(io.Reader)
case h.reg.Type("String").Type():
args.contentString = aux.Get().(string)
}
}
return out, h.attach(ctx, args)
},
}
}
type (
emailEmbedArgs struct {
hasMessage bool
Message *emailMessage
hasContent bool
Content io.Reader
hasName bool
Name string
}
)
// Embed function Embed file to an email message
//
// expects implementation of embed function:
// func (h emailHandler) embed(ctx context.Context, args *emailEmbedArgs) (err error) {
// return
// }
func (h emailHandler) Embed() *atypes.Function {
return &atypes.Function{
Ref: "emailEmbed",
Kind: "function",
Labels: map[string]string(nil),
Meta: &atypes.FunctionMeta{
Short: "Embed file to an email message",
},
Parameters: []*atypes.Param{
{
Name: "message",
Types: []string{"EmailMessage"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Message to be sent",
},
},
{
Name: "content",
Types: []string{"Reader"}, Required: true,
Meta: &atypes.ParamMeta{
Label: "Content",
},
},
{
Name: "name",
Types: []string{"String"},
Meta: &atypes.ParamMeta{
Label: "Name",
},
},
},
Handler: func(ctx context.Context, in *expr.Vars) (out *expr.Vars, err error) {
var (
args = &emailEmbedArgs{
hasMessage: in.Has("message"),
hasContent: in.Has("content"),
hasName: in.Has("name"),
}
)
if err = in.Decode(args); err != nil {
return
}
return out, h.embed(ctx, args)
},
}
}
+224
View File
@@ -0,0 +1,224 @@
package automation
import (
"context"
"fmt"
"github.com/cortezaproject/corteza-server/pkg/mail"
sysTypes "github.com/cortezaproject/corteza-server/system/types"
gomail "gopkg.in/mail.v2"
"io"
"io/ioutil"
"strings"
)
type (
emailHandler struct {
reg emailHandlerRegistry
}
messageArgs interface {
GetReplyTo() (bool, string, *sysTypes.User)
GetFrom() (bool, string, *sysTypes.User)
GetTo() (bool, string, map[string]string, *sysTypes.User)
GetCc() (bool, string, map[string]string, *sysTypes.User)
GetHtml() (bool, string, io.Reader)
GetPlain() (bool, string, io.Reader)
}
)
func EmailHandler(reg emailHandlerRegistry) *emailHandler {
h := &emailHandler{
reg: reg,
}
h.register()
return h
}
func (h emailHandler) send(_ context.Context, args *emailSendArgs) (err error) {
msg := mail.New()
if err = h.procArgs(msg, args.Subject, args); err != nil {
return
}
return mail.Send(msg)
}
func (h emailHandler) message(_ context.Context, args *emailMessageArgs) (r *emailMessageResults, err error) {
msg := mail.New()
if err = h.procArgs(msg, args.Subject, args); err != nil {
return
}
return &emailMessageResults{Message: &emailMessage{msg: msg}}, nil
}
func (h emailHandler) sendMessage(_ context.Context, args *emailSendMessageArgs) (err error) {
if args.Message.msg == nil {
return fmt.Errorf("email message not initialized")
}
return mail.Send(args.Message.msg)
}
func (h emailHandler) setSubject(_ context.Context, args *emailSetSubjectArgs) (err error) {
if args.Message.msg == nil {
return fmt.Errorf("email message not initialized")
}
args.Message.msg.SetHeader("Subject", args.Subject)
return nil
}
func (h emailHandler) setHeaders(_ context.Context, args *emailSetHeadersArgs) (err error) {
if args.Message.msg == nil {
return fmt.Errorf("email message not initialized")
}
args.Message.msg.SetHeaders(args.Headers)
return nil
}
func (h emailHandler) setHeader(_ context.Context, args *emailSetHeaderArgs) (err error) {
if args.Message.msg == nil {
return fmt.Errorf("email message not initialized")
}
if args.hasValue {
args.Message.msg.SetHeader(args.Name, append(args.Message.msg.GetHeader(args.Name), args.Value)...)
} else {
args.Message.msg.SetHeader(args.Name)
}
return nil
}
func (h emailHandler) setAddress(_ context.Context, args *emailSetAddressArgs) (err error) {
if args.Message.msg == nil {
return fmt.Errorf("email message not initialized")
}
args.Message.msg.SetAddressHeader(args.Type, args.Address, args.Name)
return nil
}
func (h emailHandler) attach(_ context.Context, args *emailAttachArgs) (err error) {
if args.Message.msg == nil {
return fmt.Errorf("email message not initialized")
}
var (
r = args.contentStream
)
if r == nil {
r = strings.NewReader(args.contentString)
}
args.Message.msg.AttachReader(args.Name, r)
return
}
func (h emailHandler) embed(_ context.Context, args *emailEmbedArgs) (err error) {
if args.Message.msg == nil {
return fmt.Errorf("email message not initialized")
}
args.Message.msg.EmbedReader(args.Name, args.Content)
return
}
func (h emailHandler) procArgs(msg *gomail.Message, subject string, args messageArgs) (err error) {
msg.SetHeader("Subject", subject)
var (
// if text/plain exists,
// we'll add text/html as alternative body!
hasPlain bool
)
if has, s, r := args.GetPlain(); has {
if r != nil {
aux, _ := ioutil.ReadAll(r)
s = string(aux)
}
msg.SetBody("text/plain", s)
hasPlain = true
}
if has, s, r := args.GetHtml(); has {
if r != nil {
aux, _ := ioutil.ReadAll(r)
s = string(aux)
}
if hasPlain {
msg.AddAlternative("text/html", s)
} else {
msg.SetBody("text/html", s)
}
}
if has, s, m, u := args.GetTo(); has {
if err = h.procEmailRecipients(msg, "To", s, m, u); err != nil {
return
}
}
if has, s, m, u := args.GetCc(); has {
if err = h.procEmailRecipients(msg, "Cc", s, m, u); err != nil {
return
}
}
if has, s, u := args.GetReplyTo(); has {
if err = h.procEmailRecipients(msg, "ReplyTo", s, nil, u); err != nil {
return
}
}
if has, s, u := args.GetFrom(); has {
if err = h.procEmailRecipients(msg, "From", s, nil, u); err != nil {
return
}
}
return
}
func (h emailHandler) procEmailRecipients(msg *gomail.Message, field string, s string, mm map[string]string, u *sysTypes.User) (err error) {
var (
rr = make([]string, 0)
)
switch {
case len(s) > 0:
var (
email string
name string
)
name = ""
if spaceAt := strings.Index(s, " "); spaceAt > -1 {
// proc <email> <name> ("foo@bar.baz foo baz")
email, name = s[:spaceAt], strings.TrimSpace(s[spaceAt+1:])
} else {
// proc <email>
email = s
}
rr = append(rr, msg.FormatAddress(email, name))
case len(mm) > 0:
for email, name := range mm {
rr = append(rr, msg.FormatAddress(email, name))
}
case u != nil:
rr = append(rr, msg.FormatAddress(u.Email, u.Name))
}
msg.SetHeader(field, rr...)
return nil
}
+171
View File
@@ -0,0 +1,171 @@
name: email
imports:
- io
- sysTypes github.com/cortezaproject/corteza-server/system/types
messageParams: &messageParams
subject:
meta:
label: Subject
types:
- { wf: String }
replyTo:
meta:
label: Reply to
types:
- { wf: String }
- { wf: User, go: '*sysTypes.User' }
from:
meta:
label: Sender
types:
- { wf: String }
- { wf: User, go: '*sysTypes.User' }
to:
meta:
label: Recipients
types:
- { wf: String }
- { wf: KV }
- { wf: User, go: '*sysTypes.User' }
cc:
meta:
label: CC
types:
- { wf: String }
- { wf: KV }
- { wf: User, go: '*sysTypes.User' }
html:
meta:
label: HTML message body
types:
- { wf: String, suffix: String }
- { wf: Reader, suffix: Stream }
plain:
meta:
label: Plain text message body
types:
- { wf: String, suffix: String }
- { wf: Reader, suffix: Stream }
messageParam: &messageParam
required: true
meta:
label: Message to be sent
types:
- { wf: EmailMessage }
messageResults: &messageResults
message: { wf: EmailMessage }
functions:
send:
kind: function
meta:
short: Sends email message with basic parameters
params: *messageParams
message:
kind: function
meta:
short: Constructs new email message
params: *messageParams
results: *messageResults
sendMessage:
kind: function
meta:
short: Sends email message
params:
message: *messageParam
setSubject:
kind: function
meta:
short: Sets message subject
params:
message: *messageParam
subject:
required: true
meta:
label: Subject
types:
- { wf: String }
setHeaders:
kind: function
meta:
short: Sets message headers (overrides any existing headers, subject, recipients)
params:
message: *messageParam
headers:
required: true
meta:
label: Headers
types:
- { wf: KVV }
setHeader:
kind: function
meta:
short: Appends value or removes specific header,
params:
message: *messageParam
name:
required: true
meta: { label: Value }
types: [ { wf: String } ]
value:
meta: { label: Value, description: Raw header value. Omiting value will remove header. }
types: [ { wf: String } ]
setAddress:
kind: function
meta:
short: Adds new recipient, sender or reply-to address
params:
message: *messageParam
type:
required: true
meta: { label: Type, description: One of From, ReplyTo, To, CC, BCC }
types: [ { wf: String } ]
address:
required: true
meta: { label: Address }
types: [ { wf: String } ]
name:
meta: { label: Name }
types: [ { wf: String } ]
attach:
kind: function
meta:
short: Attach content to an email message
params:
message: *messageParam
content:
required: true
meta: { label: Content }
types: [ { wf: Reader, suffix: Stream }, { wf: String } ]
name:
meta: { label: Name }
types: [ { wf: String } ]
embed:
kind: function
meta:
short: Embed file to an email message
params:
message: *messageParam
content:
required: true
meta: { label: Content }
types: [ { wf: Reader } ]
name:
meta: { label: Name }
types: [ { wf: String } ]
+56
View File
@@ -0,0 +1,56 @@
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:
// automation/automation/expr_types.yaml
import (
"context"
"fmt"
. "github.com/cortezaproject/corteza-server/pkg/expr"
)
var _ = context.Background
var _ = fmt.Errorf
// EmailMessage is an expression type, wrapper for *emailMessage type
type EmailMessage struct{ value *emailMessage }
// NewEmailMessage creates new instance of EmailMessage expression type
func NewEmailMessage(val interface{}) (*EmailMessage, error) {
if c, err := CastToEmailMessage(val); err != nil {
return nil, fmt.Errorf("unable to create EmailMessage: %w", err)
} else {
return &EmailMessage{value: c}, nil
}
}
// Return underlying value on EmailMessage
func (t EmailMessage) Get() interface{} { return t.value }
// Return underlying value on EmailMessage
func (t EmailMessage) GetValue() *emailMessage { return t.value }
// Return type name
func (EmailMessage) Type() string { return "EmailMessage" }
// Convert value to *emailMessage
func (EmailMessage) Cast(val interface{}) (TypedValue, error) {
return NewEmailMessage(val)
}
// Assign new value to EmailMessage
//
// value is first passed through CastToEmailMessage
func (t *EmailMessage) Assign(val interface{}) error {
if c, err := CastToEmailMessage(val); err != nil {
return err
} else {
t.value = c
return nil
}
}
+29
View File
@@ -0,0 +1,29 @@
package automation
import (
"fmt"
"github.com/cortezaproject/corteza-server/pkg/expr"
"gopkg.in/mail.v2"
)
type (
emailMessage struct {
// only basic implementation for now
// we can manipulate mail.Message internals through
// specialized wf functions (message, setSubject, setHeaders, ...)
msg *mail.Message
}
)
func CastToEmailMessage(val interface{}) (out *emailMessage, err error) {
switch val := expr.UntypedValue(val).(type) {
case *emailMessage:
if val.msg == nil {
val.msg = mail.NewMessage()
}
return val, nil
default:
return nil, fmt.Errorf("unable to cast type %T to %T", val, out)
}
}
+18
View File
@@ -0,0 +1,18 @@
package: automation
types:
EmailMessage:
# using ad-hoc type for now, we'll port this to something internal
# when email-gateway is implemented
as: '*emailMessage'
struct:
# - { name: 'subject', exprType: 'String', goType: 'string' }
# - { name: 'addresses', exprType: 'Array', goType: '[]*emailAddress' }
# - { name: 'headers', exprType: 'KVV', goType: 'map[string][]string' }
# - { name: 'replyTo', exprType: 'KV', goType: 'map[string]string', mode: ro }
# - { name: 'to', exprType: 'KV', goType: 'map[string]string', mode: ro }
# - { name: 'cc', exprType: 'KV', goType: 'map[string]string', mode: ro }
# - { name: 'bcc', exprType: 'KV', goType: 'map[string]string', mode: ro }
# - { name: 'parts', exprType: 'Any', goType: 'map[string]io.Reader', mode: ro }
# - { name: 'embedded', exprType: 'Any', goType: 'map[string]io.Reader', mode: ro }
# - { name: 'attachments', exprType: 'Any', goType: 'map[string]io.Reader', mode: ro }
+3
View File
@@ -111,12 +111,15 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, c Config)
&expr.KV{},
&expr.KVV{},
&expr.Reader{},
&automation.EmailMessage{},
)
automation.HttpRequestHandler(Registry())
automation.LogHandler(Registry())
automation.LoopHandler(Registry(), DefaultWorkflow.parser)
automation.CorredorHandler(Registry(), corredor.Service())
automation.EmailHandler(Registry())
return
}
+6
View File
@@ -168,6 +168,9 @@ func expandAutomationFunctionTypes(ff []*aFuncDefs, tt []*exprTypesDef) {
if t.GoType == "" {
t.GoType = ti[t.WorkflowType].As
if "[]TypedValue" == t.GoType {
t.GoType = "[]expr.TypedValue"
}
}
if t.Suffix == "" && len(p.Types) > 1 {
@@ -183,6 +186,9 @@ func expandAutomationFunctionTypes(ff []*aFuncDefs, tt []*exprTypesDef) {
if r.GoType == "" {
r.GoType = ti[r.WorkflowType].As
if "[]TypedValue" == r.GoType {
r.GoType = "[]expr.TypedValue"
}
}
}
}
+4 -2
View File
@@ -75,7 +75,8 @@ type (
{{ range .Params }}
{{- if gt (len .Types) 1 }}
{{ $name := .Name }}
func (a {{ $ARGS }}) {{ export "get" $name }}() (bool, {{ range .Types }}{{ .GoType }},{{ end }}) {
{{ $isArray := .IsArray }}
func (a {{ $ARGS }}) {{ export "get" $name }}() (bool, {{ range .Types }}{{ if $isArray }}[]{{ end }}{{ .GoType }},{{ end }}) {
return a.has{{ export $name }}{{ range .Types }}, a.{{ $name }}{{ export .Suffix }}{{ end }}
}
{{- end }}
@@ -250,6 +251,7 @@ func (h {{ $.Name }}Handler) {{ export .Name }}() *atypes.Function {
{{ range . }}
{{ $name := .Name }}
{{ $isArray := .IsArray }}
{{ if gt (len .Types) 1 }}
// Converting {{ export .Name }} argument
if args.has{{ export .Name }} {
@@ -257,7 +259,7 @@ func (h {{ $.Name }}Handler) {{ export .Name }}() *atypes.Function {
switch aux.Type() {
{{- range .Types }}
case h.reg.Type({{ printf "%q" .WorkflowType }}).Type():
args.{{ $name }}{{ export .Suffix }} = aux.Get().({{ .GoType }})
args.{{ $name }}{{ export .Suffix }} = aux.Get().({{ if $isArray }}[]{{ end }}{{ .GoType }})
{{- end -}}
}
}
-4
View File
@@ -8,7 +8,6 @@ package {{ .Package }}
// Definitions file that controls how this file is generated:
// {{ .Source }}
{{ if .Imports }}
import (
"context"
"fmt"
@@ -19,13 +18,10 @@ import (
. "github.com/cortezaproject/corteza-server/pkg/expr"
{{- end }}
)
{{ end }}
var _ = context.Background
var _ = fmt.Errorf
{{ range $exprType, $def := .Types }}
// {{ $exprType }} is an expression type, wrapper for {{ $def.As }} type
type {{ $exprType }} struct{ value {{ $def.As }} }