From e05b244f6e6856f485aaae8f6a46b4446496bd19 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Fri, 7 Jun 2024 12:10:39 +0200 Subject: [PATCH] feat(activitylog): finalize initial activitylog service Signed-off-by: jkoberg --- Makefile | 1 + docs/services/general-info/port-ranges.md | 2 +- ocis/pkg/init/init.go | 1 + services/activitylog/README.md | 15 ++++- services/activitylog/pkg/service/service.go | 55 ++++++++++--------- .../activitylog/pkg/service/service_test.go | 2 +- 6 files changed, 46 insertions(+), 30 deletions(-) diff --git a/Makefile b/Makefile index 39d6c7d949..7628606840 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ L10N_MODULES := \ # if you add a module here please also add it to the .drone.star file OCIS_MODULES = \ + services/activitylog \ services/antivirus \ services/app-provider \ services/app-registry \ diff --git a/docs/services/general-info/port-ranges.md b/docs/services/general-info/port-ranges.md index 3e7d90d6a5..7ddcf0aad7 100644 --- a/docs/services/general-info/port-ranges.md +++ b/docs/services/general-info/port-ranges.md @@ -49,7 +49,7 @@ We also suggest to use the last port in your extensions' range as a debug/metric | 9180-9184 | FREE (formerly used by accounts) | | 9185-9189 | [thumbnails]({{< ref "../thumbnails/_index.md" >}}) | | 9190-9194 | [settings]({{< ref "../settings/_index.md" >}}) | -| 9195-9197 | [activitylog]({{< ref "../activitylog/_index.md >}}) | +| 9195-9197 | [activitylog]({{< ref "../activitylog/_index.md" >}}) | | 9198-9199 | [auth-service]({{< ref "../auth-service/_index.md" >}}) | | 9200-9204 | [proxy]({{< ref "../proxy/_index.md" >}}) | | 9205-9209 | [proxy]({{< ref "../proxy/_index.md" >}}) | diff --git a/ocis/pkg/init/init.go b/ocis/pkg/init/init.go index f6adc4e2a6..b3c1f0b63f 100644 --- a/ocis/pkg/init/init.go +++ b/ocis/pkg/init/init.go @@ -172,6 +172,7 @@ type Nats struct { } } +// Activitylog is the configuration for the activitylog service type Activitylog struct { ServiceAccount ServiceAccount `yaml:"service_account"` } diff --git a/services/activitylog/README.md b/services/activitylog/README.md index b4fd2e3ca4..66e44ccc75 100644 --- a/services/activitylog/README.md +++ b/services/activitylog/README.md @@ -1,2 +1,15 @@ # Activitylog Service -It is mandatory to provide a README.md file for each service. This file should contain a brief description of the service and how to use it. \ No newline at end of file + +The `activitylog` service is responsible for storing events (activities) per resource. + +## The Log Service Ecosystem + +Log services like the `activitylog`, `userlog`, `clientlog` and `sse` are responsible for composing notifications for a certain audience. + - The `userlog` service translates and adjusts messages to be human readable. + - The `clientlog` service composes machine readable messages, so clients can act without the need to query the server. + - The `sse` service is only responsible for sending these messages. It does not care about their form or language. + - The `activitylog` service stores events per resource. These can be retrieved to show item activities + +## Activitylog Store + +The `activitylog` stores activities for each resource. It works in conjunction with the `eventhistory` service to keep the data it needs to store to a minimum. diff --git a/services/activitylog/pkg/service/service.go b/services/activitylog/pkg/service/service.go index 1c5ca04f22..4f2c0cf23d 100644 --- a/services/activitylog/pkg/service/service.go +++ b/services/activitylog/pkg/service/service.go @@ -34,7 +34,7 @@ type ActivitylogService struct { gws pool.Selectable[gateway.GatewayAPIClient] } -// New is what you need to implement. +// New creates a new ActivitylogService func New(opts ...Option) (*ActivitylogService, error) { o := &Options{} for _, opt := range opts { @@ -109,7 +109,7 @@ func (a *ActivitylogService) Run() error { return nil } -// AddActivity addds the activity to the given resource and all its parents +// AddActivity adds the activity to the given resource and all its parents func (a *ActivitylogService) AddActivity(initRef *provider.Reference, eventID string, timestamp time.Time) error { gwc, err := a.gws.Next() if err != nil { @@ -126,31 +126,7 @@ func (a *ActivitylogService) AddActivity(initRef *provider.Reference, eventID st }) } -// Activities returns the activities for the given reference -func (a *ActivitylogService) Activities(ref *provider.Reference) ([]Activity, error) { - resourceID, err := storagespace.FormatReference(ref) - if err != nil { - return nil, fmt.Errorf("could not format reference: %w", err) - } - - records, err := a.store.Read(resourceID) - if err != nil && err != microstore.ErrNotFound { - return nil, fmt.Errorf("could not read activities: %w", err) - } - - if len(records) == 0 { - return []Activity{}, nil - } - - var activities []Activity - if err := json.Unmarshal(records[0].Value, &activities); err != nil { - return nil, fmt.Errorf("could not unmarshal activities: %w", err) - } - - return activities, nil -} - -// AddActivityTrashed adds the activity to trashed item +// AddActivityTrashed adds the activity to given trashed resource and all its former parents func (a *ActivitylogService) AddActivityTrashed(resourceID *provider.ResourceId, reference *provider.Reference, eventID string, timestamp time.Time) error { gwc, err := a.gws.Next() if err != nil { @@ -178,6 +154,27 @@ func (a *ActivitylogService) AddActivityTrashed(resourceID *provider.ResourceId, }) } +// Activities returns the activities for the given resource +func (a *ActivitylogService) Activities(rid *provider.ResourceId) ([]Activity, error) { + resourceID := storagespace.FormatResourceID(*rid) + + records, err := a.store.Read(resourceID) + if err != nil && err != microstore.ErrNotFound { + return nil, fmt.Errorf("could not read activities: %w", err) + } + + if len(records) == 0 { + return []Activity{}, nil + } + + var activities []Activity + if err := json.Unmarshal(records[0].Value, &activities); err != nil { + return nil, fmt.Errorf("could not unmarshal activities: %w", err) + } + + return activities, nil +} + // note: getResource is abstracted to allow unit testing, in general this will just be utils.GetResource func (a *ActivitylogService) addActivity(initRef *provider.Reference, eventID string, timestamp time.Time, getResource func(*provider.Reference) (*provider.ResourceInfo, error)) error { var ( @@ -206,6 +203,10 @@ func (a *ActivitylogService) addActivity(initRef *provider.Reference, eventID st } func (a *ActivitylogService) storeActivity(rid *provider.ResourceId, eventID string, depth int, timestamp time.Time) error { + if rid == nil { + return errors.New("resource id is required") + } + resourceID := storagespace.FormatResourceID(*rid) records, err := a.store.Read(resourceID) diff --git a/services/activitylog/pkg/service/service_test.go b/services/activitylog/pkg/service/service_test.go index 616e11c700..55b2f62716 100644 --- a/services/activitylog/pkg/service/service_test.go +++ b/services/activitylog/pkg/service/service_test.go @@ -136,7 +136,7 @@ func TestAddActivity(t *testing.T) { } for id, acts := range tc.Expected { - activities, err := alog.Activities(reference(id)) + activities, err := alog.Activities(resourceID(id)) require.NoError(t, err, tc.Name+":"+id) require.ElementsMatch(t, acts, activities, tc.Name+":"+id) }