feat(activitylog): finalize initial activitylog service
Signed-off-by: jkoberg <jkoberg@owncloud.com>
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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" >}}) |
|
||||
|
||||
@@ -172,6 +172,7 @@ type Nats struct {
|
||||
}
|
||||
}
|
||||
|
||||
// Activitylog is the configuration for the activitylog service
|
||||
type Activitylog struct {
|
||||
ServiceAccount ServiceAccount `yaml:"service_account"`
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user