diff --git a/changelog/unreleased/sharing-ng-driveitemid.md b/changelog/unreleased/sharing-ng-driveitemid.md new file mode 100644 index 0000000000..baacd31f4e --- /dev/null +++ b/changelog/unreleased/sharing-ng-driveitemid.md @@ -0,0 +1,9 @@ +Bugfix: graph/sharedWithMe align IDs with webdav response + +The IDs of the driveItems returned by the 'graph/v1beta1/me/drive/sharedWithMe' +endpoint are now aligned with the IDs returned in the PROPFIND response +of the webdav service. + +https://github.com/owncloud/ocis/pull/8467 +https://github.com/owncloud/ocis/issues/8420 +https://github.com/owncloud/ocis/issues/8080 diff --git a/go.mod b/go.mod index 7ade84ee2d..8c468281a1 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/cenkalti/backoff v2.2.1+incompatible github.com/coreos/go-oidc/v3 v3.9.0 github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781 - github.com/cs3org/reva/v2 v2.18.1-0.20240221074425-cac6c6935c60 + github.com/cs3org/reva/v2 v2.18.1-0.20240221104842-3fb1ef6dc93a github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25 github.com/disintegration/imaging v1.6.2 github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e diff --git a/go.sum b/go.sum index 4b9ea7da0e..d74ea38218 100644 --- a/go.sum +++ b/go.sum @@ -1019,8 +1019,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-20231023073225-7748710e0781 h1:BUdwkIlf8IS2FasrrPg8gGPHQPOrQ18MS1Oew2tmGtY= github.com/cs3org/go-cs3apis v0.0.0-20231023073225-7748710e0781/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= -github.com/cs3org/reva/v2 v2.18.1-0.20240221074425-cac6c6935c60 h1:cx4hWeWKYnIa8m5z9JncRc+lt/+RB3mwg/kZWBbDPAc= -github.com/cs3org/reva/v2 v2.18.1-0.20240221074425-cac6c6935c60/go.mod h1:GRUrOp5HbFVwZTgR9bVrMZ/MvVy+Jhxw1PdMmhhKP9E= +github.com/cs3org/reva/v2 v2.18.1-0.20240221104842-3fb1ef6dc93a h1:iD9HJRGtIqBxEl9AM9U8t1rd+SCtNyst+uotSwEebT4= +github.com/cs3org/reva/v2 v2.18.1-0.20240221104842-3fb1ef6dc93a/go.mod h1:GRUrOp5HbFVwZTgR9bVrMZ/MvVy+Jhxw1PdMmhhKP9E= 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/graph/pkg/service/v0/sharedwithme.go b/services/graph/pkg/service/v0/sharedwithme.go index 261de483c3..247ce0d158 100644 --- a/services/graph/pkg/service/v0/sharedwithme.go +++ b/services/graph/pkg/service/v0/sharedwithme.go @@ -92,7 +92,6 @@ func (g Graph) cs3ReceivedSharesToDriveItems(ctx context.Context, receivedShares group.Go(func() error { var err error // redeclare - resourceID := receivedShares[0].GetShare().GetResourceId() shareStat, err := doStat(receivedShares[0].GetShare().GetResourceId()) if shareStat == nil || err != nil { return err @@ -100,17 +99,17 @@ func (g Graph) cs3ReceivedSharesToDriveItems(ctx context.Context, receivedShares driveItem := libregraph.NewDriveItem() - // The id of the driveItem will be the composed of the StorageID and the SpaceID of the sharestorage - // appended with the ResourceID of the shared resource - // '$!::' - driveItem.SetId(storagespace.FormatResourceID(storageprovider.ResourceId{ - StorageId: utils.ShareStorageProviderID, - OpaqueId: resourceID.GetStorageId() + ":" + resourceID.GetSpaceId() + ":" + resourceID.GetOpaqueId(), - SpaceId: utils.ShareStorageSpaceID, - })) permissions := make([]libregraph.Permission, 0, len(receivedShares)) + var oldestReceivedShare *collaboration.ReceivedShare for _, receivedShare := range receivedShares { + switch { + case oldestReceivedShare == nil: + fallthrough + case utils.TSToTime(receivedShare.GetShare().GetCtime()).Before(utils.TSToTime(oldestReceivedShare.GetShare().GetCtime())): + oldestReceivedShare = receivedShare + } + permission, err := g.cs3ReceivedShareToLibreGraphPermissions(ctx, receivedShare) if err != nil { return err @@ -150,6 +149,23 @@ func (g Graph) cs3ReceivedSharesToDriveItems(ctx context.Context, receivedShares } + // To stay compatible with the usershareprovider and the webdav + // service the id of the driveItem is composed of the StorageID and + // SpaceID of the sharestorage appended with the opaque ID of + // the oldest share for the resource: + // '$! + // Note: This means that the driveitem ID will change when the oldest + // shared is removed. It would be good to have are more stable ID here (e.g. + // derived from the shared resource's ID. But as we need to use the same + // ID across all services this means we needed to make similar adjustments + // to the sharejail (usershareprovider, webdav). Which we can't currently do + // as some clients rely on the IDs used there having a special format. + driveItem.SetId(storagespace.FormatResourceID(storageprovider.ResourceId{ + StorageId: utils.ShareStorageProviderID, + OpaqueId: oldestReceivedShare.GetShare().GetId().GetOpaqueId(), + SpaceId: utils.ShareStorageSpaceID, + })) + if !driveItem.HasUIHidden() { driveItem.SetUIHidden(false) } diff --git a/services/graph/pkg/service/v0/sharedwithme_test.go b/services/graph/pkg/service/v0/sharedwithme_test.go index 7ba445f90d..3084cf4936 100644 --- a/services/graph/pkg/service/v0/sharedwithme_test.go +++ b/services/graph/pkg/service/v0/sharedwithme_test.go @@ -158,6 +158,7 @@ var _ = Describe("SharedWithMe", func() { Permissions: roleconversions.NewViewerRole(true).CS3ResourcePermissions(), }, Creator: getUserResponseShareCreator.User.Id, + Ctime: utils.TSNow(), }, MountPoint: &providerv1beta1.Reference{ ResourceId: &providerv1beta1.ResourceId{ @@ -213,6 +214,7 @@ var _ = Describe("SharedWithMe", func() { Hidden: true, Share: &collaborationv1beta1.Share{ ResourceId: toResourceID("7$8!9"), + Ctime: utils.TSNow(), }, }) @@ -405,6 +407,7 @@ var _ = Describe("SharedWithMe", func() { Permissions: roleconversions.NewViewerRole(true).CS3ResourcePermissions(), }, Creator: getUserResponseShareCreator.User.Id, + Ctime: utils.TSNow(), Grantee: &providerv1beta1.Grantee{ Type: providerv1beta1.GranteeType_GRANTEE_TYPE_GROUP, Id: &providerv1beta1.Grantee_GroupId{ diff --git a/vendor/github.com/cs3org/reva/v2/internal/grpc/services/sharesstorageprovider/sharesstorageprovider.go b/vendor/github.com/cs3org/reva/v2/internal/grpc/services/sharesstorageprovider/sharesstorageprovider.go index da3624fd7a..8d5316c6d9 100644 --- a/vendor/github.com/cs3org/reva/v2/internal/grpc/services/sharesstorageprovider/sharesstorageprovider.go +++ b/vendor/github.com/cs3org/reva/v2/internal/grpc/services/sharesstorageprovider/sharesstorageprovider.go @@ -810,53 +810,41 @@ func (s *service) ListContainer(ctx context.Context, req *provider.ListContainer return nil, errors.Wrap(err, "sharesstorageprovider: error calling ListReceivedSharesRequest") } - gatewayClient, err := s.gatewaySelector.Next() - if err != nil { - return nil, err - } - - infos := []*provider.ResourceInfo{} - for _, share := range receivedShares { - if share.GetState() != collaboration.ShareState_SHARE_STATE_ACCEPTED { + // Create map of shares that contains only the oldest share per shared resource. This is to avoid + // returning multiple resourceInfos for the same resource. But still be able to maintain a + // "somewhat" stable resourceID + oldestReceivedSharesByResourceID := make(map[string]*collaboration.ReceivedShare, len(receivedShares)) + for _, receivedShare := range receivedShares { + if receivedShare.GetState() != collaboration.ShareState_SHARE_STATE_ACCEPTED { continue } + rIDStr := storagespace.FormatResourceID(*receivedShare.GetShare().GetResourceId()) + if oldest, ok := oldestReceivedSharesByResourceID[rIDStr]; ok { + // replace if older than current oldest + if utils.TSToTime(receivedShare.GetShare().GetCtime()).Before(utils.TSToTime(oldest.GetShare().GetCtime())) { + oldestReceivedSharesByResourceID[rIDStr] = receivedShare + } + } else { + oldestReceivedSharesByResourceID[rIDStr] = receivedShare + } + } + // now compose the resourceInfos for the unified list of shares + infos := []*provider.ResourceInfo{} + for _, share := range oldestReceivedSharesByResourceID { info := shareMd[share.GetShare().GetId().GetOpaqueId()] if info == nil { - if share.GetShare().GetResourceId().GetSpaceId() == "" { - // convert backwards compatible share id - share.Share.ResourceId.StorageId, share.Share.ResourceId.SpaceId = storagespace.SplitStorageID(share.GetShare().GetResourceId().GetSpaceId()) - } - statRes, err := gatewayClient.Stat(ctx, &provider.StatRequest{ - Opaque: req.Opaque, - Ref: &provider.Reference{ - ResourceId: share.Share.ResourceId, - Path: ".", - }, - ArbitraryMetadataKeys: req.ArbitraryMetadataKeys, - }) - switch { - case err != nil: - appctx.GetLogger(ctx).Error(). - Err(err). - Interface("share", share). - Msg("sharesstorageprovider: could not make stat request when listing virtual root, skipping") - continue - case statRes.Status.Code != rpc.Code_CODE_OK: - appctx.GetLogger(ctx).Debug(). - Interface("share", share). - Interface("status", statRes.Status). - Msg("sharesstorageprovider: could not stat share when listing virtual root, skipping") - continue - } - info = statRes.Info + appctx.GetLogger(ctx).Debug(). + Interface("share", share). + Msg("sharesstorageprovider: no resource info for share") + continue } // override resource id info info.Id = &provider.ResourceId{ StorageId: utils.ShareStorageProviderID, SpaceId: utils.ShareStorageSpaceID, - OpaqueId: share.Share.Id.OpaqueId, + OpaqueId: share.GetShare().GetId().GetOpaqueId(), } info.Path = filepath.Base(share.MountPoint.Path) info.Name = info.Path diff --git a/vendor/modules.txt b/vendor/modules.txt index 71fb7154a1..b3a33e5229 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -359,7 +359,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.18.1-0.20240221074425-cac6c6935c60 +# github.com/cs3org/reva/v2 v2.18.1-0.20240221104842-3fb1ef6dc93a ## explicit; go 1.21 github.com/cs3org/reva/v2/cmd/revad/internal/grace github.com/cs3org/reva/v2/cmd/revad/runtime