From d7b09a1256a94cddcb67069e69af95fd4bcadebd Mon Sep 17 00:00:00 2001 From: jkoberg Date: Wed, 1 Mar 2023 16:17:43 +0100 Subject: [PATCH 01/11] get SpaceDisabled event working Signed-off-by: jkoberg --- services/userlog/pkg/command/server.go | 21 +-- services/userlog/pkg/service/conversion.go | 144 ++++++++++++++++++ services/userlog/pkg/service/http.go | 96 ++---------- services/userlog/pkg/service/options.go | 8 + services/userlog/pkg/service/service.go | 59 +++---- .../service/templates/space-disabled-msg.tmpl | 1 + .../templates/space-disabled-subj.tmpl | 1 + 7 files changed, 188 insertions(+), 142 deletions(-) create mode 100644 services/userlog/pkg/service/conversion.go create mode 100644 services/userlog/pkg/service/templates/space-disabled-msg.tmpl create mode 100644 services/userlog/pkg/service/templates/space-disabled-subj.tmpl diff --git a/services/userlog/pkg/command/server.go b/services/userlog/pkg/command/server.go index 7ca044d297..6f09a53715 100644 --- a/services/userlog/pkg/command/server.go +++ b/services/userlog/pkg/command/server.go @@ -25,36 +25,17 @@ import ( // all events we care about var _registeredEvents = []events.Unmarshaller{ - // file related - events.UploadReady{}, - events.ContainerCreated{}, - events.FileTouched{}, - events.FileDownloaded{}, - events.FileVersionRestored{}, - events.ItemMoved{}, - events.ItemTrashed{}, - events.ItemPurged{}, - events.ItemRestored{}, - // space related - events.SpaceCreated{}, - events.SpaceRenamed{}, - events.SpaceEnabled{}, events.SpaceDisabled{}, events.SpaceDeleted{}, events.SpaceShared{}, events.SpaceUnshared{}, - events.SpaceUpdated{}, events.SpaceMembershipExpired{}, // share related events.ShareCreated{}, - // events.ShareRemoved{}, // TODO: ShareRemoved doesn't hold sharee information - events.ShareUpdated{}, + events.ShareRemoved{}, events.ShareExpired{}, - events.LinkCreated{}, - // events.LinkRemoved{}, // TODO: LinkRemoved doesn't hold sharee information - events.LinkUpdated{}, } // Server is the entrypoint for the server command. diff --git a/services/userlog/pkg/service/conversion.go b/services/userlog/pkg/service/conversion.go new file mode 100644 index 0000000000..46c536ea3a --- /dev/null +++ b/services/userlog/pkg/service/conversion.go @@ -0,0 +1,144 @@ +package service + +import ( + "bytes" + "context" + "path/filepath" + "text/template" + "time" + + user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + "github.com/cs3org/reva/v2/pkg/events" + "github.com/cs3org/reva/v2/pkg/storagespace" +) + +var ( + _resourceTypeSpace = "storagespace" +) + +// OC10Notification is the oc10 style representation of an event +// some fields are left out for simplicity +type OC10Notification struct { + EventID string `json:"notification_id"` + Service string `json:"app"` + UserName string `json:"user"` + Timestamp string `json:"datetime"` + ResourceID string `json:"object_id"` + ResourceType string `json:"object_type"` + Subject string `json:"subject"` + Message string `json:"message"` + MessageRaw string `json:"messageRich"` + MessageDetails map[string]interface{} `json:"messageRichParameters"` +} + +// SpaceDisabled converts a SpaceDisabled event to an OC10Notification +func (ul *UserlogService) SpaceDisabled(ctx context.Context, eventid string, ev events.SpaceDisabled) (OC10Notification, error) { + user, err := ul.getUser(ctx, ev.Executant) + if err != nil { + return OC10Notification{}, err + } + + space, err := ul.getSpace(ul.impersonate(user.GetId()), ev.ID.GetOpaqueId()) + if err != nil { + return OC10Notification{}, err + } + + subj, msg, msgraw, err := ul.composeMessage("space-disabled", map[string]string{ + "username": user.GetUsername(), + "spacename": space.GetName(), + }) + if err != nil { + return OC10Notification{}, err + } + + return OC10Notification{ + EventID: eventid, + Service: ul.cfg.Service.Name, + Timestamp: time.Now().Format(time.RFC3339Nano), + Subject: subj, + ResourceID: ev.ID.GetOpaqueId(), + ResourceType: _resourceTypeSpace, + Message: msg, + MessageRaw: msgraw, + MessageDetails: ul.getMessageDetails(user, space, nil), + }, nil + +} + +func (ul *UserlogService) composeMessage(eventname string, vars map[string]string) (string, string, string, error) { + subjtpl, err := ul.parseTemplate(eventname + "-subj") + if err != nil { + return "", "", "", err + } + + subject := ul.executeTemplate(subjtpl, vars) + + msgtpl, err := ul.parseTemplate(eventname + "-msg") + if err != nil { + return "", "", "", err + } + + message := ul.executeTemplate(msgtpl, vars) + + messageraw := ul.executeTemplate(msgtpl, map[string]string{ + "username": "{user}", + "spacename": "{space}", + "resource": "{resource}", + }) + + return subject, message, messageraw, nil + +} + +func (ul *UserlogService) getMessageDetails(user *user.User, space *storageprovider.StorageSpace, item *storageprovider.ResourceInfo) map[string]interface{} { + details := make(map[string]interface{}) + + if user != nil { + details["user"] = map[string]string{ + "id": user.GetId().GetOpaqueId(), + "name": user.GetUsername(), + } + } + + if space != nil { + details["space"] = map[string]string{ + "id": space.GetId().GetOpaqueId(), + "name": space.GetName(), + } + } + + if item != nil { + details["resource"] = map[string]string{ + "id": storagespace.FormatResourceID(*item.GetId()), + "name": item.GetName(), + } + } + + return details +} + +func (ul *UserlogService) parseTemplate(templateName string) (*template.Template, error) { + var ( + tpl *template.Template + err error + ) + switch ul.templatePath { + case "": + tpl, err = template.ParseFS(templatesFS, filepath.Join("templates/", templateName+".tmpl")) + default: + tpl, err = template.ParseFiles(filepath.Join(ul.templatePath, templateName+".tmpl")) + } + + return tpl, err +} + +func (ul *UserlogService) executeTemplate(tpl *template.Template, vars map[string]string) string { + var writer bytes.Buffer + if err := tpl.Execute(&writer, vars); err != nil { + ul.log.Error().Err(err).Str("templateName", tpl.Name()).Msg("cannot execute template") + return "" + } + + return writer.String() +} diff --git a/services/userlog/pkg/service/http.go b/services/userlog/pkg/service/http.go index 4ad2011ac1..1b9c7d3856 100644 --- a/services/userlog/pkg/service/http.go +++ b/services/userlog/pkg/service/http.go @@ -2,6 +2,7 @@ package service import ( "context" + "embed" "encoding/json" "errors" "fmt" @@ -14,6 +15,11 @@ import ( ehmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/eventhistory/v0" ) +var ( + //go:embed templates + templatesFS embed.FS +) + // ServeHTTP fulfills Handler interface func (ul *UserlogService) ServeHTTP(w http.ResponseWriter, r *http.Request) { ul.m.ServeHTTP(w, r) @@ -97,119 +103,39 @@ func (ul *UserlogService) convertEvent(ctx context.Context, event *ehmsg.Event) // TODO: strange bug with getting space -> fix postponed to make master panic-free var space storageprovider.StorageSpace - switch ev := einterface.(type) { - // file related - case events.UploadReady: - noti.UserID = ev.ExecutingUser.GetId().GetOpaqueId() - noti.Subject = "File uploaded" - noti.Message = fmt.Sprintf("File '%s' was uploaded to space '%s' by user '%s'", ev.Filename, space.GetName(), ev.ExecutingUser.GetUsername()) - case events.ContainerCreated: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "Folder created" - noti.Message = fmt.Sprintf("Folder '%s' was created", ev.Ref.GetPath()) - case events.FileTouched: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "File touched" - noti.Message = fmt.Sprintf("File '%s' was touched", ev.Ref.GetPath()) - case events.FileDownloaded: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "File downloaded" - noti.Message = fmt.Sprintf("File '%s' was downloaded", ev.Ref.GetPath()) - case events.FileVersionRestored: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "File version restored" - noti.Message = fmt.Sprintf("An older version of file '%s' was restored", ev.Ref.GetPath()) - case events.ItemMoved: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "File moved" - noti.Message = fmt.Sprintf("File '%s' was moved from '%s'", ev.Ref.GetPath(), ev.OldReference.GetPath()) - case events.ItemTrashed: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "File trashed" - noti.Message = fmt.Sprintf("File '%s' was trashed", ev.Ref.GetPath()) - case events.ItemPurged: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "File purged" - noti.Message = fmt.Sprintf("File '%s' was purged", ev.Ref.GetPath()) - case events.ItemRestored: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "File restored" - noti.Message = fmt.Sprintf("File '%s' was restored", ev.Ref.GetPath()) + switch ev := einterface.(type) { // space related - case events.SpaceCreated: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "Space created" - noti.Message = fmt.Sprintf("Space '%s' was created", ev.Name) - case events.SpaceRenamed: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "Space renamed" - noti.Message = fmt.Sprintf("Space '%s' was renamed", ev.Name) - case events.SpaceEnabled: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "Space enabled" - noti.Message = fmt.Sprintf("Space '%s' was renamed", space.Name) case events.SpaceDisabled: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "Space disabled" - noti.Message = fmt.Sprintf("Space '%s' was disabled", space.Name) + return ul.SpaceDisabled(ctx, event.Id, ev) case events.SpaceDeleted: - noti.UserID = ev.Executant.GetOpaqueId() noti.Subject = "Space deleted" noti.Message = fmt.Sprintf("Space '%s' was deleted", space.Name) case events.SpaceShared: - noti.UserID = ev.Executant.GetOpaqueId() noti.Subject = "Space shared" noti.Message = fmt.Sprintf("Space '%s' was shared", space.Name) case events.SpaceUnshared: - noti.UserID = ev.Executant.GetOpaqueId() noti.Subject = "Space unshared" noti.Message = fmt.Sprintf("Space '%s' was unshared", space.Name) - case events.SpaceUpdated: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "Space updated" - noti.Message = fmt.Sprintf("Space '%s' was updated", space.Name) case events.SpaceMembershipExpired: - noti.UserID = "" noti.Subject = "Space membership expired" noti.Message = fmt.Sprintf("A spacemembership for space '%s' has expired", space.Name) // share related case events.ShareCreated: - noti.UserID = ev.Executant.GetOpaqueId() noti.Subject = "Share received" noti.Message = fmt.Sprintf("A file was shared in space %s", space.Name) - case events.ShareUpdated: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "Share updated" - noti.Message = fmt.Sprintf("A share was updated in space %s", space.Name) case events.ShareExpired: noti.Subject = "Share expired" noti.Message = fmt.Sprintf("A share has expired in space %s", space.Name) - case events.LinkCreated: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "Share received" - noti.Message = fmt.Sprintf("A link was created in space %s", space.Name) - case events.LinkUpdated: - noti.UserID = ev.Executant.GetOpaqueId() - noti.Subject = "Share received" - noti.Message = fmt.Sprintf("A link was updated in space %s", space.Name) + case events.ShareRemoved: + noti.Subject = "Share removed" + noti.Message = "share was removed" } return noti, nil } -// OC10Notification is the oc10 style representation of an event -// some fields are left out for simplicity -type OC10Notification struct { - EventID string `json:"notification_id"` - Service string `json:"app"` - Timestamp string `json:"datetime"` - UserID string `json:"user"` - Subject string `json:"subject"` - Message string `json:"message"` -} - // GetEventResponseOC10 is the response from GET events endpoint in oc10 style type GetEventResponseOC10 struct { OCS struct { diff --git a/services/userlog/pkg/service/options.go b/services/userlog/pkg/service/options.go index b84c67725e..2bb737bd12 100644 --- a/services/userlog/pkg/service/options.go +++ b/services/userlog/pkg/service/options.go @@ -23,6 +23,7 @@ type Options struct { HistoryClient ehsvc.EventHistoryService GatewayClient gateway.GatewayAPIClient RegisteredEvents []events.Unmarshaller + TemplatePath string } // Logger configures a logger for the userlog service @@ -80,3 +81,10 @@ func RegisteredEvents(e []events.Unmarshaller) Option { o.RegisteredEvents = e } } + +// TemplatePath registers the events the service should listen to +func TemplatePath(tmpl string) Option { + return func(o *Options) { + o.TemplatePath = tmpl + } +} diff --git a/services/userlog/pkg/service/service.go b/services/userlog/pkg/service/service.go index 838f75dc9c..cb46953736 100644 --- a/services/userlog/pkg/service/service.go +++ b/services/userlog/pkg/service/service.go @@ -32,6 +32,7 @@ type UserlogService struct { historyClient ehsvc.EventHistoryService gwClient gateway.GatewayAPIClient registeredEvents map[string]events.Unmarshaller + templatePath string // for custom notification templates } // NewUserlogService returns an EventHistory service @@ -59,6 +60,7 @@ func NewUserlogService(opts ...Option) (*UserlogService, error) { historyClient: o.HistoryClient, gwClient: o.GatewayClient, registeredEvents: make(map[string]events.Unmarshaller), + templatePath: o.TemplatePath, } for _, e := range o.RegisteredEvents { @@ -85,62 +87,30 @@ func (ul *UserlogService) MemorizeEvents() { users []string err error ) + + fmt.Println("RECEIVED", event) switch e := event.Event.(type) { default: err = errors.New("unhandled event") - - // file related - case events.UploadReady: - users, err = ul.findSpaceMembers(ul.impersonate(e.SpaceOwner), e.FileRef.GetResourceId().GetSpaceId(), viewer) - case events.ContainerCreated: - users, err = ul.findSpaceMembers(ul.impersonate(e.SpaceOwner), e.Ref.GetResourceId().GetSpaceId(), viewer) - case events.FileTouched: - users, err = ul.findSpaceMembers(ul.impersonate(e.SpaceOwner), e.Ref.GetResourceId().GetSpaceId(), viewer) - case events.FileDownloaded: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.Ref.GetResourceId().GetSpaceId(), viewer) // no space owner in event - case events.FileVersionRestored: - users, err = ul.findSpaceMembers(ul.impersonate(e.SpaceOwner), e.Ref.GetResourceId().GetSpaceId(), editor) - case events.ItemMoved: - users, err = ul.findSpaceMembers(ul.impersonate(e.SpaceOwner), e.Ref.GetResourceId().GetSpaceId(), viewer) - case events.ItemTrashed: - users, err = ul.findSpaceMembers(ul.impersonate(e.SpaceOwner), e.Ref.GetResourceId().GetSpaceId(), viewer) - case events.ItemPurged: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.Ref.GetResourceId().GetSpaceId(), editor) // no space owner in event - case events.ItemRestored: - users, err = ul.findSpaceMembers(ul.impersonate(e.SpaceOwner), e.Ref.GetResourceId().GetSpaceId(), viewer) - // space related // TODO: how to find spaceadmins? - case events.SpaceCreated: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), viewer) - case events.SpaceRenamed: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), viewer) - case events.SpaceEnabled: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), viewer) case events.SpaceDisabled: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), manager) + users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), viewer) case events.SpaceDeleted: users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), manager) case events.SpaceShared: users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), manager) case events.SpaceUnshared: users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), manager) - case events.SpaceUpdated: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), manager) case events.SpaceMembershipExpired: users, err = ul.resolveShare(ul.impersonate(e.SpaceOwner), e.GranteeUserID, e.GranteeGroupID, e.SpaceID.GetOpaqueId()) // share related case events.ShareCreated: users, err = ul.resolveShare(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID, e.ItemID.GetSpaceId()) - case events.ShareUpdated: - users, err = ul.resolveShare(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID, e.ItemID.GetSpaceId()) + case events.ShareRemoved: + err = errors.New("no grantee in share removed event") case events.ShareExpired: users, err = ul.resolveShare(ul.impersonate(e.ShareOwner), e.GranteeUserID, e.GranteeGroupID, e.ItemID.GetSpaceId()) - case events.LinkCreated: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ItemID.GetOpaqueId(), editor) - case events.LinkUpdated: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ItemID.GetOpaqueId(), editor) - } if err != nil { @@ -423,6 +393,21 @@ func (ul *UserlogService) resolveShare(ctx context.Context, userid *user.UserId, return append(users, usr...), nil } +func (ul *UserlogService) getUser(ctx context.Context, userid *user.UserId) (*user.User, error) { + getUserResponse, err := ul.gwClient.GetUser(context.Background(), &user.GetUserRequest{ + UserId: userid, + }) + if err != nil { + return nil, err + } + + if getUserResponse.Status.Code != rpc.Code_CODE_OK { + return nil, fmt.Errorf("error getting user: %s", getUserResponse.Status.Message) + } + + return getUserResponse.GetUser(), nil +} + func listStorageSpaceRequest(spaceID string) *storageprovider.ListStorageSpacesRequest { return &storageprovider.ListStorageSpacesRequest{ Filters: []*storageprovider.ListStorageSpacesRequest_Filter{ diff --git a/services/userlog/pkg/service/templates/space-disabled-msg.tmpl b/services/userlog/pkg/service/templates/space-disabled-msg.tmpl new file mode 100644 index 0000000000..0aa5c5e5f6 --- /dev/null +++ b/services/userlog/pkg/service/templates/space-disabled-msg.tmpl @@ -0,0 +1 @@ +{{ .username }} disabled Space {{ .spacename }} \ No newline at end of file diff --git a/services/userlog/pkg/service/templates/space-disabled-subj.tmpl b/services/userlog/pkg/service/templates/space-disabled-subj.tmpl new file mode 100644 index 0000000000..fa07032fee --- /dev/null +++ b/services/userlog/pkg/service/templates/space-disabled-subj.tmpl @@ -0,0 +1 @@ +Space Disabled \ No newline at end of file From f62bfaf9a0375b1cd60591347bac33d015b20013 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Wed, 1 Mar 2023 16:19:39 +0100 Subject: [PATCH 02/11] add a changelog Signed-off-by: jkoberg --- changelog/unreleased/userlog-improvements.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelog/unreleased/userlog-improvements.md diff --git a/changelog/unreleased/userlog-improvements.md b/changelog/unreleased/userlog-improvements.md new file mode 100644 index 0000000000..95e4e94bc5 --- /dev/null +++ b/changelog/unreleased/userlog-improvements.md @@ -0,0 +1,5 @@ +Enhancement: Userlog + +Enhane userlog service with proper api and messages + +https://github.com/owncloud/ocis/pull/5699 From 00c8d687005b3f75bf789a59ed5ad765afca806c Mon Sep 17 00:00:00 2001 From: jkoberg Date: Thu, 2 Mar 2023 10:45:20 +0100 Subject: [PATCH 03/11] read hardcoded templates Signed-off-by: jkoberg --- services/userlog/pkg/service/conversion.go | 64 ++++++++----------- services/userlog/pkg/service/http.go | 6 -- services/userlog/pkg/service/options.go | 8 --- services/userlog/pkg/service/service.go | 11 +--- services/userlog/pkg/service/service_test.go | 10 +-- services/userlog/pkg/service/templates.go | 26 ++++++++ .../service/templates/space-disabled-msg.tmpl | 1 - .../templates/space-disabled-subj.tmpl | 1 - 8 files changed, 62 insertions(+), 65 deletions(-) create mode 100644 services/userlog/pkg/service/templates.go delete mode 100644 services/userlog/pkg/service/templates/space-disabled-msg.tmpl delete mode 100644 services/userlog/pkg/service/templates/space-disabled-subj.tmpl diff --git a/services/userlog/pkg/service/conversion.go b/services/userlog/pkg/service/conversion.go index 46c536ea3a..ee14f1dcea 100644 --- a/services/userlog/pkg/service/conversion.go +++ b/services/userlog/pkg/service/conversion.go @@ -3,7 +3,7 @@ package service import ( "bytes" "context" - "path/filepath" + "errors" "text/template" "time" @@ -27,6 +27,7 @@ type OC10Notification struct { ResourceID string `json:"object_id"` ResourceType string `json:"object_type"` Subject string `json:"subject"` + SubjectRaw string `json:"subjectRich"` Message string `json:"message"` MessageRaw string `json:"messageRich"` MessageDetails map[string]interface{} `json:"messageRichParameters"` @@ -44,8 +45,8 @@ func (ul *UserlogService) SpaceDisabled(ctx context.Context, eventid string, ev return OC10Notification{}, err } - subj, msg, msgraw, err := ul.composeMessage("space-disabled", map[string]string{ - "username": user.GetUsername(), + subj, subjraw, msg, msgraw, err := ul.composeMessage(SpaceDisabled, map[string]string{ + "username": user.GetDisplayName(), "spacename": space.GetName(), }) if err != nil { @@ -55,49 +56,53 @@ func (ul *UserlogService) SpaceDisabled(ctx context.Context, eventid string, ev return OC10Notification{ EventID: eventid, Service: ul.cfg.Service.Name, + UserName: user.GetUsername(), Timestamp: time.Now().Format(time.RFC3339Nano), - Subject: subj, ResourceID: ev.ID.GetOpaqueId(), ResourceType: _resourceTypeSpace, + Subject: subj, + SubjectRaw: subjraw, Message: msg, MessageRaw: msgraw, - MessageDetails: ul.getMessageDetails(user, space, nil), + MessageDetails: ul.getDetails(user, space, nil), }, nil } -func (ul *UserlogService) composeMessage(eventname string, vars map[string]string) (string, string, string, error) { - subjtpl, err := ul.parseTemplate(eventname + "-subj") - if err != nil { - return "", "", "", err +func (ul *UserlogService) composeMessage(eventname string, vars map[string]string) (string, string, string, string, error) { + tpl, ok := _templates[eventname] + if !ok { + return "", "", "", "", errors.New("unknown template name") } - subject := ul.executeTemplate(subjtpl, vars) + subject := ul.executeTemplate(tpl.Subject, vars) - msgtpl, err := ul.parseTemplate(eventname + "-msg") - if err != nil { - return "", "", "", err - } - - message := ul.executeTemplate(msgtpl, vars) - - messageraw := ul.executeTemplate(msgtpl, map[string]string{ + subjectraw := ul.executeTemplate(tpl.Subject, map[string]string{ "username": "{user}", "spacename": "{space}", "resource": "{resource}", }) - return subject, message, messageraw, nil + message := ul.executeTemplate(tpl.Message, vars) + + messageraw := ul.executeTemplate(tpl.Message, map[string]string{ + "username": "{user}", + "spacename": "{space}", + "resource": "{resource}", + }) + + return subject, subjectraw, message, messageraw, nil } -func (ul *UserlogService) getMessageDetails(user *user.User, space *storageprovider.StorageSpace, item *storageprovider.ResourceInfo) map[string]interface{} { +func (ul *UserlogService) getDetails(user *user.User, space *storageprovider.StorageSpace, item *storageprovider.ResourceInfo) map[string]interface{} { details := make(map[string]interface{}) if user != nil { details["user"] = map[string]string{ - "id": user.GetId().GetOpaqueId(), - "name": user.GetUsername(), + "id": user.GetId().GetOpaqueId(), + "name": user.GetUsername(), + "displayname": user.GetDisplayName(), } } @@ -118,21 +123,6 @@ func (ul *UserlogService) getMessageDetails(user *user.User, space *storageprovi return details } -func (ul *UserlogService) parseTemplate(templateName string) (*template.Template, error) { - var ( - tpl *template.Template - err error - ) - switch ul.templatePath { - case "": - tpl, err = template.ParseFS(templatesFS, filepath.Join("templates/", templateName+".tmpl")) - default: - tpl, err = template.ParseFiles(filepath.Join(ul.templatePath, templateName+".tmpl")) - } - - return tpl, err -} - func (ul *UserlogService) executeTemplate(tpl *template.Template, vars map[string]string) string { var writer bytes.Buffer if err := tpl.Execute(&writer, vars); err != nil { diff --git a/services/userlog/pkg/service/http.go b/services/userlog/pkg/service/http.go index 1b9c7d3856..481cab4103 100644 --- a/services/userlog/pkg/service/http.go +++ b/services/userlog/pkg/service/http.go @@ -2,7 +2,6 @@ package service import ( "context" - "embed" "encoding/json" "errors" "fmt" @@ -15,11 +14,6 @@ import ( ehmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/eventhistory/v0" ) -var ( - //go:embed templates - templatesFS embed.FS -) - // ServeHTTP fulfills Handler interface func (ul *UserlogService) ServeHTTP(w http.ResponseWriter, r *http.Request) { ul.m.ServeHTTP(w, r) diff --git a/services/userlog/pkg/service/options.go b/services/userlog/pkg/service/options.go index 2bb737bd12..b84c67725e 100644 --- a/services/userlog/pkg/service/options.go +++ b/services/userlog/pkg/service/options.go @@ -23,7 +23,6 @@ type Options struct { HistoryClient ehsvc.EventHistoryService GatewayClient gateway.GatewayAPIClient RegisteredEvents []events.Unmarshaller - TemplatePath string } // Logger configures a logger for the userlog service @@ -81,10 +80,3 @@ func RegisteredEvents(e []events.Unmarshaller) Option { o.RegisteredEvents = e } } - -// TemplatePath registers the events the service should listen to -func TemplatePath(tmpl string) Option { - return func(o *Options) { - o.TemplatePath = tmpl - } -} diff --git a/services/userlog/pkg/service/service.go b/services/userlog/pkg/service/service.go index cb46953736..cbf792a65b 100644 --- a/services/userlog/pkg/service/service.go +++ b/services/userlog/pkg/service/service.go @@ -25,14 +25,12 @@ import ( // UserlogService is the service responsible for user activities type UserlogService struct { log log.Logger - ch <-chan events.Event m *chi.Mux store store.Store cfg *config.Config historyClient ehsvc.EventHistoryService gwClient gateway.GatewayAPIClient registeredEvents map[string]events.Unmarshaller - templatePath string // for custom notification templates } // NewUserlogService returns an EventHistory service @@ -53,14 +51,12 @@ func NewUserlogService(opts ...Option) (*UserlogService, error) { ul := &UserlogService{ log: o.Logger, - ch: ch, m: o.Mux, store: o.Store, cfg: o.Config, historyClient: o.HistoryClient, gwClient: o.GatewayClient, registeredEvents: make(map[string]events.Unmarshaller), - templatePath: o.TemplatePath, } for _, e := range o.RegisteredEvents { @@ -73,14 +69,14 @@ func NewUserlogService(opts ...Option) (*UserlogService, error) { r.Delete("/*", ul.HandleDeleteEvents) }) - go ul.MemorizeEvents() + go ul.MemorizeEvents(ch) return ul, nil } // MemorizeEvents stores eventIDs a user wants to receive -func (ul *UserlogService) MemorizeEvents() { - for event := range ul.ch { +func (ul *UserlogService) MemorizeEvents(ch <-chan events.Event) { + for event := range ch { // for each event we need to: // I) find users eligible to receive the event var ( @@ -88,7 +84,6 @@ func (ul *UserlogService) MemorizeEvents() { err error ) - fmt.Println("RECEIVED", event) switch e := event.Event.(type) { default: err = errors.New("unhandled event") diff --git a/services/userlog/pkg/service/service_test.go b/services/userlog/pkg/service/service_test.go index 724d4c7d92..89ce6871fa 100644 --- a/services/userlog/pkg/service/service_test.go +++ b/services/userlog/pkg/service/service_test.go @@ -64,7 +64,7 @@ var _ = Describe("UserlogService", func() { service.GatewayClient(&gwc), service.HistoryClient(&ehc), service.RegisteredEvents([]events.Unmarshaller{ - events.UploadReady{}, + events.SpaceDisabled{}, }), ) Expect(err).ToNot(HaveOccurred()) @@ -73,9 +73,11 @@ var _ = Describe("UserlogService", func() { It("it stores, returns and deletes a couple of events", func() { ids := make(map[string]struct{}) - ids[bus.Publish(events.SpaceCreated{Executant: &user.UserId{OpaqueId: "userid"}})] = struct{}{} - ids[bus.Publish(events.UploadReady{SpaceOwner: &user.UserId{OpaqueId: "userid"}})] = struct{}{} - ids[bus.Publish(events.ContainerCreated{SpaceOwner: &user.UserId{OpaqueId: "userid"}})] = struct{}{} + ids[bus.Publish(events.SpaceDisabled{Executant: &user.UserId{OpaqueId: "userid"}})] = struct{}{} + ids[bus.Publish(events.SpaceDisabled{Executant: &user.UserId{OpaqueId: "userid"}})] = struct{}{} + ids[bus.Publish(events.SpaceDisabled{Executant: &user.UserId{OpaqueId: "userid"}})] = struct{}{} + // ids[bus.Publish(events.SpaceMembershipExpired{SpaceOwner: &user.UserId{OpaqueId: "userid"}})] = struct{}{} + // ids[bus.Publish(events.ShareCreated{Executant: &user.UserId{OpaqueId: "userid"}})] = struct{}{} time.Sleep(500 * time.Millisecond) diff --git a/services/userlog/pkg/service/templates.go b/services/userlog/pkg/service/templates.go new file mode 100644 index 0000000000..63c0c6f215 --- /dev/null +++ b/services/userlog/pkg/service/templates.go @@ -0,0 +1,26 @@ +package service + +import "text/template" + +// the available templates +var ( + SpaceDisabled = "space-disabled" + SpaceDisabledSubject = "space disabled" + SpaceDisabledMessage = "{{ .username }} disabled space {{ .spacename }}" +) + +// NotificationTemplate is the data structure for the notifications +type NotificationTemplate struct { + Subject *template.Template + Message *template.Template +} + +// rendered templates +var ( + _templates = map[string]NotificationTemplate{ + SpaceDisabled: { + Subject: template.Must(template.New(SpaceDisabled).Parse(SpaceDisabledSubject)), + Message: template.Must(template.New("").Parse(SpaceDisabledMessage)), + }, + } +) diff --git a/services/userlog/pkg/service/templates/space-disabled-msg.tmpl b/services/userlog/pkg/service/templates/space-disabled-msg.tmpl deleted file mode 100644 index 0aa5c5e5f6..0000000000 --- a/services/userlog/pkg/service/templates/space-disabled-msg.tmpl +++ /dev/null @@ -1 +0,0 @@ -{{ .username }} disabled Space {{ .spacename }} \ No newline at end of file diff --git a/services/userlog/pkg/service/templates/space-disabled-subj.tmpl b/services/userlog/pkg/service/templates/space-disabled-subj.tmpl deleted file mode 100644 index fa07032fee..0000000000 --- a/services/userlog/pkg/service/templates/space-disabled-subj.tmpl +++ /dev/null @@ -1 +0,0 @@ -Space Disabled \ No newline at end of file From 49914e1c6b4cbcb5f4241bb729d67422607bd9d2 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Thu, 2 Mar 2023 15:56:37 +0100 Subject: [PATCH 04/11] notify about SpaceShared Signed-off-by: jkoberg --- services/userlog/pkg/service/conversion.go | 36 +++++++ services/userlog/pkg/service/http.go | 3 +- services/userlog/pkg/service/service.go | 120 ++++++++++----------- services/userlog/pkg/service/templates.go | 14 ++- 4 files changed, 104 insertions(+), 69 deletions(-) diff --git a/services/userlog/pkg/service/conversion.go b/services/userlog/pkg/service/conversion.go index ee14f1dcea..2b66e42a35 100644 --- a/services/userlog/pkg/service/conversion.go +++ b/services/userlog/pkg/service/conversion.go @@ -69,6 +69,42 @@ func (ul *UserlogService) SpaceDisabled(ctx context.Context, eventid string, ev } +// SpaceShared converts a SpaceShared event to an OC10Notification +func (ul *UserlogService) SpaceShared(ctx context.Context, eventid string, ev events.SpaceShared) (OC10Notification, error) { + user, err := ul.getUser(ctx, ev.Executant) + if err != nil { + return OC10Notification{}, err + } + + space, err := ul.getSpace(ul.impersonate(user.GetId()), ev.ID.GetOpaqueId()) + if err != nil { + return OC10Notification{}, err + } + + subj, subjraw, msg, msgraw, err := ul.composeMessage(SpaceShared, map[string]string{ + "username": user.GetDisplayName(), + "spacename": space.GetName(), + }) + if err != nil { + return OC10Notification{}, err + } + + return OC10Notification{ + EventID: eventid, + Service: ul.cfg.Service.Name, + UserName: user.GetUsername(), + Timestamp: time.Now().Format(time.RFC3339Nano), + ResourceID: ev.ID.GetOpaqueId(), + ResourceType: _resourceTypeSpace, + Subject: subj, + SubjectRaw: subjraw, + Message: msg, + MessageRaw: msgraw, + MessageDetails: ul.getDetails(user, space, nil), + }, nil + +} + func (ul *UserlogService) composeMessage(eventname string, vars map[string]string) (string, string, string, string, error) { tpl, ok := _templates[eventname] if !ok { diff --git a/services/userlog/pkg/service/http.go b/services/userlog/pkg/service/http.go index 481cab4103..b9e7ef0398 100644 --- a/services/userlog/pkg/service/http.go +++ b/services/userlog/pkg/service/http.go @@ -106,8 +106,7 @@ func (ul *UserlogService) convertEvent(ctx context.Context, event *ehmsg.Event) noti.Subject = "Space deleted" noti.Message = fmt.Sprintf("Space '%s' was deleted", space.Name) case events.SpaceShared: - noti.Subject = "Space shared" - noti.Message = fmt.Sprintf("Space '%s' was shared", space.Name) + return ul.SpaceShared(ctx, event.Id, ev) case events.SpaceUnshared: noti.Subject = "Space unshared" noti.Message = fmt.Sprintf("Space '%s' was unshared", space.Name) diff --git a/services/userlog/pkg/service/service.go b/services/userlog/pkg/service/service.go index cbf792a65b..a0d1de45aa 100644 --- a/services/userlog/pkg/service/service.go +++ b/services/userlog/pkg/service/service.go @@ -91,21 +91,22 @@ func (ul *UserlogService) MemorizeEvents(ch <-chan events.Event) { case events.SpaceDisabled: users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), viewer) case events.SpaceDeleted: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), manager) + // won't work - space is deleted + users, err = nil, errors.New("i do not know whom to inform") case events.SpaceShared: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), manager) + users, err = ul.resolveID(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID) case events.SpaceUnshared: - users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), manager) + users, err = ul.resolveID(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID) case events.SpaceMembershipExpired: - users, err = ul.resolveShare(ul.impersonate(e.SpaceOwner), e.GranteeUserID, e.GranteeGroupID, e.SpaceID.GetOpaqueId()) + users, err = ul.resolveID(ul.impersonate(e.SpaceOwner), e.GranteeUserID, e.GranteeGroupID) // share related case events.ShareCreated: - users, err = ul.resolveShare(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID, e.ItemID.GetSpaceId()) + users, err = ul.resolveID(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID) case events.ShareRemoved: err = errors.New("no grantee in share removed event") case events.ShareExpired: - users, err = ul.resolveShare(ul.impersonate(e.ShareOwner), e.GranteeUserID, e.GranteeGroupID, e.ItemID.GetSpaceId()) + users, err = ul.resolveID(ul.impersonate(e.ShareOwner), e.GranteeUserID, e.GranteeGroupID) } if err != nil { @@ -183,20 +184,6 @@ func (ul *UserlogService) DeleteEvents(userid string, evids []string) error { }) } -func (ul *UserlogService) impersonate(u *user.UserId) context.Context { - if u == nil { - ul.log.Debug().Msg("cannot impersonate nil user") - return nil - } - - ctx, _, err := utils.Impersonate(u, ul.gwClient, ul.cfg.MachineAuthAPIKey) - if err != nil { - ul.log.Error().Err(err).Str("userid", u.GetOpaqueId()).Msg("failed to impersonate user") - return nil - } - return ctx -} - func (ul *UserlogService) addEventsToUser(userid string, eventids ...string) error { return ul.alterUserEventList(userid, func(ids []string) []string { return append(ids, eventids...) @@ -283,23 +270,6 @@ func (ul *UserlogService) findSpaceMembers(ctx context.Context, spaceID string, return users, nil } -func (ul *UserlogService) getSpace(ctx context.Context, spaceID string) (*storageprovider.StorageSpace, error) { - res, err := ul.gwClient.ListStorageSpaces(ctx, listStorageSpaceRequest(spaceID)) - if err != nil { - return nil, err - } - - if res.GetStatus().GetCode() != rpc.Code_CODE_OK { - return nil, fmt.Errorf("Unexpected status code while getting space: %v", res.GetStatus().GetCode()) - } - - if len(res.StorageSpaces) == 0 { - return nil, fmt.Errorf("error getting storage space %s: no space returned", spaceID) - } - - return res.StorageSpaces[0], nil -} - func (ul *UserlogService) gatherSpaceMembers(ctx context.Context, space *storageprovider.StorageSpace, hasRequiredRole permissionChecker) ([]string, error) { var permissionsMap map[string]*storageprovider.ResourcePermissions if err := utils.ReadJSONFromOpaque(space.GetOpaque(), "grants", &permissionsMap); err != nil { @@ -343,29 +313,6 @@ func (ul *UserlogService) gatherSpaceMembers(ctx context.Context, space *storage return users, nil } -// resolves the users of a group -func (ul *UserlogService) resolveGroup(ctx context.Context, groupID string) ([]string, error) { - if ctx == nil { - return nil, errors.New("need authenticated context to resolve groups") - } - - r, err := ul.gwClient.GetGroup(ctx, &group.GetGroupRequest{GroupId: &group.GroupId{OpaqueId: groupID}}) - if err != nil { - return nil, err - } - - if r.GetStatus().GetCode() != rpc.Code_CODE_OK { - return nil, fmt.Errorf("unexpected status code from gateway client: %d", r.GetStatus().GetCode()) - } - - var userIDs []string - for _, m := range r.GetGroup().GetMembers() { - userIDs = append(userIDs, m.GetOpaqueId()) - } - - return userIDs, nil -} - func (ul *UserlogService) resolveID(ctx context.Context, userid *user.UserId, groupid *group.GroupId) ([]string, error) { if userid != nil { return []string{userid.GetOpaqueId()}, nil @@ -374,18 +321,50 @@ func (ul *UserlogService) resolveID(ctx context.Context, userid *user.UserId, gr return ul.resolveGroup(ctx, groupid.GetOpaqueId()) } -func (ul *UserlogService) resolveShare(ctx context.Context, userid *user.UserId, groupid *group.GroupId, spaceid string) ([]string, error) { - users, err := ul.resolveID(ctx, userid, groupid) +// resolves the users of a group +func (ul *UserlogService) resolveGroup(ctx context.Context, groupID string) ([]string, error) { + grp, err := ul.getGroup(ctx, groupID) if err != nil { return nil, err } - usr, err := ul.findSpaceMembers(ctx, spaceid, editor) + var userIDs []string + for _, m := range grp.GetMembers() { + userIDs = append(userIDs, m.GetOpaqueId()) + } + + return userIDs, nil +} + +func (ul *UserlogService) impersonate(u *user.UserId) context.Context { + if u == nil { + ul.log.Debug().Msg("cannot impersonate nil user") + return nil + } + + ctx, _, err := utils.Impersonate(u, ul.gwClient, ul.cfg.MachineAuthAPIKey) + if err != nil { + ul.log.Error().Err(err).Str("userid", u.GetOpaqueId()).Msg("failed to impersonate user") + return nil + } + return ctx +} + +func (ul *UserlogService) getSpace(ctx context.Context, spaceID string) (*storageprovider.StorageSpace, error) { + res, err := ul.gwClient.ListStorageSpaces(ctx, listStorageSpaceRequest(spaceID)) if err != nil { return nil, err } - return append(users, usr...), nil + if res.GetStatus().GetCode() != rpc.Code_CODE_OK { + return nil, fmt.Errorf("Unexpected status code while getting space: %v", res.GetStatus().GetCode()) + } + + if len(res.StorageSpaces) == 0 { + return nil, fmt.Errorf("error getting storage space %s: no space returned", spaceID) + } + + return res.StorageSpaces[0], nil } func (ul *UserlogService) getUser(ctx context.Context, userid *user.UserId) (*user.User, error) { @@ -403,6 +382,19 @@ func (ul *UserlogService) getUser(ctx context.Context, userid *user.UserId) (*us return getUserResponse.GetUser(), nil } +func (ul *UserlogService) getGroup(ctx context.Context, groupid string) (*group.Group, error) { + r, err := ul.gwClient.GetGroup(ctx, &group.GetGroupRequest{GroupId: &group.GroupId{OpaqueId: groupid}}) + if err != nil { + return nil, err + } + + if r.GetStatus().GetCode() != rpc.Code_CODE_OK { + return nil, fmt.Errorf("unexpected status code from gateway client: %d", r.GetStatus().GetCode()) + } + + return r.GetGroup(), nil +} + func listStorageSpaceRequest(spaceID string) *storageprovider.ListStorageSpacesRequest { return &storageprovider.ListStorageSpacesRequest{ Filters: []*storageprovider.ListStorageSpacesRequest_Filter{ diff --git a/services/userlog/pkg/service/templates.go b/services/userlog/pkg/service/templates.go index 63c0c6f215..cd83bb74b3 100644 --- a/services/userlog/pkg/service/templates.go +++ b/services/userlog/pkg/service/templates.go @@ -5,8 +5,12 @@ import "text/template" // the available templates var ( SpaceDisabled = "space-disabled" - SpaceDisabledSubject = "space disabled" - SpaceDisabledMessage = "{{ .username }} disabled space {{ .spacename }}" + SpaceDisabledSubject = "Space disabled" + SpaceDisabledMessage = "{{ .username }} disabled Space {{ .spacename }}" + + SpaceShared = "space-shared" + SpaceSharedSubject = "Space shared" + SpaceSharedMessage = "{{ .username }} shared Space {{ .spacename }} with you" ) // NotificationTemplate is the data structure for the notifications @@ -19,8 +23,12 @@ type NotificationTemplate struct { var ( _templates = map[string]NotificationTemplate{ SpaceDisabled: { - Subject: template.Must(template.New(SpaceDisabled).Parse(SpaceDisabledSubject)), + Subject: template.Must(template.New("").Parse(SpaceDisabledSubject)), Message: template.Must(template.New("").Parse(SpaceDisabledMessage)), }, + SpaceShared: { + Subject: template.Must(template.New("").Parse(SpaceSharedSubject)), + Message: template.Must(template.New("").Parse(SpaceSharedMessage)), + }, } ) From 6960da69fbc0bb4dc886e46700156136ede8d36c Mon Sep 17 00:00:00 2001 From: jkoberg Date: Thu, 2 Mar 2023 16:47:22 +0100 Subject: [PATCH 05/11] notify about other events Signed-off-by: jkoberg --- services/userlog/pkg/service/conversion.go | 119 ++++++++++++++------- services/userlog/pkg/service/http.go | 62 +---------- services/userlog/pkg/service/service.go | 13 +++ services/userlog/pkg/service/templates.go | 61 ++++++++--- 4 files changed, 138 insertions(+), 117 deletions(-) diff --git a/services/userlog/pkg/service/conversion.go b/services/userlog/pkg/service/conversion.go index 2b66e42a35..74eda00e13 100644 --- a/services/userlog/pkg/service/conversion.go +++ b/services/userlog/pkg/service/conversion.go @@ -2,7 +2,6 @@ package service import ( "bytes" - "context" "errors" "text/template" "time" @@ -11,10 +10,13 @@ import ( storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/v2/pkg/events" "github.com/cs3org/reva/v2/pkg/storagespace" + "github.com/cs3org/reva/v2/pkg/utils" + ehmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/eventhistory/v0" ) var ( _resourceTypeSpace = "storagespace" + _resourceTypeShare = "share" ) // OC10Notification is the oc10 style representation of an event @@ -33,55 +35,57 @@ type OC10Notification struct { MessageDetails map[string]interface{} `json:"messageRichParameters"` } -// SpaceDisabled converts a SpaceDisabled event to an OC10Notification -func (ul *UserlogService) SpaceDisabled(ctx context.Context, eventid string, ev events.SpaceDisabled) (OC10Notification, error) { - user, err := ul.getUser(ctx, ev.Executant) - if err != nil { - return OC10Notification{}, err +// ConvertEvent converts an eventhistory event to an OC10Notification +func (ul *UserlogService) ConvertEvent(event *ehmsg.Event) (OC10Notification, error) { + etype, ok := ul.registeredEvents[event.Type] + if !ok { + // this should not happen + return OC10Notification{}, errors.New("eventtype not registered") } - space, err := ul.getSpace(ul.impersonate(user.GetId()), ev.ID.GetOpaqueId()) + einterface, err := etype.Unmarshal(event.Event) if err != nil { - return OC10Notification{}, err + // this shouldn't happen either + return OC10Notification{}, errors.New("cant unmarshal event") } - subj, subjraw, msg, msgraw, err := ul.composeMessage(SpaceDisabled, map[string]string{ - "username": user.GetDisplayName(), - "spacename": space.GetName(), - }) - if err != nil { - return OC10Notification{}, err + switch ev := einterface.(type) { + default: + return OC10Notification{}, errors.New("unknown event type") + // space related + case events.SpaceDisabled: + return ul.spaceMessage(event.Id, SpaceDisabled, ev.Executant, ev.ID.GetOpaqueId()) + case events.SpaceDeleted: + return ul.spaceMessage(event.Id, SpaceDeleted, ev.Executant, ev.ID.GetOpaqueId()) + case events.SpaceShared: + return ul.spaceMessage(event.Id, SpaceShared, ev.Executant, ev.ID.GetOpaqueId()) + case events.SpaceUnshared: + return ul.spaceMessage(event.Id, SpaceUnshared, ev.Executant, ev.ID.GetOpaqueId()) + case events.SpaceMembershipExpired: + return ul.spaceMessage(event.Id, SpaceMembershipExpired, ev.SpaceOwner, ev.SpaceID.GetOpaqueId()) + + // share related + case events.ShareCreated: + return ul.shareMessage(event.Id, ShareCreated, ev.Executant, ev.ItemID) + case events.ShareExpired: + return ul.shareMessage(event.Id, ShareExpired, ev.ShareOwner, ev.ItemID) + case events.ShareRemoved: + return ul.shareMessage(event.Id, ShareRemoved, ev.Executant, nil) } - - return OC10Notification{ - EventID: eventid, - Service: ul.cfg.Service.Name, - UserName: user.GetUsername(), - Timestamp: time.Now().Format(time.RFC3339Nano), - ResourceID: ev.ID.GetOpaqueId(), - ResourceType: _resourceTypeSpace, - Subject: subj, - SubjectRaw: subjraw, - Message: msg, - MessageRaw: msgraw, - MessageDetails: ul.getDetails(user, space, nil), - }, nil - } -// SpaceShared converts a SpaceShared event to an OC10Notification -func (ul *UserlogService) SpaceShared(ctx context.Context, eventid string, ev events.SpaceShared) (OC10Notification, error) { - user, err := ul.getUser(ctx, ev.Executant) +func (ul *UserlogService) spaceMessage(eventid string, eventname string, executant *user.UserId, spaceid string) (OC10Notification, error) { + ctx, user, err := utils.Impersonate(executant, ul.gwClient, ul.cfg.MachineAuthAPIKey) if err != nil { return OC10Notification{}, err } - space, err := ul.getSpace(ul.impersonate(user.GetId()), ev.ID.GetOpaqueId()) + space, err := ul.getSpace(ctx, spaceid) if err != nil { return OC10Notification{}, err } - subj, subjraw, msg, msgraw, err := ul.composeMessage(SpaceShared, map[string]string{ + subj, subjraw, msg, msgraw, err := ul.composeMessage(eventname, map[string]string{ "username": user.GetDisplayName(), "spacename": space.GetName(), }) @@ -94,7 +98,7 @@ func (ul *UserlogService) SpaceShared(ctx context.Context, eventid string, ev ev Service: ul.cfg.Service.Name, UserName: user.GetUsername(), Timestamp: time.Now().Format(time.RFC3339Nano), - ResourceID: ev.ID.GetOpaqueId(), + ResourceID: spaceid, ResourceType: _resourceTypeSpace, Subject: subj, SubjectRaw: subjraw, @@ -102,7 +106,40 @@ func (ul *UserlogService) SpaceShared(ctx context.Context, eventid string, ev ev MessageRaw: msgraw, MessageDetails: ul.getDetails(user, space, nil), }, nil +} +func (ul *UserlogService) shareMessage(eventid string, eventname string, executant *user.UserId, resourceid *storageprovider.ResourceId) (OC10Notification, error) { + ctx, user, err := utils.Impersonate(executant, ul.gwClient, ul.cfg.MachineAuthAPIKey) + if err != nil { + return OC10Notification{}, err + } + + info, err := ul.getResource(ctx, resourceid) + if err != nil { + return OC10Notification{}, err + } + + subj, subjraw, msg, msgraw, err := ul.composeMessage(eventname, map[string]string{ + "username": user.GetDisplayName(), + "resourcename": info.GetName(), + }) + if err != nil { + return OC10Notification{}, err + } + + return OC10Notification{ + EventID: eventid, + Service: ul.cfg.Service.Name, + UserName: user.GetUsername(), + Timestamp: time.Now().Format(time.RFC3339Nano), + ResourceID: storagespace.FormatResourceID(*info.GetId()), + ResourceType: _resourceTypeShare, + Subject: subj, + SubjectRaw: subjraw, + Message: msg, + MessageRaw: msgraw, + MessageDetails: ul.getDetails(user, nil, info), + }, nil } func (ul *UserlogService) composeMessage(eventname string, vars map[string]string) (string, string, string, string, error) { @@ -114,17 +151,17 @@ func (ul *UserlogService) composeMessage(eventname string, vars map[string]strin subject := ul.executeTemplate(tpl.Subject, vars) subjectraw := ul.executeTemplate(tpl.Subject, map[string]string{ - "username": "{user}", - "spacename": "{space}", - "resource": "{resource}", + "username": "{user}", + "spacename": "{space}", + "resourcename": "{resource}", }) message := ul.executeTemplate(tpl.Message, vars) messageraw := ul.executeTemplate(tpl.Message, map[string]string{ - "username": "{user}", - "spacename": "{space}", - "resource": "{resource}", + "username": "{user}", + "spacename": "{space}", + "resourcename": "{resource}", }) return subject, subjectraw, message, messageraw, nil diff --git a/services/userlog/pkg/service/http.go b/services/userlog/pkg/service/http.go index b9e7ef0398..072e35b26b 100644 --- a/services/userlog/pkg/service/http.go +++ b/services/userlog/pkg/service/http.go @@ -1,17 +1,10 @@ package service import ( - "context" "encoding/json" - "errors" - "fmt" "net/http" - "time" - storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" revactx "github.com/cs3org/reva/v2/pkg/ctx" - "github.com/cs3org/reva/v2/pkg/events" - ehmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/eventhistory/v0" ) // ServeHTTP fulfills Handler interface @@ -37,7 +30,7 @@ func (ul *UserlogService) HandleGetEvents(w http.ResponseWriter, r *http.Request resp := GetEventResponseOC10{} for _, e := range evs { - noti, err := ul.convertEvent(r.Context(), e) + noti, err := ul.ConvertEvent(e) if err != nil { ul.log.Error().Err(err).Str("eventid", e.Id).Str("eventtype", e.Type).Msg("failed to convert event") continue @@ -76,59 +69,6 @@ func (ul *UserlogService) HandleDeleteEvents(w http.ResponseWriter, r *http.Requ w.WriteHeader(http.StatusOK) } -func (ul *UserlogService) convertEvent(ctx context.Context, event *ehmsg.Event) (OC10Notification, error) { - etype, ok := ul.registeredEvents[event.Type] - if !ok { - // this should not happen - return OC10Notification{}, errors.New("eventtype not registered") - } - - einterface, err := etype.Unmarshal(event.Event) - if err != nil { - // this shouldn't happen either - return OC10Notification{}, errors.New("cant unmarshal event") - } - - noti := OC10Notification{ - EventID: event.Id, - Service: "userlog", - Timestamp: time.Now().Format(time.RFC3339Nano), - } - - // TODO: strange bug with getting space -> fix postponed to make master panic-free - var space storageprovider.StorageSpace - - switch ev := einterface.(type) { - // space related - case events.SpaceDisabled: - return ul.SpaceDisabled(ctx, event.Id, ev) - case events.SpaceDeleted: - noti.Subject = "Space deleted" - noti.Message = fmt.Sprintf("Space '%s' was deleted", space.Name) - case events.SpaceShared: - return ul.SpaceShared(ctx, event.Id, ev) - case events.SpaceUnshared: - noti.Subject = "Space unshared" - noti.Message = fmt.Sprintf("Space '%s' was unshared", space.Name) - case events.SpaceMembershipExpired: - noti.Subject = "Space membership expired" - noti.Message = fmt.Sprintf("A spacemembership for space '%s' has expired", space.Name) - - // share related - case events.ShareCreated: - noti.Subject = "Share received" - noti.Message = fmt.Sprintf("A file was shared in space %s", space.Name) - case events.ShareExpired: - noti.Subject = "Share expired" - noti.Message = fmt.Sprintf("A share has expired in space %s", space.Name) - case events.ShareRemoved: - noti.Subject = "Share removed" - noti.Message = "share was removed" - } - - return noti, nil -} - // GetEventResponseOC10 is the response from GET events endpoint in oc10 style type GetEventResponseOC10 struct { OCS struct { diff --git a/services/userlog/pkg/service/service.go b/services/userlog/pkg/service/service.go index a0d1de45aa..657a306597 100644 --- a/services/userlog/pkg/service/service.go +++ b/services/userlog/pkg/service/service.go @@ -395,6 +395,19 @@ func (ul *UserlogService) getGroup(ctx context.Context, groupid string) (*group. return r.GetGroup(), nil } +func (ul *UserlogService) getResource(ctx context.Context, resourceid *storageprovider.ResourceId) (*storageprovider.ResourceInfo, error) { + res, err := ul.gwClient.Stat(ctx, &storageprovider.StatRequest{Ref: &storageprovider.Reference{ResourceId: resourceid}}) + if err != nil { + return nil, err + } + + if res.GetStatus().GetCode() != rpc.Code_CODE_OK { + return nil, fmt.Errorf("Unexpected status code while getting space: %v", res.GetStatus().GetCode()) + } + + return res.GetInfo(), nil +} + func listStorageSpaceRequest(spaceID string) *storageprovider.ListStorageSpacesRequest { return &storageprovider.ListStorageSpacesRequest{ Filters: []*storageprovider.ListStorageSpacesRequest_Filter{ diff --git a/services/userlog/pkg/service/templates.go b/services/userlog/pkg/service/templates.go index cd83bb74b3..3a597cfb6d 100644 --- a/services/userlog/pkg/service/templates.go +++ b/services/userlog/pkg/service/templates.go @@ -4,13 +4,51 @@ import "text/template" // the available templates var ( + SpaceShared = "space-shared" + SpaceSharedSubject = "Space shared" + SpaceSharedMessage = "{{ .username }} shared Space {{ .spacename }} with you" + + SpaceUnshared = "space-unshared" + SpaceUnsharedSubject = "Removed from Space" + SpaceUnsharedMessage = "{{ .username }} removed you from Space {{ .spacename }}" + SpaceDisabled = "space-disabled" SpaceDisabledSubject = "Space disabled" SpaceDisabledMessage = "{{ .username }} disabled Space {{ .spacename }}" - SpaceShared = "space-shared" - SpaceSharedSubject = "Space shared" - SpaceSharedMessage = "{{ .username }} shared Space {{ .spacename }} with you" + SpaceDeleted = "space-deleted" + SpaceDeletedSubject = "Space deleted" + SpaceDeletedMessage = "{{ .username }} deleted Space {{ .spacename }}" + + SpaceMembershipExpired = "space-membership-expired" + SpaceMembershipExpiredSubject = "Membership expired" + SpaceMembershipExpiredMessage = "Access to Space {{ .spacename }} lost" + + ShareCreated = "item-shared" + ShareCreatedSubject = "Resource shared" + ShareCreatedMessage = "{{ .username }} shared {{ .itemname }} with you" + + ShareRemoved = "item-unshared" + ShareRemovedSubject = "Resource unshared" + ShareRemovedMessage = "{{ .username }} unshared {{ .itemname }} with you" + + ShareExpired = "share-expired" + ShareExpiredSubject = "Share expired" + ShareExpiredMessage = "Access to {{ .resourcename }} expired" +) + +// rendered templates +var ( + _templates = map[string]NotificationTemplate{ + SpaceShared: notiTmpl(SpaceSharedSubject, SpaceSharedMessage), + SpaceUnshared: notiTmpl(SpaceUnsharedSubject, SpaceUnsharedMessage), + SpaceDisabled: notiTmpl(SpaceDisabledSubject, SpaceDisabledMessage), + SpaceDeleted: notiTmpl(SpaceDeletedSubject, SpaceDeletedMessage), + SpaceMembershipExpired: notiTmpl(SpaceMembershipExpiredSubject, SpaceMembershipExpiredMessage), + ShareCreated: notiTmpl(ShareCreatedSubject, ShareCreatedMessage), + ShareRemoved: notiTmpl(ShareRemovedSubject, ShareRemovedMessage), + ShareExpired: notiTmpl(ShareExpiredSubject, ShareExpiredMessage), + } ) // NotificationTemplate is the data structure for the notifications @@ -19,16 +57,9 @@ type NotificationTemplate struct { Message *template.Template } -// rendered templates -var ( - _templates = map[string]NotificationTemplate{ - SpaceDisabled: { - Subject: template.Must(template.New("").Parse(SpaceDisabledSubject)), - Message: template.Must(template.New("").Parse(SpaceDisabledMessage)), - }, - SpaceShared: { - Subject: template.Must(template.New("").Parse(SpaceSharedSubject)), - Message: template.Must(template.New("").Parse(SpaceSharedMessage)), - }, +func notiTmpl(subjectname string, messagename string) NotificationTemplate { + return NotificationTemplate{ + Subject: template.Must(template.New("").Parse(subjectname)), + Message: template.Must(template.New("").Parse(messagename)), } -) +} From 179d82c9cfd3f0b0fc99099ed5313d6b04df923c Mon Sep 17 00:00:00 2001 From: jkoberg Date: Fri, 3 Mar 2023 14:50:38 +0100 Subject: [PATCH 06/11] bump dockerfile go version Signed-off-by: jkoberg --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 3777d7207a..3f007f9c50 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ COPY ./ /ocis/ WORKDIR /ocis/ocis RUN make ci-node-generate -FROM owncloudci/golang:1.18 as build +FROM owncloudci/golang:1.19 as build COPY --from=generate /ocis /ocis From 5c2453affcd4963b0a021f6c55c2f0a33b367817 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Fri, 3 Mar 2023 14:50:59 +0100 Subject: [PATCH 07/11] bugfixes round one Signed-off-by: jkoberg --- services/userlog/pkg/service/http.go | 11 ++++++++--- services/userlog/pkg/service/templates.go | 6 +++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/services/userlog/pkg/service/http.go b/services/userlog/pkg/service/http.go index 072e35b26b..725275e04d 100644 --- a/services/userlog/pkg/service/http.go +++ b/services/userlog/pkg/service/http.go @@ -53,14 +53,14 @@ func (ul *UserlogService) HandleDeleteEvents(w http.ResponseWriter, r *http.Requ return } - var ids []string - if err := json.NewDecoder(r.Body).Decode(&ids); err != nil { + var req DeleteEventsRequest + if err := json.NewDecoder(r.Body).Decode(&req); err != nil { ul.log.Error().Err(err).Int("returned statuscode", http.StatusBadRequest).Msg("request body is malformed") w.WriteHeader(http.StatusBadRequest) return } - if err := ul.DeleteEvents(u.GetId().GetOpaqueId(), ids); err != nil { + if err := ul.DeleteEvents(u.GetId().GetOpaqueId(), req.IDs); err != nil { ul.log.Error().Err(err).Int("returned statuscode", http.StatusInternalServerError).Msg("delete events failed") w.WriteHeader(http.StatusInternalServerError) return @@ -80,3 +80,8 @@ type GetEventResponseOC10 struct { Data []OC10Notification `json:"data"` } `json:"ocs"` } + +// DeleteEventsRequest is the expected body for the delete request +type DeleteEventsRequest struct { + IDs []string `json:"ids"` +} diff --git a/services/userlog/pkg/service/templates.go b/services/userlog/pkg/service/templates.go index 3a597cfb6d..bc9bf33d2b 100644 --- a/services/userlog/pkg/service/templates.go +++ b/services/userlog/pkg/service/templates.go @@ -6,7 +6,7 @@ import "text/template" var ( SpaceShared = "space-shared" SpaceSharedSubject = "Space shared" - SpaceSharedMessage = "{{ .username }} shared Space {{ .spacename }} with you" + SpaceSharedMessage = "{{ .username }} added you to Space {{ .spacename }}" SpaceUnshared = "space-unshared" SpaceUnsharedSubject = "Removed from Space" @@ -26,11 +26,11 @@ var ( ShareCreated = "item-shared" ShareCreatedSubject = "Resource shared" - ShareCreatedMessage = "{{ .username }} shared {{ .itemname }} with you" + ShareCreatedMessage = "{{ .username }} shared {{ .resourcename }} with you" ShareRemoved = "item-unshared" ShareRemovedSubject = "Resource unshared" - ShareRemovedMessage = "{{ .username }} unshared {{ .itemname }} with you" + ShareRemovedMessage = "{{ .username }} unshared {{ .resourcename }} with you" ShareExpired = "share-expired" ShareExpiredSubject = "Share expired" From 8a02a568f1b43e634280eaac2e9d2ba9dec76db8 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Mon, 6 Mar 2023 13:06:22 +0100 Subject: [PATCH 08/11] adjust for new reva version Signed-off-by: jkoberg --- services/userlog/pkg/service/conversion.go | 59 +++++++++++++++++----- services/userlog/pkg/service/service.go | 7 +-- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/services/userlog/pkg/service/conversion.go b/services/userlog/pkg/service/conversion.go index 74eda00e13..256d2e8da4 100644 --- a/services/userlog/pkg/service/conversion.go +++ b/services/userlog/pkg/service/conversion.go @@ -54,27 +54,62 @@ func (ul *UserlogService) ConvertEvent(event *ehmsg.Event) (OC10Notification, er return OC10Notification{}, errors.New("unknown event type") // space related case events.SpaceDisabled: - return ul.spaceMessage(event.Id, SpaceDisabled, ev.Executant, ev.ID.GetOpaqueId()) + return ul.spaceMessage(event.Id, SpaceDisabled, ev.Executant, ev.ID.GetOpaqueId(), ev.Timestamp) case events.SpaceDeleted: - return ul.spaceMessage(event.Id, SpaceDeleted, ev.Executant, ev.ID.GetOpaqueId()) + return ul.spaceDeletedMessage(event.Id, ev.Executant, ev.ID.GetOpaqueId(), ev.SpaceName, ev.Timestamp) case events.SpaceShared: - return ul.spaceMessage(event.Id, SpaceShared, ev.Executant, ev.ID.GetOpaqueId()) + return ul.spaceMessage(event.Id, SpaceShared, ev.Executant, ev.ID.GetOpaqueId(), ev.Timestamp) case events.SpaceUnshared: - return ul.spaceMessage(event.Id, SpaceUnshared, ev.Executant, ev.ID.GetOpaqueId()) + return ul.spaceMessage(event.Id, SpaceUnshared, ev.Executant, ev.ID.GetOpaqueId(), ev.Timestamp) case events.SpaceMembershipExpired: - return ul.spaceMessage(event.Id, SpaceMembershipExpired, ev.SpaceOwner, ev.SpaceID.GetOpaqueId()) + return ul.spaceMessage(event.Id, SpaceMembershipExpired, ev.SpaceOwner, ev.SpaceID.GetOpaqueId(), ev.ExpiredAt) // share related case events.ShareCreated: - return ul.shareMessage(event.Id, ShareCreated, ev.Executant, ev.ItemID) + return ul.shareMessage(event.Id, ShareCreated, ev.Executant, ev.ItemID, utils.TSToTime(ev.CTime)) case events.ShareExpired: - return ul.shareMessage(event.Id, ShareExpired, ev.ShareOwner, ev.ItemID) + return ul.shareMessage(event.Id, ShareExpired, ev.ShareOwner, ev.ItemID, ev.ExpiredAt) case events.ShareRemoved: - return ul.shareMessage(event.Id, ShareRemoved, ev.Executant, nil) + return ul.shareMessage(event.Id, ShareRemoved, ev.Executant, ev.ItemID, ev.Timestamp) } } -func (ul *UserlogService) spaceMessage(eventid string, eventname string, executant *user.UserId, spaceid string) (OC10Notification, error) { +func (ul *UserlogService) spaceDeletedMessage(eventid string, executant *user.UserId, spaceid string, spacename string, ts time.Time) (OC10Notification, error) { + _, user, err := utils.Impersonate(executant, ul.gwClient, ul.cfg.MachineAuthAPIKey) + if err != nil { + return OC10Notification{}, err + } + + subj, subjraw, msg, msgraw, err := ul.composeMessage(SpaceDeleted, map[string]string{ + "username": user.GetDisplayName(), + "spacename": spacename, + }) + if err != nil { + return OC10Notification{}, err + } + + details := ul.getDetails(user, nil, nil) + details["space"] = map[string]string{ + "id": spaceid, + "name": spacename, + } + + return OC10Notification{ + EventID: eventid, + Service: ul.cfg.Service.Name, + UserName: user.GetUsername(), + Timestamp: ts.Format(time.RFC3339Nano), + ResourceID: spaceid, + ResourceType: _resourceTypeSpace, + Subject: subj, + SubjectRaw: subjraw, + Message: msg, + MessageRaw: msgraw, + MessageDetails: details, + }, nil +} + +func (ul *UserlogService) spaceMessage(eventid string, eventname string, executant *user.UserId, spaceid string, ts time.Time) (OC10Notification, error) { ctx, user, err := utils.Impersonate(executant, ul.gwClient, ul.cfg.MachineAuthAPIKey) if err != nil { return OC10Notification{}, err @@ -97,7 +132,7 @@ func (ul *UserlogService) spaceMessage(eventid string, eventname string, executa EventID: eventid, Service: ul.cfg.Service.Name, UserName: user.GetUsername(), - Timestamp: time.Now().Format(time.RFC3339Nano), + Timestamp: ts.Format(time.RFC3339Nano), ResourceID: spaceid, ResourceType: _resourceTypeSpace, Subject: subj, @@ -108,7 +143,7 @@ func (ul *UserlogService) spaceMessage(eventid string, eventname string, executa }, nil } -func (ul *UserlogService) shareMessage(eventid string, eventname string, executant *user.UserId, resourceid *storageprovider.ResourceId) (OC10Notification, error) { +func (ul *UserlogService) shareMessage(eventid string, eventname string, executant *user.UserId, resourceid *storageprovider.ResourceId, ts time.Time) (OC10Notification, error) { ctx, user, err := utils.Impersonate(executant, ul.gwClient, ul.cfg.MachineAuthAPIKey) if err != nil { return OC10Notification{}, err @@ -131,7 +166,7 @@ func (ul *UserlogService) shareMessage(eventid string, eventname string, executa EventID: eventid, Service: ul.cfg.Service.Name, UserName: user.GetUsername(), - Timestamp: time.Now().Format(time.RFC3339Nano), + Timestamp: ts.Format(time.RFC3339Nano), ResourceID: storagespace.FormatResourceID(*info.GetId()), ResourceType: _resourceTypeShare, Subject: subj, diff --git a/services/userlog/pkg/service/service.go b/services/userlog/pkg/service/service.go index 657a306597..a83b34c7e3 100644 --- a/services/userlog/pkg/service/service.go +++ b/services/userlog/pkg/service/service.go @@ -91,8 +91,9 @@ func (ul *UserlogService) MemorizeEvents(ch <-chan events.Event) { case events.SpaceDisabled: users, err = ul.findSpaceMembers(ul.impersonate(e.Executant), e.ID.GetOpaqueId(), viewer) case events.SpaceDeleted: - // won't work - space is deleted - users, err = nil, errors.New("i do not know whom to inform") + for u, _ := range e.FinalMembers { + users = append(users, u) + } case events.SpaceShared: users, err = ul.resolveID(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID) case events.SpaceUnshared: @@ -104,7 +105,7 @@ func (ul *UserlogService) MemorizeEvents(ch <-chan events.Event) { case events.ShareCreated: users, err = ul.resolveID(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID) case events.ShareRemoved: - err = errors.New("no grantee in share removed event") + users, err = ul.resolveID(ul.impersonate(e.Executant), e.GranteeUserID, e.GranteeGroupID) case events.ShareExpired: users, err = ul.resolveID(ul.impersonate(e.ShareOwner), e.GranteeUserID, e.GranteeGroupID) } From ee96c516d79ad9f0f62518daea405bf85f5f7967 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Mon, 6 Mar 2023 13:18:07 +0100 Subject: [PATCH 09/11] add capability Signed-off-by: jkoberg --- services/frontend/pkg/revaconfig/config.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/frontend/pkg/revaconfig/config.go b/services/frontend/pkg/revaconfig/config.go index 80570badc7..70da96c8e4 100644 --- a/services/frontend/pkg/revaconfig/config.go +++ b/services/frontend/pkg/revaconfig/config.go @@ -267,6 +267,9 @@ func FrontendConfigFromStruct(cfg *config.Config) (map[string]interface{}, error "share_jail": cfg.EnableShareJail, "max_quota": cfg.MaxQuota, }, + "notifications": map[string]interface{}{ + "endpoints": []string{"list", "get", "delete"}, + }, }, "version": map[string]interface{}{ "product": "Infinite Scale", From 9255fdd9356d23240ec2c05a6110303595edceef Mon Sep 17 00:00:00 2001 From: jkoberg Date: Mon, 6 Mar 2023 14:39:37 +0100 Subject: [PATCH 10/11] add shareid to message details Signed-off-by: jkoberg --- services/userlog/pkg/service/conversion.go | 23 ++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/services/userlog/pkg/service/conversion.go b/services/userlog/pkg/service/conversion.go index 256d2e8da4..a346350894 100644 --- a/services/userlog/pkg/service/conversion.go +++ b/services/userlog/pkg/service/conversion.go @@ -7,6 +7,7 @@ import ( "time" user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1" storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" "github.com/cs3org/reva/v2/pkg/events" "github.com/cs3org/reva/v2/pkg/storagespace" @@ -66,11 +67,11 @@ func (ul *UserlogService) ConvertEvent(event *ehmsg.Event) (OC10Notification, er // share related case events.ShareCreated: - return ul.shareMessage(event.Id, ShareCreated, ev.Executant, ev.ItemID, utils.TSToTime(ev.CTime)) + return ul.shareMessage(event.Id, ShareCreated, ev.Executant, ev.ItemID, ev.ShareID, utils.TSToTime(ev.CTime)) case events.ShareExpired: - return ul.shareMessage(event.Id, ShareExpired, ev.ShareOwner, ev.ItemID, ev.ExpiredAt) + return ul.shareMessage(event.Id, ShareExpired, ev.ShareOwner, ev.ItemID, ev.ShareID, ev.ExpiredAt) case events.ShareRemoved: - return ul.shareMessage(event.Id, ShareRemoved, ev.Executant, ev.ItemID, ev.Timestamp) + return ul.shareMessage(event.Id, ShareRemoved, ev.Executant, ev.ItemID, ev.ShareID, ev.Timestamp) } } @@ -88,7 +89,7 @@ func (ul *UserlogService) spaceDeletedMessage(eventid string, executant *user.Us return OC10Notification{}, err } - details := ul.getDetails(user, nil, nil) + details := ul.getDetails(user, nil, nil, nil) details["space"] = map[string]string{ "id": spaceid, "name": spacename, @@ -139,11 +140,11 @@ func (ul *UserlogService) spaceMessage(eventid string, eventname string, executa SubjectRaw: subjraw, Message: msg, MessageRaw: msgraw, - MessageDetails: ul.getDetails(user, space, nil), + MessageDetails: ul.getDetails(user, space, nil, nil), }, nil } -func (ul *UserlogService) shareMessage(eventid string, eventname string, executant *user.UserId, resourceid *storageprovider.ResourceId, ts time.Time) (OC10Notification, error) { +func (ul *UserlogService) shareMessage(eventid string, eventname string, executant *user.UserId, resourceid *storageprovider.ResourceId, shareid *collaboration.ShareId, ts time.Time) (OC10Notification, error) { ctx, user, err := utils.Impersonate(executant, ul.gwClient, ul.cfg.MachineAuthAPIKey) if err != nil { return OC10Notification{}, err @@ -173,7 +174,7 @@ func (ul *UserlogService) shareMessage(eventid string, eventname string, executa SubjectRaw: subjraw, Message: msg, MessageRaw: msgraw, - MessageDetails: ul.getDetails(user, nil, info), + MessageDetails: ul.getDetails(user, nil, info, shareid), }, nil } @@ -203,7 +204,7 @@ func (ul *UserlogService) composeMessage(eventname string, vars map[string]strin } -func (ul *UserlogService) getDetails(user *user.User, space *storageprovider.StorageSpace, item *storageprovider.ResourceInfo) map[string]interface{} { +func (ul *UserlogService) getDetails(user *user.User, space *storageprovider.StorageSpace, item *storageprovider.ResourceInfo, shareid *collaboration.ShareId) map[string]interface{} { details := make(map[string]interface{}) if user != nil { @@ -228,6 +229,12 @@ func (ul *UserlogService) getDetails(user *user.User, space *storageprovider.Sto } } + if shareid != nil { + details["share"] = map[string]string{ + "id": shareid.GetOpaqueId(), + } + } + return details } From c1d436a271eeb5f2a0ff4af51526126c2001b3da Mon Sep 17 00:00:00 2001 From: jkoberg Date: Wed, 8 Mar 2023 12:04:49 +0100 Subject: [PATCH 11/11] bump reva Signed-off-by: jkoberg --- services/userlog/pkg/service/service.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/userlog/pkg/service/service.go b/services/userlog/pkg/service/service.go index a83b34c7e3..3a8e855997 100644 --- a/services/userlog/pkg/service/service.go +++ b/services/userlog/pkg/service/service.go @@ -111,7 +111,8 @@ func (ul *UserlogService) MemorizeEvents(ch <-chan events.Event) { } if err != nil { - ul.log.Error().Err(err).Interface("event", event).Msg("error gathering members for event") + // TODO: Find out why this errors on ci pipeline + ul.log.Debug().Err(err).Interface("event", event).Msg("error gathering members for event") continue }