Repository: owncloud/ocis
Pull request #10104 (2024-09-18 14:52:39)

Added the ShareUpdate activity in the space context.
<!--
Thanks for submitting a change to ownCloud!

This is the bug tracker for the oCIS component. Find other components at https://github.com/owncloud/core/blob/master/.github/CONTRIBUTING.md#guidelines

For fixing potential security issues please see https://owncloud.org/security/

To make it possible for us to get your change reviewed and merged please carefully fill out the requested information below.

Please note that any kind of change needs first be submitted to the master branch which holds the next version of oCIS.

Please set the following labels:

- Set label "Status:Needs-Review" for review or "Status:In-Progress" if the PR still has open tasks.
- Assignment: assign to self
- Reviewers: pick at least one
-->

## Description
<!--- Describe your changes in detail -->

## Related Issue
<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->
- Fixes <issue_link>

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->

## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
- test environment:
- test case 1:
- test case 2:
- ...

## Screenshots (if appropriate):

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Technical debt
- [ ] Tests only (no source changes)

## Checklist:
<!-- Tick the checkboxes when done. -->
<!-- Raise documentation ticket in owncloud.github.io/ -->
- [ ] Code changes
- [ ] Unit tests added
- [ ] Acceptance tests added
- [ ] Documentation ticket raised: <link> 


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=10104&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=10104&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=10104&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10104&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10104&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104)


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=10104&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=10104&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=10104&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10104&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10104&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104)


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=10104&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=10104&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=10104&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10104&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10104&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104)


2403905: @tboerger The few questions about the activity templates
When a user updates the `permission` and `expiration` the ocis emit a single event.
Then the activity uses the template for this event like `MessageShareUpdated    = l10n.Template("{user} updated {field} for the {resource}")`
1. Can we join the fields enum by comma? `permission` and `expiration` => `permission, expiration`
2. We translate the activity message template on the server side. Should we also translate the field data that represents as updated field ( `permission, expiration`) in this case? 

Now: 
| **admin** updated **expiration, permissions** for **the New folder** |
 translated as 
| **admin** оновив **expiration, permissions** для **the New folder** |

Could be:
| **admin** updated **expiration, permissions** for **the New folder** |
 translated as
| **admin** оновив **термін дії, дозволи** для **the New folder** |


<img width="410" alt="Screenshot 2024-09-19 at 09 46 35" src="https://github.com/user-attachments/assets/9e329769-d3ab-442d-9b9d-b7f487631d90">

tbsbdr: @2403905 1,2:yes 🙂
sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [3 New Bugs](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


sonarcloud[bot]: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104) **Quality Gate failed**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [2 New Bugs](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104) (required ≤ 0)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104)

##   
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png '') Catch issues before they fail your Quality Gate with our IDE extension ![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png '') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=pull-request)


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=10104&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=10104&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=10104&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [3.1% Coverage on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10104&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10104&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104)


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=10104&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=owncloud_ocis&pullRequest=10104&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=owncloud_ocis&pullRequest=10104&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [3.1% Coverage on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10104&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=owncloud_ocis&pullRequest=10104&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=owncloud_ocis&pullRequest=10104)


micbar: who mentioned @tboerger here? 
micbar: This needs a rebase to get a green CI, we need #10131

