Skip to content

Commit

Permalink
Determine the users preferred language to translate emails via Transi…
Browse files Browse the repository at this point in the history
  • Loading branch information
2403905 committed Apr 19, 2023
1 parent e34e0b5 commit 2c24274
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 44 deletions.
71 changes: 65 additions & 6 deletions services/notifications/pkg/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@ import (
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/pkg/events"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/ocis-pkg/middleware"
"github.com/owncloud/ocis/v2/ocis-pkg/service/grpc"
"github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0"
"github.com/owncloud/ocis/v2/services/notifications/pkg/channels"
"github.com/owncloud/ocis/v2/services/notifications/pkg/email"
"go-micro.dev/v4/metadata"
"google.golang.org/protobuf/types/known/fieldmaskpb"
)

Expand All @@ -34,12 +39,14 @@ func NewEventsNotifier(
logger log.Logger,
gwClient gateway.GatewayAPIClient,
machineAuthAPIKey, emailTemplatePath, ocisURL string) Service {

return eventsNotifier{
logger: logger,
channel: channel,
events: events,
signals: make(chan os.Signal, 1),
gwClient: gwClient,
valueService: settingssvc.NewValueService("com.owncloud.api.settings", grpc.DefaultClient()),
machineAuthAPIKey: machineAuthAPIKey,
emailTemplatePath: emailTemplatePath,
ocisURL: ocisURL,
Expand All @@ -52,6 +59,7 @@ type eventsNotifier struct {
events <-chan events.Event
signals chan os.Signal
gwClient gateway.GatewayAPIClient
valueService settingssvc.ValueService
machineAuthAPIKey string
emailTemplatePath string
translationPath string
Expand Down Expand Up @@ -87,24 +95,75 @@ func (s eventsNotifier) Run() error {
}
}

func (s eventsNotifier) render(template email.MessageTemplate, values map[string]interface{}) (string, string, error) {
func (s eventsNotifier) render(template email.MessageTemplate, values map[string]interface{}) func(string) (string, string, error) {
// The locate have to come from the user setting
return email.RenderEmailTemplate(template, "en", s.emailTemplatePath, s.translationPath, values)
return func(locale string) (string, string, error) {
return email.RenderEmailTemplate(template, locale, s.emailTemplatePath, s.translationPath, values)
}
}

func (s eventsNotifier) send(ctx context.Context, u *user.UserId, g *group.GroupId, msg, subj, sender string) error {
func (s eventsNotifier) send(ctx context.Context, u *user.UserId, g *group.GroupId, renderFunc func(string) (string, string, error), sender string) error {
if u != nil {
locale, err := s.getUserLang(ctx, u)
if err != nil {
return err
}
subj, msg, err := renderFunc(locale)
if err != nil {
return err
}
return s.channel.SendMessage(ctx, []string{u.GetOpaqueId()}, msg, subj, sender)

}

if g != nil {
return s.channel.SendMessageToGroup(ctx, g, msg, subj, sender)
}
res, err := s.gwClient.GetGroup(ctx, &group.GetGroupRequest{GroupId: g})
if err != nil {
return err
}
if res.Status.Code != rpc.Code_CODE_OK {
return errors.New("could not get group")
}

for _, id := range res.Group.Members {
locale, err := s.getUserLang(ctx, id)
if err != nil {
return err
}
subj, msg, err := renderFunc(locale)
if err != nil {
return err
}
err = s.channel.SendMessage(ctx, []string{u.GetOpaqueId()}, msg, subj, sender)
if err != nil {
s.logger.Error().Err(err).Str("event", "SendEmailGroupMembers").Msg("failed to send a message")
}
}
if err != nil {
s.logger.Error().Err(err).Str("event", "SendEmailGroupMembers").Msg("failed to send a message")
}
}
return nil
}

func (s eventsNotifier) getUserLang(ctx context.Context, u *user.UserId) (string, error) {
defaultLocale := "en"
granteeCtx := metadata.Set(ctx, middleware.AccountID, u.OpaqueId)
resp, err := s.valueService.GetValueByUniqueIdentifiers(granteeCtx,
&v0.GetValueByUniqueIdentifiersRequest{
AccountUuid: u.OpaqueId,
SettingId: "aa8cfbe5-95d4-4f7e-a032-c3c01f5f062f",
})

if err != nil || resp == nil {
return defaultLocale, nil
}
val := resp.Value.GetValue().GetListValue().GetValues()
if len(val) > 0 && val[0] != nil {
return val[0].GetStringValue(), nil
}
return defaultLocale, nil
}

func (s eventsNotifier) getGranteeName(ctx context.Context, u *user.UserId, g *group.GroupId) (string, error) {
switch {
case u != nil:
Expand Down
20 changes: 6 additions & 14 deletions services/notifications/pkg/service/shares.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,14 @@ func (s eventsNotifier) handleShareCreated(e events.ShareCreated) {
}

sharerDisplayName := owner.GetDisplayName()
subj, msg, err := s.render(email.ShareCreated, map[string]interface{}{
renderFunc := s.render(email.ShareCreated, map[string]interface{}{
"ShareGrantee": shareGrantee,
"ShareSharer": sharerDisplayName,
"ShareFolder": resourceInfo.Name,
"ShareLink": shareLink,
})

if err != nil {
s.logger.Error().Err(err).Str("event", "ShareCreated").Msg("Could not render E-Mail body template for shares")
}

if err := s.send(ownerCtx, e.GranteeUserID, e.GranteeGroupID, msg, subj, sharerDisplayName); err != nil {
if err := s.send(ownerCtx, e.GranteeUserID, e.GranteeGroupID, renderFunc, sharerDisplayName); err != nil {
s.logger.Error().Err(err).Str("event", "ShareCreated").Msg("failed to send a message")
}

Expand Down Expand Up @@ -81,22 +77,18 @@ func (s eventsNotifier) handleShareExpired(e events.ShareExpired) {

shareGrantee, err := s.getGranteeName(ctx, e.GranteeUserID, e.GranteeGroupID)
if err != nil {
s.logger.Error().Err(err).Str("event", "ShareCreated").Msg("Could not get grantee name")
s.logger.Error().Err(err).Str("event", "ShareExpired").Msg("Could not get grantee name")
return
}

subj, msg, err := s.render(email.ShareExpired, map[string]interface{}{
renderFunc := s.render(email.ShareExpired, map[string]interface{}{
"ShareGrantee": shareGrantee,
"ShareFolder": resourceInfo.GetName(),
"ExpiredAt": e.ExpiredAt.Format("2006-01-02 15:04:05"),
})

if err != nil {
s.logger.Error().Err(err).Str("event", "ShareCreated").Msg("Could not render E-Mail body template for shares")
}

if err := s.send(ctx, e.GranteeUserID, e.GranteeGroupID, msg, subj, owner.GetDisplayName()); err != nil {
s.logger.Error().Err(err).Str("event", "ShareCreated").Msg("failed to send a message")
if err := s.send(ctx, e.GranteeUserID, e.GranteeGroupID, renderFunc, owner.GetDisplayName()); err != nil {
s.logger.Error().Err(err).Str("event", "ShareExpired").Msg("failed to send a message")
}

}
29 changes: 8 additions & 21 deletions services/notifications/pkg/service/spaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,14 @@ func (s eventsNotifier) handleSpaceShared(e events.SpaceShared) {
}

sharerDisplayName := owner.GetDisplayName()
subj, msg, err := s.render(email.SharedSpace, map[string]interface{}{
renderFunc := s.render(email.SharedSpace, map[string]interface{}{
"SpaceGrantee": spaceGrantee,
"SpaceSharer": sharerDisplayName,
"SpaceName": resourceInfo.GetSpace().GetName(),
"ShareLink": shareLink,
})
if err != nil {
logger.Error().Err(err).Msg("Could not render E-Mail template for spaces")
return
}

if err := s.send(ownerCtx, e.GranteeUserID, e.GranteeGroupID, msg, subj, sharerDisplayName); err != nil {
if err := s.send(ownerCtx, e.GranteeUserID, e.GranteeGroupID, renderFunc, sharerDisplayName); err != nil {
logger.Error().Err(err).Msg("failed to send a message")
}
}
Expand Down Expand Up @@ -117,20 +113,15 @@ func (s eventsNotifier) handleSpaceUnshared(e events.SpaceUnshared) {
}

sharerDisplayName := owner.GetDisplayName()
subj, msg, err := s.render(email.UnsharedSpace, map[string]interface{}{
renderFunc := s.render(email.UnsharedSpace, map[string]interface{}{
"SpaceGrantee": spaceGrantee,
"SpaceSharer": sharerDisplayName,
"SpaceName": resourceInfo.GetSpace().Name,
"ShareLink": shareLink,
})

if err != nil {
logger.Error().Err(err).Msg("Could not render E-Mail template for spaces")
return
}

if err := s.send(ownerCtx, e.GranteeUserID, e.GranteeGroupID, msg, subj, sharerDisplayName); err != nil {
logger.Error().Err(err).Msg("failed to send a message")
if err := s.send(ownerCtx, e.GranteeUserID, e.GranteeGroupID, renderFunc, sharerDisplayName); err != nil {
s.logger.Error().Err(err).Str("event", "ShareCreated").Msg("failed to send a message")
}
}

Expand All @@ -152,18 +143,14 @@ func (s eventsNotifier) handleSpaceMembershipExpired(e events.SpaceMembershipExp
return
}

subj, msg, err := s.render(email.MembershipExpired, map[string]interface{}{
renderFunc := s.render(email.MembershipExpired, map[string]interface{}{
"SpaceGrantee": shareGrantee,
"SpaceName": e.SpaceName,
"ExpiredAt": e.ExpiredAt.Format("2006-01-02 15:04:05"),
})

if err != nil {
s.logger.Error().Err(err).Str("event", "ShareCreated").Msg("Could not render E-Mail body template for shares")
}

if err := s.send(ctx, e.GranteeUserID, e.GranteeGroupID, msg, subj, owner.GetDisplayName()); err != nil {
s.logger.Error().Err(err).Str("event", "ShareCreated").Msg("failed to send a message")
if err := s.send(ctx, e.GranteeUserID, e.GranteeGroupID, renderFunc, owner.GetDisplayName()); err != nil {
s.logger.Error().Err(err).Str("event", "SpaceUnshared").Msg("failed to send a message")
}

}
36 changes: 33 additions & 3 deletions services/settings/pkg/store/metadata/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package store
import (
"context"
"encoding/json"
"errors"
"fmt"

"github.com/cs3org/reva/v2/pkg/errtypes"
Expand Down Expand Up @@ -87,8 +86,39 @@ func (s *Store) ReadValue(valueID string) (*settingsmsg.Value, error) {

// ReadValueByUniqueIdentifiers tries to find a value given a set of unique identifiers
func (s *Store) ReadValueByUniqueIdentifiers(accountUUID, settingID string) (*settingsmsg.Value, error) {
fmt.Println("ReadValueByUniqueIdentifiers not implemented")
return nil, errors.New("not implemented")
if settingID == "" {
return nil, fmt.Errorf("settingID can not be empty %w", settings.ErrNotFound)
}
s.Init()
ctx := context.TODO()

vIDs, err := s.mdc.ReadDir(ctx, valuesFolderLocation)
if err != nil {
return nil, err
}

for _, vid := range vIDs {
b, err := s.mdc.SimpleDownload(ctx, valuePath(vid))
switch err.(type) {
case nil:
// continue
case errtypes.NotFound:
continue
default:
return nil, err
}

v := &settingsmsg.Value{}
err = json.Unmarshal(b, v)
if err != nil {
return nil, err
}

if v.AccountUuid == accountUUID && v.SettingId == settingID {
return v, nil
}
}
return nil, settings.ErrNotFound
}

// WriteValue writes the given value into a file within the dataPath
Expand Down

0 comments on commit 2c24274

Please sign in to comment.