From 45349fe560bc75338e3bcc6403da19d06c2c9f32 Mon Sep 17 00:00:00 2001 From: Roman Perekhod Date: Wed, 19 Apr 2023 16:33:37 +0200 Subject: [PATCH] Determine the users preferred language to translate emails via Transifex. #6087 --- .../users-preferred-language-email.md | 6 ++ services/notifications/pkg/command/server.go | 6 +- services/notifications/pkg/service/service.go | 72 +++++++++++++++++-- .../notifications/pkg/service/service_test.go | 28 ++++++-- services/notifications/pkg/service/shares.go | 21 ++---- services/notifications/pkg/service/spaces.go | 30 +++----- services/settings/pkg/service/v0/settings.go | 13 ++-- .../settings/pkg/store/defaults/defaults.go | 13 ++-- .../settings/pkg/store/metadata/values.go | 36 +++++++++- 9 files changed, 158 insertions(+), 67 deletions(-) create mode 100644 changelog/unreleased/users-preferred-language-email.md diff --git a/changelog/unreleased/users-preferred-language-email.md b/changelog/unreleased/users-preferred-language-email.md new file mode 100644 index 00000000000..9e6af440bb4 --- /dev/null +++ b/changelog/unreleased/users-preferred-language-email.md @@ -0,0 +1,6 @@ +Enhancement: Determine the users preferred language to translate emails via Transifex. + +Enhane userlog service with proper api and messages + +https://github.com/owncloud/ocis/pull/6089 +https://github.com/owncloud/ocis/issues/6087 diff --git a/services/notifications/pkg/command/server.go b/services/notifications/pkg/command/server.go index d5eff832243..2bacb06619d 100644 --- a/services/notifications/pkg/command/server.go +++ b/services/notifications/pkg/command/server.go @@ -12,6 +12,8 @@ import ( "github.com/go-micro/plugins/v4/events/natsjs" "github.com/owncloud/ocis/v2/ocis-pkg/config/configlog" "github.com/owncloud/ocis/v2/ocis-pkg/crypto" + "github.com/owncloud/ocis/v2/ocis-pkg/service/grpc" + 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/config" "github.com/owncloud/ocis/v2/services/notifications/pkg/config/parser" @@ -93,8 +95,8 @@ func Server(cfg *config.Config) *cli.Command { 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.Notifications.MachineAuthAPIKey, cfg.Notifications.EmailTemplatePath, cfg.WebUIURL) + valueService := settingssvc.NewValueService("com.owncloud.api.settings", grpc.DefaultClient()) + svc := service.NewEventsNotifier(evts, channel, logger, gwclient, valueService, cfg.Notifications.MachineAuthAPIKey, cfg.Notifications.EmailTemplatePath, cfg.WebUIURL) return svc.Run() }, } diff --git a/services/notifications/pkg/service/service.go b/services/notifications/pkg/service/service.go index 714696e720f..a80701193f9 100644 --- a/services/notifications/pkg/service/service.go +++ b/services/notifications/pkg/service/service.go @@ -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/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" + "github.com/owncloud/ocis/v2/services/settings/pkg/store/defaults" + "go-micro.dev/v4/metadata" "google.golang.org/protobuf/types/known/fieldmaskpb" ) @@ -33,13 +38,16 @@ func NewEventsNotifier( channel channels.Channel, logger log.Logger, gwClient gateway.GatewayAPIClient, + valueService settingssvc.ValueService, machineAuthAPIKey, emailTemplatePath, ocisURL string) Service { + return eventsNotifier{ logger: logger, channel: channel, events: events, signals: make(chan os.Signal, 1), gwClient: gwClient, + valueService: valueService, machineAuthAPIKey: machineAuthAPIKey, emailTemplatePath: emailTemplatePath, ocisURL: ocisURL, @@ -52,6 +60,7 @@ type eventsNotifier struct { events <-chan events.Event signals chan os.Signal gwClient gateway.GatewayAPIClient + valueService settingssvc.ValueService machineAuthAPIKey string emailTemplatePath string translationPath string @@ -87,24 +96,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: defaults.SettingUUIDProfileLanguage, + }) + + 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: diff --git a/services/notifications/pkg/service/service_test.go b/services/notifications/pkg/service/service_test.go index aad56181995..4f6017eded5 100644 --- a/services/notifications/pkg/service/service_test.go +++ b/services/notifications/pkg/service/service_test.go @@ -15,13 +15,19 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/owncloud/ocis/v2/ocis-pkg/log" + ogrpc "github.com/owncloud/ocis/v2/ocis-pkg/service/grpc" + "github.com/owncloud/ocis/v2/ocis-pkg/shared" + settingssvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/settings/v0" + "github.com/owncloud/ocis/v2/services/graph/pkg/config/defaults" "github.com/owncloud/ocis/v2/services/notifications/pkg/service" "github.com/test-go/testify/mock" + "go-micro.dev/v4/client" ) var _ = Describe("Notifications", func() { var ( gwc *cs3mocks.GatewayAPIClient + vs *settingssvc.MockValueService sharer = &user.User{ Id: &user.UserId{ OpaqueId: "sharer", @@ -43,15 +49,23 @@ var _ = Describe("Notifications", func() { BeforeEach(func() { gwc = &cs3mocks.GatewayAPIClient{} - gwc.On("GetUser", mock.Anything, mock.Anything).Return(&user.GetUserResponse{Status: &rpc.Status{Code: rpc.Code_CODE_OK}, User: sharer}, nil) + gwc.On("GetUser", mock.Anything, mock.Anything).Return(&user.GetUserResponse{Status: &rpc.Status{Code: rpc.Code_CODE_OK}, User: sharer}, nil).Once() + gwc.On("GetUser", mock.Anything, mock.Anything).Return(&user.GetUserResponse{Status: &rpc.Status{Code: rpc.Code_CODE_OK}, User: sharee}, nil).Once() gwc.On("Authenticate", mock.Anything, mock.Anything).Return(&gateway.AuthenticateResponse{Status: &rpc.Status{Code: rpc.Code_CODE_OK}, User: sharer}, nil) gwc.On("Stat", mock.Anything, mock.Anything).Return(&provider.StatResponse{Status: &rpc.Status{Code: rpc.Code_CODE_OK}, Info: &provider.ResourceInfo{Name: "secrets of the board", Space: &provider.StorageSpace{Name: "secret space"}}}, nil) + vs = &settingssvc.MockValueService{} + vs.GetValueByUniqueIdentifiersFunc = func(ctx context.Context, req *settingssvc.GetValueByUniqueIdentifiersRequest, opts ...client.CallOption) (*settingssvc.GetValueResponse, error) { + return nil, nil + } }) DescribeTable("Sending notifications", func(tc testChannel, ev events.Event) { + cfg := defaults.FullDefaultConfig() + cfg.GRPCClientTLS = &shared.GRPCClientTLS{} + _ = ogrpc.Configure(ogrpc.GetClientOptions(cfg.GRPCClientTLS)...) ch := make(chan events.Event) - evts := service.NewEventsNotifier(ch, tc, log.NewLogger(), gwc, "", "", "") + evts := service.NewEventsNotifier(ch, tc, log.NewLogger(), gwc, vs, "", "", "") go evts.Run() ch <- ev @@ -66,7 +80,7 @@ var _ = Describe("Notifications", func() { Entry("Share Created", testChannel{ expectedReceipients: map[string]bool{sharee.GetId().GetOpaqueId(): true}, expectedSubject: "Dr. S. Harer shared 'secrets of the board' with you", - expectedMessage: `Hello Dr. S. Harer + expectedMessage: `Hello Eric Expireling Dr. S. Harer has shared "secrets of the board" with you. @@ -91,7 +105,7 @@ https://owncloud.com Entry("Share Expired", testChannel{ expectedReceipients: map[string]bool{sharee.GetId().GetOpaqueId(): true}, expectedSubject: "Share to 'secrets of the board' expired at 2023-04-17 16:42:00", - expectedMessage: `Hello Dr. S. Harer, + expectedMessage: `Hello Eric Expireling, Your share to secrets of the board has expired at 2023-04-17 16:42:00 @@ -116,7 +130,7 @@ https://owncloud.com Entry("Added to Space", testChannel{ expectedReceipients: map[string]bool{sharee.GetId().GetOpaqueId(): true}, expectedSubject: "Dr. S. Harer invited you to join secret space", - expectedMessage: `Hello Dr. S. Harer, + expectedMessage: `Hello Eric Expireling, Dr. S. Harer has invited you to join "secret space". @@ -141,7 +155,7 @@ https://owncloud.com Entry("Removed from Space", testChannel{ expectedReceipients: map[string]bool{sharee.GetId().GetOpaqueId(): true}, expectedSubject: "Dr. S. Harer removed you from secret space", - expectedMessage: `Hello Dr. S. Harer, + expectedMessage: `Hello Eric Expireling, Dr. S. Harer has removed you from "secret space". @@ -167,7 +181,7 @@ https://owncloud.com Entry("Space Expired", testChannel{ expectedReceipients: map[string]bool{sharee.GetId().GetOpaqueId(): true}, expectedSubject: "Membership of 'secret space' expired at 2023-04-17 16:42:00", - expectedMessage: `Hello Dr. S. Harer, + expectedMessage: `Hello Eric Expireling, Your membership of space secret space has expired at 2023-04-17 16:42:00 diff --git a/services/notifications/pkg/service/shares.go b/services/notifications/pkg/service/shares.go index 6451783bc2f..8049974faef 100644 --- a/services/notifications/pkg/service/shares.go +++ b/services/notifications/pkg/service/shares.go @@ -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") } @@ -81,22 +77,17 @@ 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, renderFunc, owner.GetDisplayName()); err != nil { + s.logger.Error().Err(err).Str("event", "ShareExpired").Msg("failed to send a message") } - - 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") - } - } diff --git a/services/notifications/pkg/service/spaces.go b/services/notifications/pkg/service/spaces.go index bf7d7473428..f3c8e0670d1 100644 --- a/services/notifications/pkg/service/spaces.go +++ b/services/notifications/pkg/service/spaces.go @@ -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") } } @@ -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") } } @@ -152,18 +143,13 @@ 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, renderFunc, owner.GetDisplayName()); err != nil { + s.logger.Error().Err(err).Str("event", "SpaceUnshared").Msg("failed to send a message") } - - 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") - } - } diff --git a/services/settings/pkg/service/v0/settings.go b/services/settings/pkg/service/v0/settings.go index 411e6310bfc..ab58b915ff4 100644 --- a/services/settings/pkg/service/v0/settings.go +++ b/services/settings/pkg/service/v0/settings.go @@ -43,7 +43,8 @@ const ( // CreateSpacePermissionName is the hardcoded setting name for the create space permission CreateSpacePermissionName string = "create-space" - settingUUIDProfileLanguage = "aa8cfbe5-95d4-4f7e-a032-c3c01f5f062f" + // SettingUUIDProfileLanguage is the hardcoded setting UUID for the user profile language + SettingUUIDProfileLanguage = "aa8cfbe5-95d4-4f7e-a032-c3c01f5f062f" // AccountManagementPermissionID is the hardcoded setting UUID for the account management permission AccountManagementPermissionID string = "8e587774-d929-4215-910b-a317b1e80f73" @@ -207,7 +208,7 @@ func generateBundleProfileRequest() *settingsmsg.Bundle { DisplayName: "Profile", Settings: []*settingsmsg.Setting{ { - Id: settingUUIDProfileLanguage, + Id: SettingUUIDProfileLanguage, Name: "language", DisplayName: "Language", Description: "User language", @@ -268,7 +269,7 @@ func generatePermissionRequests() []*settingssvc.AddSettingToBundleRequest { DisplayName: "Permission to read and set the language (anyone)", Resource: &settingsmsg.Resource{ Type: settingsmsg.Resource_TYPE_SETTING, - Id: settingUUIDProfileLanguage, + Id: SettingUUIDProfileLanguage, }, Value: &settingsmsg.Setting_PermissionValue{ PermissionValue: &settingsmsg.Permission{ @@ -286,7 +287,7 @@ func generatePermissionRequests() []*settingssvc.AddSettingToBundleRequest { DisplayName: "Permission to read and set the language (self)", Resource: &settingsmsg.Resource{ Type: settingsmsg.Resource_TYPE_SETTING, - Id: settingUUIDProfileLanguage, + Id: SettingUUIDProfileLanguage, }, Value: &settingsmsg.Setting_PermissionValue{ PermissionValue: &settingsmsg.Permission{ @@ -304,7 +305,7 @@ func generatePermissionRequests() []*settingssvc.AddSettingToBundleRequest { DisplayName: "Permission to read and set the language (self)", Resource: &settingsmsg.Resource{ Type: settingsmsg.Resource_TYPE_SETTING, - Id: settingUUIDProfileLanguage, + Id: SettingUUIDProfileLanguage, }, Value: &settingsmsg.Setting_PermissionValue{ PermissionValue: &settingsmsg.Permission{ @@ -523,7 +524,7 @@ func generatePermissionRequests() []*settingssvc.AddSettingToBundleRequest { DisplayName: "Permission to read and set the language (self)", Resource: &settingsmsg.Resource{ Type: settingsmsg.Resource_TYPE_SETTING, - Id: settingUUIDProfileLanguage, + Id: SettingUUIDProfileLanguage, }, Value: &settingsmsg.Setting_PermissionValue{ PermissionValue: &settingsmsg.Permission{ diff --git a/services/settings/pkg/store/defaults/defaults.go b/services/settings/pkg/store/defaults/defaults.go index 534da706f1c..6e7b463f6b5 100644 --- a/services/settings/pkg/store/defaults/defaults.go +++ b/services/settings/pkg/store/defaults/defaults.go @@ -73,7 +73,8 @@ const ( // SpaceAbilityPermissionName is the hardcoded setting name for the space ability permission SpaceAbilityPermissionName string = "Drive.ReadWriteEnabled" - settingUUIDProfileLanguage = "aa8cfbe5-95d4-4f7e-a032-c3c01f5f062f" + // SettingUUIDProfileLanguage is the hardcoded setting UUID for the user profile language + SettingUUIDProfileLanguage = "aa8cfbe5-95d4-4f7e-a032-c3c01f5f062f" // AccountManagementPermissionID is the hardcoded setting UUID for the account management permission AccountManagementPermissionID string = "8e587774-d929-4215-910b-a317b1e80f73" @@ -159,7 +160,7 @@ func generateBundleAdminRole() *settingsmsg.Bundle { DisplayName: "Permission to read and set the language (anyone)", Resource: &settingsmsg.Resource{ Type: settingsmsg.Resource_TYPE_SETTING, - Id: settingUUIDProfileLanguage, + Id: SettingUUIDProfileLanguage, }, Value: &settingsmsg.Setting_PermissionValue{ PermissionValue: &settingsmsg.Permission{ @@ -416,7 +417,7 @@ func generateBundleSpaceAdminRole() *settingsmsg.Bundle { DisplayName: "Permission to read and set the language (self)", Resource: &settingsmsg.Resource{ Type: settingsmsg.Resource_TYPE_SETTING, - Id: settingUUIDProfileLanguage, + Id: SettingUUIDProfileLanguage, }, Value: &settingsmsg.Setting_PermissionValue{ PermissionValue: &settingsmsg.Permission{ @@ -492,7 +493,7 @@ func generateBundleUserRole() *settingsmsg.Bundle { DisplayName: "Permission to read and set the language (self)", Resource: &settingsmsg.Resource{ Type: settingsmsg.Resource_TYPE_SETTING, - Id: settingUUIDProfileLanguage, + Id: SettingUUIDProfileLanguage, }, Value: &settingsmsg.Setting_PermissionValue{ PermissionValue: &settingsmsg.Permission{ @@ -568,7 +569,7 @@ func generateBundleGuestRole() *settingsmsg.Bundle { DisplayName: "Permission to read and set the language (self)", Resource: &settingsmsg.Resource{ Type: settingsmsg.Resource_TYPE_SETTING, - Id: settingUUIDProfileLanguage, + Id: SettingUUIDProfileLanguage, }, Value: &settingsmsg.Setting_PermissionValue{ PermissionValue: &settingsmsg.Permission{ @@ -593,7 +594,7 @@ func generateBundleProfileRequest() *settingsmsg.Bundle { DisplayName: "Profile", Settings: []*settingsmsg.Setting{ { - Id: settingUUIDProfileLanguage, + Id: SettingUUIDProfileLanguage, Name: "language", DisplayName: "Language", Description: "User language", diff --git a/services/settings/pkg/store/metadata/values.go b/services/settings/pkg/store/metadata/values.go index a9df99dacea..c40f859fa73 100644 --- a/services/settings/pkg/store/metadata/values.go +++ b/services/settings/pkg/store/metadata/values.go @@ -4,7 +4,6 @@ package store import ( "context" "encoding/json" - "errors" "fmt" "github.com/cs3org/reva/v2/pkg/errtypes" @@ -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