Patch:
diff --git a/changelog/unreleased/fix-acitivity-update-share.md b/changelog/unreleased/fix-acitivity-update-share.md
new file mode 100644
index 00000000000..7814c03d034
--- /dev/null
+++ b/changelog/unreleased/fix-acitivity-update-share.md
@@ -0,0 +1,6 @@
+Bugfix: Added ShareUpdate activity
+
+Added the ShareUpdate activity in the space context.
+
+https://github.com/owncloud/ocis/pull/10104
+https://github.com/owncloud/ocis/issues/10011
diff --git a/go.mod b/go.mod
index 3bb85e73b19..a3740902525 100644
--- a/go.mod
+++ b/go.mod
@@ -15,7 +15,7 @@ require (
 	github.com/cenkalti/backoff v2.2.1+incompatible
 	github.com/coreos/go-oidc/v3 v3.11.0
 	github.com/cs3org/go-cs3apis v0.0.0-20240724121416-062c4e3046cb
-	github.com/cs3org/reva/v2 v2.24.2-0.20240918135034-5a494dc2ebf7
+	github.com/cs3org/reva/v2 v2.24.2-0.20240919151635-556263192484
 	github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
 	github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
 	github.com/egirna/icap-client v0.1.1
diff --git a/go.sum b/go.sum
index f4796878ba8..2a9d17f66c7 100644
--- a/go.sum
+++ b/go.sum
@@ -255,8 +255,8 @@ github.com/crewjam/saml v0.4.14 h1:g9FBNx62osKusnFzs3QTN5L9CVA/Egfgm+stJShzw/c=
 github.com/crewjam/saml v0.4.14/go.mod h1:UVSZCf18jJkk6GpWNVqcyQJMD5HsRugBPf4I1nl2mME=
 github.com/cs3org/go-cs3apis v0.0.0-20240724121416-062c4e3046cb h1:KmYZDReplv/yfwc1LNYpDcVhVujC3Pasv6WjXx1haSU=
 github.com/cs3org/go-cs3apis v0.0.0-20240724121416-062c4e3046cb/go.mod h1:yyP8PRo0EZou3nSH7H4qjlzQwaydPeIRNgX50npQHpE=
-github.com/cs3org/reva/v2 v2.24.2-0.20240918135034-5a494dc2ebf7 h1:htjWHMNWh1YLOArxMtjV9zvj9Uu214iyYOHn8wi/10Q=
-github.com/cs3org/reva/v2 v2.24.2-0.20240918135034-5a494dc2ebf7/go.mod h1:p7CHBXcg6sSqB+0JMNDfC1S7TSh9FghXkw1kTV3KcJI=
+github.com/cs3org/reva/v2 v2.24.2-0.20240919151635-556263192484 h1:MeHzCFCh5WttP2hz7UTCHgV6WQXrucQXSyQs5+aIrcY=
+github.com/cs3org/reva/v2 v2.24.2-0.20240919151635-556263192484/go.mod h1:p7CHBXcg6sSqB+0JMNDfC1S7TSh9FghXkw1kTV3KcJI=
 github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
 github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
 github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
diff --git a/services/activitylog/pkg/command/server.go b/services/activitylog/pkg/command/server.go
index e2a92a3ec64..4989abb1c37 100644
--- a/services/activitylog/pkg/command/server.go
+++ b/services/activitylog/pkg/command/server.go
@@ -35,6 +35,7 @@ var _registeredEvents = []events.Unmarshaller{
 	events.ItemPurged{},
 	events.ItemMoved{},
 	events.ShareCreated{},
+	events.ShareUpdated{},
 	events.ShareRemoved{},
 	events.LinkCreated{},
 	events.LinkUpdated{},
diff --git a/services/activitylog/pkg/service/http.go b/services/activitylog/pkg/service/http.go
index ea5ea415817..543c85e0e2a 100644
--- a/services/activitylog/pkg/service/http.go
+++ b/services/activitylog/pkg/service/http.go
@@ -115,6 +115,9 @@ func (s *ActivitylogService) HandleGetItemActivities(w http.ResponseWriter, r *h
 			vars    map[string]interface{}
 		)
 
+		loc := l10n.MustGetUserLocale(r.Context(), activeUser.GetId().GetOpaqueId(), r.Header.Get(l10n.HeaderAcceptLanguage), s.valService)
+		t := l10n.NewTranslatorFromCommonConfig(s.cfg.DefaultLanguage, _domain, s.cfg.TranslationPath, _localeFS, _localeSubPath)
+
 		switch ev := s.unwrapEvent(e).(type) {
 		case nil:
 			// error already logged in unwrapEvent
@@ -152,6 +155,13 @@ func (s *ActivitylogService) HandleGetItemActivities(w http.ResponseWriter, r *h
 			message = MessageShareCreated
 			ts = utils.TSToTime(ev.CTime)
 			vars, err = s.GetVars(ctx, WithResource(toRef(ev.ItemID), false), WithUser(ev.Executant, ""), WithSharee(ev.GranteeUserID, ev.GranteeGroupID))
+		case events.ShareUpdated:
+			if ev.Sharer != nil && ev.ItemID != nil && ev.Sharer.GetOpaqueId() == ev.ItemID.GetSpaceId() {
+				continue
+			}
+			message = MessageShareUpdated
+			ts = utils.TSToTime(ev.MTime)
+			vars, err = s.GetVars(ctx, WithResource(toRef(ev.ItemID), false), WithUser(ev.Executant, ""), WithTranslation(&t, loc, "field", ev.UpdateMask))
 		case events.ShareRemoved:
 			message = MessageShareDeleted
 			ts = ev.Timestamp
@@ -165,11 +175,12 @@ func (s *ActivitylogService) HandleGetItemActivities(w http.ResponseWriter, r *h
 				continue
 			}
 			message = MessageLinkUpdated
-			ts = utils.TSToTime(ev.CTime)
+			ts = utils.TSToTime(ev.MTime)
 			vars, err = s.GetVars(ctx,
 				WithResource(toRef(ev.ItemID), false),
 				WithUser(ev.Executant, ""),
-				WithLinkFieldUpdated(&ev))
+				WithTranslation(&t, loc, "field", []string{ev.FieldUpdated}),
+				WithVar("token", ev.ItemID.GetOpaqueId(), ev.Token))
 		case events.LinkRemoved:
 			message = MessageLinkDeleted
 			ts = utils.TSToTime(ev.Timestamp)
@@ -189,9 +200,6 @@ func (s *ActivitylogService) HandleGetItemActivities(w http.ResponseWriter, r *h
 			continue
 		}
 
-		loc := l10n.MustGetUserLocale(r.Context(), activeUser.GetId().GetOpaqueId(), r.Header.Get(l10n.HeaderAcceptLanguage), s.valService)
-		t := l10n.NewTranslatorFromCommonConfig(s.cfg.DefaultLanguage, _domain, s.cfg.TranslationPath, _localeFS, _localeSubPath)
-
 		resp.Activities = append(resp.Activities, NewActivity(t.Translate(message, loc), ts, e.GetId(), vars))
 	}
 
diff --git a/services/activitylog/pkg/service/response.go b/services/activitylog/pkg/service/response.go
index cfd45768aac..0e790a2b920 100644
--- a/services/activitylog/pkg/service/response.go
+++ b/services/activitylog/pkg/service/response.go
@@ -3,8 +3,8 @@ package service
 import (
 	"context"
 	"fmt"
-	"github.com/cs3org/reva/v2/pkg/events"
 	"path/filepath"
+	"strings"
 	"time"
 
 	gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
@@ -27,12 +27,29 @@ var (
 	MessageResourceMoved   = l10n.Template("{user} moved {resource} to {folder}")
 	MessageResourceRenamed = l10n.Template("{user} renamed {oldResource} to {resource}")
 	MessageShareCreated    = l10n.Template("{user} shared {resource} with {sharee}")
+	MessageShareUpdated    = l10n.Template("{user} updated {field} for the {resource}")
 	MessageShareDeleted    = l10n.Template("{user} removed {sharee} from {resource}")
 	MessageLinkCreated     = l10n.Template("{user} shared {resource} via link")
 	MessageLinkUpdated     = l10n.Template("{user} updated {field} for a link {token} on {resource}")
 	MessageLinkDeleted     = l10n.Template("{user} removed link to {resource}")
 	MessageSpaceShared     = l10n.Template("{user} added {sharee} as member of {space}")
 	MessageSpaceUnshared   = l10n.Template("{user} removed {sharee} from {space}")
+
+	StrSomeField      = l10n.Template(_someField)
+	StrPermission     = l10n.Template(_permission)
+	StrPassword       = l10n.Template(_password)
+	StrExpirationDate = l10n.Template(_expirationDate)
+	StrDisplayName    = l10n.Template(_displayName)
+	StrDescription    = l10n.Template(_description)
+)
+
+const (
+	_someField      = "some field"
+	_permission     = "permission"
+	_password       = "password"
+	_expirationDate = "expiration date"
+	_displayName    = "display name"
+	_description    = "description"
 )
 
 // GetActivitiesResponse is the response on GET activities requests
@@ -228,29 +245,29 @@ func WithSpace(spaceid *provider.StorageSpaceId) ActivityOption {
 	}
 }
 
-// WithLinkFieldUpdated sets the field and token variables for an activity
-func WithLinkFieldUpdated(e *events.LinkUpdated) ActivityOption {
+// WithTranslation sets a variable that translation is needed for
+func WithTranslation(t *l10n.Translator, locale string, key string, values []string) ActivityOption {
 	return func(_ context.Context, _ gateway.GatewayAPIClient, vars map[string]interface{}) error {
-		f := "some field"
-		switch e.FieldUpdated {
-		case "TYPE_PERMISSIONS":
-			f = "permission"
-		case "TYPE_PASSWORD":
-			f = "password"
-		case "TYPE_EXPIRATION":
-			f = "expiration date"
-		case "TYPE_DISPLAYNAME":
-			f = "display name"
-		case "TYPE_DESCRIPTION":
-			f = "description"
+		f := t.Translate(StrSomeField, locale)
+		if len(values) > 0 {
+			for i := range values {
+				values[i] = t.Translate(mapField(values[i]), locale)
+			}
+			f = strings.Join(values, ", ")
 		}
-		vars["field"] = Resource{
-			ID:   e.ItemID.GetOpaqueId(),
+		vars[key] = Resource{
 			Name: f,
 		}
-		vars["token"] = Resource{
-			ID:   e.ItemID.GetOpaqueId(),
-			Name: e.Token,
+		return nil
+	}
+}
+
+// WithVar sets a variable for an activity
+func WithVar(key, id, name string) ActivityOption {
+	return func(_ context.Context, _ gateway.GatewayAPIClient, vars map[string]interface{}) error {
+		vars[key] = Resource{
+			ID:   id,
+			Name: name,
 		}
 		return nil
 	}
@@ -284,3 +301,19 @@ func (s *ActivitylogService) GetVars(ctx context.Context, opts ...ActivityOption
 
 	return vars, nil
 }
+
+func mapField(val string) string {
+	switch val {
+	case "TYPE_PERMISSIONS", "permission":
+		return _permission
+	case "TYPE_PASSWORD", "password":
+		return _password
+	case "TYPE_EXPIRATION", "expiration":
+		return _expirationDate
+	case "TYPE_DISPLAYNAME":
+		return _displayName
+	case "TYPE_DESCRIPTION":
+		return _description
+	}
+	return _someField
+}
diff --git a/services/activitylog/pkg/service/service.go b/services/activitylog/pkg/service/service.go
index 168a12ccd08..33aa2e4f81e 100644
--- a/services/activitylog/pkg/service/service.go
+++ b/services/activitylog/pkg/service/service.go
@@ -110,13 +110,17 @@ func (a *ActivitylogService) Run() {
 			err = a.AddActivity(ev.Ref, e.ID, utils.TSToTime(ev.Timestamp))
 		case events.ShareCreated:
 			err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.CTime))
+		case events.ShareUpdated:
+			if ev.Sharer != nil && ev.ItemID != nil && ev.Sharer.GetOpaqueId() != ev.ItemID.GetSpaceId() {
+				err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.MTime))
+			}
 		case events.ShareRemoved:
 			err = a.AddActivity(toRef(ev.ItemID), e.ID, ev.Timestamp)
 		case events.LinkCreated:
 			err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.CTime))
 		case events.LinkUpdated:
 			if ev.Sharer != nil && ev.ItemID != nil && ev.Sharer.GetOpaqueId() != ev.ItemID.GetSpaceId() {
-				err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.CTime))
+				err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.MTime))
 			}
 		case events.LinkRemoved:
 			err = a.AddActivity(toRef(ev.ItemID), e.ID, utils.TSToTime(ev.Timestamp))
