Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add email templating #4564

Merged
merged 13 commits into from
Sep 22, 2022
7 changes: 7 additions & 0 deletions changelog/unreleased/add-email-templating.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Enhancement: Add Email templating

We have added email templating to ocis. Which are send on the SpaceShared and ShareCreated event.

https://github.com/owncloud/ocis/pull/4564
https://github.com/owncloud/ocis/issues/4303
https://github.com/cs3org/reva/pull/3252
1 change: 1 addition & 0 deletions services/audit/pkg/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func RegisteredEvents() []events.Unmarshaller {
events.SpaceEnabled{},
events.SpaceDisabled{},
events.SpaceDeleted{},
events.SpaceShared{},
events.UserCreated{},
events.UserDeleted{},
events.UserFeatureChanged{},
Expand Down
18 changes: 12 additions & 6 deletions services/notifications/pkg/channels/channels.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package channels
import (
"context"
"crypto/tls"
"fmt"
"strings"

gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
Expand All @@ -19,9 +20,9 @@ import (
// Channel defines the methods of a communication channel.
type Channel interface {
// SendMessage sends a message to users.
SendMessage(userIDs []string, msg string) error
SendMessage(userIDs []string, msg, subject, senderDisplayName string) error
// SendMessageToGroup sends a message to a group.
SendMessageToGroup(groupdID *groups.GroupId, msg string) error
SendMessageToGroup(groupdID *groups.GroupId, msg, subject, senderDisplayName string) error
}

// NewMailChannel instantiates a new mail communication channel.
Expand Down Expand Up @@ -100,7 +101,7 @@ func (m Mail) getMailClient() (*mail.SMTPClient, error) {
}

// SendMessage sends a message to all given users.
func (m Mail) SendMessage(userIDs []string, msg string) error {
func (m Mail) SendMessage(userIDs []string, msg, subject, senderDisplayName string) error {
if m.conf.Notifications.SMTP.Host == "" {
return nil
}
Expand All @@ -116,14 +117,19 @@ func (m Mail) SendMessage(userIDs []string, msg string) error {
}

email := mail.NewMSG()
email.SetFrom(m.conf.Notifications.SMTP.Sender).AddTo(to...)
if senderDisplayName != "" {
email.SetFrom(fmt.Sprintf("%s via owncloud <%s>", senderDisplayName, m.conf.Notifications.SMTP.Sender)).AddTo(to...)
} else {
email.SetFrom(m.conf.Notifications.SMTP.Sender).AddTo(to...)
}
email.SetBody(mail.TextPlain, msg)
email.SetSubject(subject)

return email.Send(smtpClient)
}

// SendMessageToGroup sends a message to all members of the given group.
func (m Mail) SendMessageToGroup(groupID *groups.GroupId, msg string) error {
func (m Mail) SendMessageToGroup(groupID *groups.GroupId, msg, subject, senderDisplayName string) error {
// TODO We need an authenticated context here...
res, err := m.gatewayClient.GetGroup(context.Background(), &groups.GetGroupRequest{GroupId: groupID})
if err != nil {
Expand All @@ -138,7 +144,7 @@ func (m Mail) SendMessageToGroup(groupID *groups.GroupId, msg string) error {
members = append(members, id.OpaqueId)
}

return m.SendMessage(members, msg)
return m.SendMessage(members, msg, subject, senderDisplayName)
}

func (m Mail) getReceiverAddresses(receivers []string) ([]string, error) {
Expand Down
10 changes: 9 additions & 1 deletion services/notifications/pkg/command/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/cs3org/reva/v2/pkg/events"
"github.com/cs3org/reva/v2/pkg/events/server"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/go-micro/plugins/v4/events/natsjs"
"github.com/owncloud/ocis/v2/ocis-pkg/config/configlog"
"github.com/owncloud/ocis/v2/services/notifications/pkg/channels"
Expand All @@ -27,8 +28,10 @@ func Server(cfg *config.Config) *cli.Command {
Action: func(c *cli.Context) error {
logger := logging.Configure(cfg.Service.Name, cfg.Log)

// evs defines a list of events to subscribe to
evs := []events.Unmarshaller{
events.ShareCreated{},
events.SpaceShared{},
}

evtsCfg := cfg.Notifications.Events
Expand All @@ -47,7 +50,12 @@ func Server(cfg *config.Config) *cli.Command {
if err != nil {
return err
}
svc := service.NewEventsNotifier(evts, channel, logger)
gwclient, err := pool.GetGatewayServiceClient(cfg.Notifications.RevaGateway)
if err != nil {
logger.Fatal().Err(err).Str("addr", cfg.Notifications.RevaGateway).Msg("could not get reva client")
}

svc := service.NewEventsNotifier(evts, channel, logger, gwclient, cfg.Commons.MachineAuthAPIKey, cfg.Notifications.EmailTemplatePath)
return svc.Run()
},
}
Expand Down
1 change: 1 addition & 0 deletions services/notifications/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Notifications struct {
Events Events `yaml:"events"`
RevaGateway string `yaml:"reva_gateway" env:"REVA_GATEWAY;NOTIFICATIONS_REVA_GATEWAY" desc:"CS3 gateway used to look up user metadata"`
MachineAuthAPIKey string `yaml:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;NOTIFICATIONS_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used to validate internal requests necessary to access resources from other services."`
EmailTemplatePath string `yaml:"email_template_path" env:"OCIS_EMAIL_TEMPLATE_PATH;NOTIFICATIONS_EMAIL_TEMPLATE_PATH" desc:"Path to the E-Mail templates for the notifications to override the embedded ones."`
}

// SMTP combines the smtp configuration options.
Expand Down
34 changes: 34 additions & 0 deletions services/notifications/pkg/email/email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package email

import (
"bytes"
"embed"
"html/template"
"path/filepath"
)

var (
//go:embed templates
templatesFS embed.FS
)

// RenderEmailTemplate renders the email template for a new share
func RenderEmailTemplate(templateName string, templateVariables map[string]string, emailTemplatePath string) (string, error) {
var err error
var tpl *template.Template
// try to lookup the files in the filesystem
tpl, err = template.ParseFiles(filepath.Join(emailTemplatePath, templateName))
if err != nil {
// template has not been found in the fs, or path has not been specified => use embed templates
tpl, err = template.ParseFS(templatesFS, filepath.Join("templates/", templateName))
if err != nil {
return "", err
}
}
var writer bytes.Buffer
err = tpl.Execute(&writer, templateVariables)
if err != nil {
return "", err
}
return writer.String(), nil
}
18 changes: 18 additions & 0 deletions services/notifications/pkg/email/templates/shareCreated.email.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Hello {{ .ShareGrantee }},

{{ .ShareSharer }} has shared {{ .ShareFolder }} with you.

Click here to view it: {{ .ShareLink }}

----------------------------------------------------------

Hallo {{ .Grantee }},

{{ .ShareSharer }} hat dich zu {{ .ShareFolder }} eingeladen.

Klicke hier zum Anzeigen: {{ .ShareLink }}


---
ownCloud - Store. Share. Work.
https://owncloud.com
18 changes: 18 additions & 0 deletions services/notifications/pkg/email/templates/sharedSpace.email.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Hello {{ .SpaceGrantee }},

{{ .SpaceSharer }} has invited you to join {{ .SpaceName }}.

Click here to view it: {{ .ShareLink }}

----------------------------------------------------------

Hallo {{ .SpaceGrantee }},

{{ .SpaceSharer }} hat dich in den Space {{ .SpaceName }} eingeladen.

Klicke hier zum Anzeigen: {{ .ShareLink }}


---
ownCloud - Store. Share. Work.
https://owncloud.com
Loading