diff --git a/services/audit/pkg/types/conversion.go b/services/audit/pkg/types/conversion.go
index 55c6da847a7..62fa363b517 100644
--- a/services/audit/pkg/types/conversion.go
+++ b/services/audit/pkg/types/conversion.go
@@ -115,7 +115,7 @@ func ShareUpdated(ev events.ShareUpdated) AuditEventShareUpdated {
 func LinkUpdated(ev events.LinkUpdated) AuditEventShareUpdated {
 	uid := ev.Sharer.OpaqueId
 	with, typ := "", _linktype
-	base := BasicAuditEvent(uid, formatTime(ev.CTime), MessageLinkUpdated(uid, ev.ShareID.OpaqueId, ev.FieldUpdated), updateType(ev.FieldUpdated))
+	base := BasicAuditEvent(uid, formatTime(ev.MTime), MessageLinkUpdated(uid, ev.ShareID.GetOpaqueId(), ev.FieldUpdated), updateType(ev.FieldUpdated))
 	return AuditEventShareUpdated{
 		AuditEventSharing: SharingAuditEvent(ev.ShareID.GetOpaqueId(), ev.ItemID.OpaqueId, uid, base),
 		ShareOwner:        uid,
diff --git a/vendor/github.com/cs3org/reva/v2/internal/grpc/interceptors/eventsmiddleware/conversion.go b/vendor/github.com/cs3org/reva/v2/internal/grpc/interceptors/eventsmiddleware/conversion.go
index 87ee14af578..9e5a739e0fa 100644
--- a/vendor/github.com/cs3org/reva/v2/internal/grpc/interceptors/eventsmiddleware/conversion.go
+++ b/vendor/github.com/cs3org/reva/v2/internal/grpc/interceptors/eventsmiddleware/conversion.go
@@ -78,12 +78,6 @@ func ShareRemoved(r *collaboration.RemoveShareResponse, req *collaboration.Remov
 
 // ShareUpdated converts the response to an event
 func ShareUpdated(r *collaboration.UpdateShareResponse, req *collaboration.UpdateShareRequest, executant *user.UserId) events.ShareUpdated {
-	updated := ""
-	if req.Field.GetPermissions() != nil {
-		updated = "permissions"
-	} else if req.Field.GetDisplayName() != "" {
-		updated = "displayname"
-	}
 	return events.ShareUpdated{
 		Executant:      executant,
 		ShareID:        r.Share.Id,
@@ -93,7 +87,7 @@ func ShareUpdated(r *collaboration.UpdateShareResponse, req *collaboration.Updat
 		GranteeGroupID: r.Share.GetGrantee().GetGroupId(),
 		Sharer:         r.Share.Creator,
 		MTime:          r.Share.Mtime,
-		Updated:        updated,
+		UpdateMask:     req.GetUpdateMask().GetPaths(),
 	}
 }
 
@@ -139,7 +133,7 @@ func LinkUpdated(r *link.UpdatePublicShareResponse, req *link.UpdatePublicShareR
 		DisplayName:       r.Share.DisplayName,
 		Expiration:        r.Share.Expiration,
 		PasswordProtected: r.Share.PasswordProtected,
-		CTime:             r.Share.Ctime,
+		MTime:             r.Share.Mtime,
 		Token:             r.Share.Token,
 		FieldUpdated:      link.UpdatePublicShareRequest_Update_Type_name[int32(req.Update.GetType())],
 	}
diff --git a/vendor/github.com/cs3org/reva/v2/pkg/events/sharing.go b/vendor/github.com/cs3org/reva/v2/pkg/events/sharing.go
index 6c438d5dbad..daa13ad11b6 100644
--- a/vendor/github.com/cs3org/reva/v2/pkg/events/sharing.go
+++ b/vendor/github.com/cs3org/reva/v2/pkg/events/sharing.go
@@ -84,8 +84,9 @@ type ShareUpdated struct {
 	Sharer         *user.UserId
 	MTime          *types.Timestamp
 
-	// indicates what was updated - one of "displayname", "permissions"
-	Updated string
+	Updated string // Deprecated
+	// indicates what was updated
+	UpdateMask []string
 }
 
 // Unmarshal to fulfill umarshaller interface
@@ -165,7 +166,7 @@ type LinkUpdated struct {
 	DisplayName       string
 	Expiration        *types.Timestamp
 	PasswordProtected bool
-	CTime             *types.Timestamp
+	MTime             *types.Timestamp
 	Token             string
 
 	FieldUpdated string
diff --git a/vendor/github.com/cs3org/reva/v2/pkg/utils/utils.go b/vendor/github.com/cs3org/reva/v2/pkg/utils/utils.go
index 8f97f7be819..77e1c9ef0ec 100644
--- a/vendor/github.com/cs3org/reva/v2/pkg/utils/utils.go
+++ b/vendor/github.com/cs3org/reva/v2/pkg/utils/utils.go
@@ -146,6 +146,9 @@ func TSToUnixNano(ts *types.Timestamp) uint64 {
 
 // TSToTime converts a protobuf Timestamp to Go's time.Time.
 func TSToTime(ts *types.Timestamp) time.Time {
+	if ts == nil {
+		return time.Time{}
+	}
 	return time.Unix(int64(ts.Seconds), int64(ts.Nanos))
 }
 
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 91659cf4714..8df98f3242b 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -367,7 +367,7 @@ github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1
 github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1
 github.com/cs3org/go-cs3apis/cs3/tx/v1beta1
 github.com/cs3org/go-cs3apis/cs3/types/v1beta1
-# github.com/cs3org/reva/v2 v2.24.2-0.20240918135034-5a494dc2ebf7
+# github.com/cs3org/reva/v2 v2.24.2-0.20240919151635-556263192484
 ## explicit; go 1.21
 github.com/cs3org/reva/v2/cmd/revad/internal/grace
 github.com/cs3org/reva/v2/cmd/revad/runtime


Test patch:
diff --git a/services/audit/pkg/service/service_test.go b/services/audit/pkg/service/service_test.go
index 95224d314e5..b18209409b3 100644
--- a/services/audit/pkg/service/service_test.go
+++ b/services/audit/pkg/service/service_test.go
@@ -123,7 +123,7 @@ var testCases = []struct {
 				Sharer:            userID("sharing-userid"),
 				ItemID:            resourceID("provider-1", "storage-1", "itemid-1"),
 				Permissions:       linkPermissions("stat"),
-				CTime:             timestamp(10e8),
+				MTime:             timestamp(10e8),
 				DisplayName:       "link",
 				Expiration:        timestamp(10e8 + 10e5),
 				PasswordProtected: true,