diff --git a/changelog/unreleased/graph-me-drives.md b/changelog/unreleased/graph-me-drives.md new file mode 100644 index 00000000000..3104450cd94 --- /dev/null +++ b/changelog/unreleased/graph-me-drives.md @@ -0,0 +1,6 @@ +Change: Reduce drives in graph /me/drives API + +Reduced the drives in the graph `/me/drives` API to only the drives the user has access to. +The endpoint `/drives` will list all drives when the user has the permission. + +https://github.com/owncloud/ocis/pull/3629 diff --git a/changelog/unreleased/update-reva.md b/changelog/unreleased/update-reva.md index 0cce56ff613..8b4b79c912f 100644 --- a/changelog/unreleased/update-reva.md +++ b/changelog/unreleased/update-reva.md @@ -9,3 +9,4 @@ https://github.com/owncloud/ocis/pull/3570 https://github.com/owncloud/ocis/pull/3601 https://github.com/owncloud/ocis/pull/3605 https://github.com/owncloud/ocis/pull/3611 +https://github.com/owncloud/ocis/pull/3621 diff --git a/extensions/audit/pkg/service/service_test.go b/extensions/audit/pkg/service/service_test.go index 6fb5dc1ea0e..6d45dfde1a3 100644 --- a/extensions/audit/pkg/service/service_test.go +++ b/extensions/audit/pkg/service/service_test.go @@ -297,8 +297,8 @@ var testCases = []struct { }, { Alias: "File created", SystemEvent: events.FileUploaded{ - FileID: reference("sto-123", "iid-123", "./item"), - Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva + Ref: reference("sto-123", "iid-123", "./item"), + Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva }, CheckAuditEvent: func(t *testing.T, b []byte) { ev := types.AuditEventFileCreated{} @@ -312,8 +312,8 @@ var testCases = []struct { }, { Alias: "File read", SystemEvent: events.FileDownloaded{ - FileID: reference("sto-123", "iid-123", "./item"), - Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva + Ref: reference("sto-123", "iid-123", "./item"), + Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva }, CheckAuditEvent: func(t *testing.T, b []byte) { ev := types.AuditEventFileRead{} @@ -327,8 +327,8 @@ var testCases = []struct { }, { Alias: "File trashed", SystemEvent: events.ItemTrashed{ - FileID: reference("sto-123", "iid-123", "./item"), - Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva + Ref: reference("sto-123", "iid-123", "./item"), + Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva }, CheckAuditEvent: func(t *testing.T, b []byte) { ev := types.AuditEventFileDeleted{} @@ -342,7 +342,7 @@ var testCases = []struct { }, { Alias: "File renamed", SystemEvent: events.ItemMoved{ - FileID: reference("sto-123", "iid-123", "./item"), + Ref: reference("sto-123", "iid-123", "./item"), OldReference: reference("sto-123", "iid-123", "./anotheritem"), Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva }, @@ -361,8 +361,8 @@ var testCases = []struct { }, { Alias: "File purged", SystemEvent: events.ItemPurged{ - FileID: reference("sto-123", "iid-123", "./item"), - Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva + Ref: reference("sto-123", "iid-123", "./item"), + Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva }, CheckAuditEvent: func(t *testing.T, b []byte) { ev := types.AuditEventFilePurged{} @@ -376,7 +376,7 @@ var testCases = []struct { }, { Alias: "File restored", SystemEvent: events.ItemRestored{ - FileID: reference("sto-123", "iid-123", "./item"), + Ref: reference("sto-123", "iid-123", "./item"), Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva OldReference: reference("sto-123", "sto-123!iid-123/item", "./oldpath"), Key: "", @@ -396,9 +396,9 @@ var testCases = []struct { }, { Alias: "File version restored", SystemEvent: events.FileVersionRestored{ - FileID: reference("sto-123", "iid-123", "./item"), - Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva - Key: "v1", + Ref: reference("sto-123", "iid-123", "./item"), + Owner: userID("uid-123"), // NOTE: owner not yet implemented in reva + Key: "v1", }, CheckAuditEvent: func(t *testing.T, b []byte) { ev := types.AuditEventFileVersionRestored{} diff --git a/extensions/audit/pkg/types/conversion.go b/extensions/audit/pkg/types/conversion.go index 5c3f3f1c85b..fbb789ea596 100644 --- a/extensions/audit/pkg/types/conversion.go +++ b/extensions/audit/pkg/types/conversion.go @@ -234,7 +234,7 @@ func FilesAuditEvent(base AuditEvent, itemid, owner, path string) AuditEventFile // FileUploaded converts a FileUploaded event to an AuditEventFileCreated func FileUploaded(ev events.FileUploaded) AuditEventFileCreated { - iid, path, uid := extractFileDetails(ev.FileID, ev.Owner) + iid, path, uid := extractFileDetails(ev.Ref, ev.Owner) base := BasicAuditEvent(uid, "", MessageFileCreated(iid), ActionFileCreated) return AuditEventFileCreated{ AuditEventFiles: FilesAuditEvent(base, iid, uid, path), @@ -243,7 +243,7 @@ func FileUploaded(ev events.FileUploaded) AuditEventFileCreated { // FileDownloaded converts a FileDownloaded event to an AuditEventFileRead func FileDownloaded(ev events.FileDownloaded) AuditEventFileRead { - iid, path, uid := extractFileDetails(ev.FileID, ev.Owner) + iid, path, uid := extractFileDetails(ev.Ref, ev.Owner) base := BasicAuditEvent(uid, "", MessageFileRead(iid), ActionFileRead) return AuditEventFileRead{ AuditEventFiles: FilesAuditEvent(base, iid, uid, path), @@ -252,7 +252,7 @@ func FileDownloaded(ev events.FileDownloaded) AuditEventFileRead { // ItemMoved converts a ItemMoved event to an AuditEventFileRenamed func ItemMoved(ev events.ItemMoved) AuditEventFileRenamed { - iid, path, uid := extractFileDetails(ev.FileID, ev.Owner) + iid, path, uid := extractFileDetails(ev.Ref, ev.Owner) oldpath := "" if ev.OldReference != nil { @@ -268,7 +268,7 @@ func ItemMoved(ev events.ItemMoved) AuditEventFileRenamed { // ItemTrashed converts a ItemTrashed event to an AuditEventFileDeleted func ItemTrashed(ev events.ItemTrashed) AuditEventFileDeleted { - iid, path, uid := extractFileDetails(ev.FileID, ev.Owner) + iid, path, uid := extractFileDetails(ev.Ref, ev.Owner) base := BasicAuditEvent(uid, "", MessageFileTrashed(iid), ActionFileTrashed) return AuditEventFileDeleted{ AuditEventFiles: FilesAuditEvent(base, iid, uid, path), @@ -277,7 +277,7 @@ func ItemTrashed(ev events.ItemTrashed) AuditEventFileDeleted { // ItemPurged converts a ItemPurged event to an AuditEventFilePurged func ItemPurged(ev events.ItemPurged) AuditEventFilePurged { - iid, path, uid := extractFileDetails(ev.FileID, ev.Owner) + iid, path, uid := extractFileDetails(ev.Ref, ev.Owner) base := BasicAuditEvent(uid, "", MessageFilePurged(iid), ActionFilePurged) return AuditEventFilePurged{ AuditEventFiles: FilesAuditEvent(base, iid, uid, path), @@ -286,7 +286,7 @@ func ItemPurged(ev events.ItemPurged) AuditEventFilePurged { // ItemRestored converts a ItemRestored event to an AuditEventFileRestored func ItemRestored(ev events.ItemRestored) AuditEventFileRestored { - iid, path, uid := extractFileDetails(ev.FileID, ev.Owner) + iid, path, uid := extractFileDetails(ev.Ref, ev.Owner) oldpath := "" if ev.OldReference != nil { @@ -302,7 +302,7 @@ func ItemRestored(ev events.ItemRestored) AuditEventFileRestored { // FileVersionRestored converts a FileVersionRestored event to an AuditEventFileVersionRestored func FileVersionRestored(ev events.FileVersionRestored) AuditEventFileVersionRestored { - iid, path, uid := extractFileDetails(ev.FileID, ev.Owner) + iid, path, uid := extractFileDetails(ev.Ref, ev.Owner) base := BasicAuditEvent(uid, "", MessageFileVersionRestored(iid, ev.Key), ActionFileVersionRestored) return AuditEventFileVersionRestored{ AuditEventFiles: FilesAuditEvent(base, iid, uid, path), diff --git a/extensions/graph/pkg/service/v0/drives.go b/extensions/graph/pkg/service/v0/drives.go index 673f246fa57..821e664898e 100644 --- a/extensions/graph/pkg/service/v0/drives.go +++ b/extensions/graph/pkg/service/v0/drives.go @@ -31,8 +31,19 @@ import ( merrors "go-micro.dev/v4/errors" ) -// GetDrives implements the Service interface. +// GetDrives lists all drives the current user has access to func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) { + g.getDrives(w, r, false) +} + +// GetAllDrives lists all drives, including other user's drives, if the current +// user has the permission. +func (g Graph) GetAllDrives(w http.ResponseWriter, r *http.Request) { + g.getDrives(w, r, true) +} + +// getDrives implements the Service interface. +func (g Graph) getDrives(w http.ResponseWriter, r *http.Request, unrestricted bool) { sanitizedPath := strings.TrimPrefix(r.URL.Path, "/graph/v1.0/") // Parse the request with odata parser odataReq, err := godata.ParseRequest(r.Context(), sanitizedPath, r.URL.Query()) @@ -41,7 +52,10 @@ func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) { errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error()) return } - g.logger.Info().Interface("query", r.URL.Query()).Msg("Calling GetDrives") + g.logger.Debug(). + Interface("query", r.URL.Query()). + Bool("unrestricted", unrestricted). + Msg("Calling getDrives") ctx := r.Context() filters, err := generateCs3Filters(odataReq) @@ -50,7 +64,7 @@ func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) { errorcode.NotSupported.Render(w, r, http.StatusNotImplemented, err.Error()) return } - res, err := g.ListStorageSpacesWithFilters(ctx, filters) + res, err := g.ListStorageSpacesWithFilters(ctx, filters, unrestricted) switch { case err != nil: g.logger.Error().Err(err).Msg(ListStorageSpacesTransportErr) @@ -106,7 +120,7 @@ func (g Graph) GetSingleDrive(w http.ResponseWriter, r *http.Request) { ctx := r.Context() filters := []*storageprovider.ListStorageSpacesRequest_Filter{listStorageSpacesIDFilter(driveID)} - res, err := g.ListStorageSpacesWithFilters(ctx, filters) + res, err := g.ListStorageSpacesWithFilters(ctx, filters, true) switch { case err != nil: g.logger.Error().Err(err).Msg(ListStorageSpacesTransportErr) @@ -273,7 +287,8 @@ func (g Graph) UpdateDrive(w http.ResponseWriter, r *http.Request) { identifierParts := strings.Split(driveID, "!") switch len(identifierParts) { case 1: - root.StorageId, root.OpaqueId = identifierParts[0], identifierParts[0] + sID, _ := resourceid.StorageIDUnwrap(identifierParts[0]) + root.StorageId, root.OpaqueId = identifierParts[0], sID case 2: root.StorageId, root.OpaqueId = identifierParts[0], identifierParts[1] default: @@ -398,7 +413,7 @@ func (g Graph) formatDrives(ctx context.Context, baseURL *url.URL, storageSpaces } // ListStorageSpacesWithFilters List Storage Spaces using filters -func (g Graph) ListStorageSpacesWithFilters(ctx context.Context, filters []*storageprovider.ListStorageSpacesRequest_Filter) (*storageprovider.ListStorageSpacesResponse, error) { +func (g Graph) ListStorageSpacesWithFilters(ctx context.Context, filters []*storageprovider.ListStorageSpacesRequest_Filter, unrestricted bool) (*storageprovider.ListStorageSpacesResponse, error) { client := g.GetGatewayClient() permissions := make(map[string]struct{}, 1) @@ -423,17 +438,35 @@ func (g Graph) ListStorageSpacesWithFilters(ctx context.Context, filters []*stor Decoder: "json", Value: value, }, + "unrestricted": { + Decoder: "plain", + Value: []byte(strconv.FormatBool(unrestricted)), + }, }}, Filters: filters, }) return res, err } +func generateSpaceId(id *storageprovider.ResourceId) (spaceID string) { + spaceID = id.GetStorageId() + // 2nd ID to compare is the opaque ID of the Space Root + spaceID2 := id.GetOpaqueId() + if strings.Contains(spaceID, "$") { + spaceID2, _ = resourceid.StorageIDUnwrap(spaceID) + } + // Append opaqueID only if it is different from the spaceID2 + if id.OpaqueId != spaceID2 { + spaceID += "!" + id.OpaqueId + } + return spaceID +} + func (g Graph) cs3StorageSpaceToDrive(ctx context.Context, baseURL *url.URL, space *storageprovider.StorageSpace) (*libregraph.Drive, error) { if space.Root == nil { return nil, fmt.Errorf("space has no root") } - rootID := resourceid.OwnCloudResourceIDWrap(space.Root) + spaceID := generateSpaceId(space.Root) var permissions []libregraph.Permission if space.Opaque != nil { @@ -491,18 +524,14 @@ func (g Graph) cs3StorageSpaceToDrive(ctx context.Context, baseURL *url.URL, spa } } - spaceID := space.Root.StorageId - if space.Root.OpaqueId != space.Root.StorageId { - spaceID = rootID - } drive := &libregraph.Drive{ - Id: &spaceID, + Id: libregraph.PtrString(spaceID), Name: &space.Name, //"createdDateTime": "string (timestamp)", // TODO read from StorageSpace ... needs Opaque for now //"description": "string", // TODO read from StorageSpace ... needs Opaque for now DriveType: &space.SpaceType, Root: &libregraph.DriveItem{ - Id: &rootID, + Id: libregraph.PtrString(resourceid.OwnCloudResourceIDWrap(space.Root)), Permissions: permissions, }, } @@ -735,9 +764,10 @@ func (g Graph) DeleteDrive(w http.ResponseWriter, r *http.Request) { root := &storageprovider.ResourceId{} identifierParts := strings.Split(driveID, "!") + sID, _ := resourceid.StorageIDUnwrap(identifierParts[0]) switch len(identifierParts) { case 1: - root.StorageId, root.OpaqueId = identifierParts[0], identifierParts[0] + root.StorageId, root.OpaqueId = identifierParts[0], sID case 2: root.StorageId, root.OpaqueId = identifierParts[0], identifierParts[1] default: diff --git a/extensions/graph/pkg/service/v0/graph_test.go b/extensions/graph/pkg/service/v0/graph_test.go index 0d52357cf8a..8ad28656ee2 100644 --- a/extensions/graph/pkg/service/v0/graph_test.go +++ b/extensions/graph/pkg/service/v0/graph_test.go @@ -201,7 +201,7 @@ var _ = Describe("Graph", func() { Id: &provider.StorageSpaceId{OpaqueId: "aID!differentID"}, SpaceType: "mountpoint", Root: &provider.ResourceId{ - StorageId: "aID", + StorageId: "prID$aID", OpaqueId: "differentID", }, Name: "New Folder", @@ -246,11 +246,11 @@ var _ = Describe("Graph", func() { value := response["value"][0] Expect(*value.DriveAlias).To(Equal("mountpoint/new-folder")) Expect(*value.DriveType).To(Equal("mountpoint")) - Expect(*value.Id).To(Equal("aID!differentID")) + Expect(*value.Id).To(Equal("prID$aID!differentID")) Expect(*value.Name).To(Equal("New Folder")) - Expect(*value.Root.WebDavUrl).To(Equal("https://localhost:9200/dav/spaces/aID!differentID")) + Expect(*value.Root.WebDavUrl).To(Equal("https://localhost:9200/dav/spaces/prID$aID!differentID")) Expect(*value.Root.ETag).To(Equal("101112131415")) - Expect(*value.Root.Id).To(Equal("aID!differentID")) + Expect(*value.Root.Id).To(Equal("prID$aID!differentID")) Expect(*value.Root.RemoteItem.ETag).To(Equal("123456789")) Expect(*value.Root.RemoteItem.Id).To(Equal("ownerStorageID!opaqueID")) Expect(value.Root.RemoteItem.LastModifiedDateTime.UTC()).To(Equal(time.Unix(1648327606, 0).UTC())) diff --git a/extensions/graph/pkg/service/v0/service.go b/extensions/graph/pkg/service/v0/service.go index 599a558f3b3..c198834716e 100644 --- a/extensions/graph/pkg/service/v0/service.go +++ b/extensions/graph/pkg/service/v0/service.go @@ -173,7 +173,7 @@ func NewService(opts ...Option) Service { account.JWTSecret(options.Config.TokenManager.JWTSecret)), ) r.Route("/drives", func(r chi.Router) { - r.Get("/", svc.GetDrives) + r.Get("/", svc.GetAllDrives) r.Post("/", svc.CreateDrive) r.Route("/{driveID}", func(r chi.Router) { r.Patch("/", svc.UpdateDrive) diff --git a/go.mod b/go.mod index abb9d949f2f..90185fb87ae 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/blevesearch/bleve/v2 v2.3.2 github.com/coreos/go-oidc/v3 v3.1.0 github.com/cs3org/go-cs3apis v0.0.0-20220412090512-93c5918b4bde - github.com/cs3org/reva/v2 v2.0.0-20220427203355-0164880ac7d3 + github.com/cs3org/reva/v2 v2.0.0-20220502075009-8bcec2e4663e github.com/disintegration/imaging v1.6.2 github.com/glauth/glauth/v2 v2.0.0-20211021011345-ef3151c28733 github.com/go-chi/chi/v5 v5.0.7 diff --git a/go.sum b/go.sum index 97e90625a25..2ee58f6e4f1 100644 --- a/go.sum +++ b/go.sum @@ -318,10 +318,8 @@ github.com/cs3org/go-cs3apis v0.0.0-20220412090512-93c5918b4bde h1:WrD9O8ZaWvsm0 github.com/cs3org/go-cs3apis v0.0.0-20220412090512-93c5918b4bde/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= github.com/cs3org/reva v1.18.0 h1:MbPS5ZAa8RzKcTxAVeSDdISB3XXqLIxqB03BTN5ReBY= github.com/cs3org/reva v1.18.0/go.mod h1:e5VDUDu4vVWIeVkZcW//n6UZzhGGMa+Tz/whCiX3N6o= -github.com/cs3org/reva/v2 v2.0.0-20220427133111-618964eed515 h1:8pPCLxNXVz/q7PMM6Zq1lff3P8SFAu8/CXwB2eA21xc= -github.com/cs3org/reva/v2 v2.0.0-20220427133111-618964eed515/go.mod h1:2e/4HcIy54Mic3V7Ow0bz4n5dkZU0dHIZSWomFe5vng= -github.com/cs3org/reva/v2 v2.0.0-20220427203355-0164880ac7d3 h1:6sKjGI0AUW5tBXWBduaBoc+9sNYZWQR894G0oFCbus0= -github.com/cs3org/reva/v2 v2.0.0-20220427203355-0164880ac7d3/go.mod h1:2e/4HcIy54Mic3V7Ow0bz4n5dkZU0dHIZSWomFe5vng= +github.com/cs3org/reva/v2 v2.0.0-20220502075009-8bcec2e4663e h1:ym80MMvfFLHMxt6aiU67kTe/pzRBaSOUNdPkmeKYejk= +github.com/cs3org/reva/v2 v2.0.0-20220502075009-8bcec2e4663e/go.mod h1:2e/4HcIy54Mic3V7Ow0bz4n5dkZU0dHIZSWomFe5vng= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= diff --git a/tests/acceptance/expected-failures-API-on-OCIS-storage.md b/tests/acceptance/expected-failures-API-on-OCIS-storage.md index 8fd9fa56977..87bdf5ad1b0 100644 --- a/tests/acceptance/expected-failures-API-on-OCIS-storage.md +++ b/tests/acceptance/expected-failures-API-on-OCIS-storage.md @@ -1847,10 +1847,6 @@ Not everything needs to be implemented for ocis. While the oc10 testsuite covers #### [OCS status code zero](https://github.com/owncloud/ocis/issues/3621) - [apiShareManagementToShares/moveReceivedShare.feature:32](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/moveReceivedShare.feature#L32) -#### [share_with_user_type is not set in response](https://github.com/owncloud/ocis/issues/3622) -- [apiShareManagementBasicToShares/createShareToSharesFolder.feature:37](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L37) -- [apiShareManagementBasicToShares/createShareToSharesFolder.feature:38](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L38) - #### [HTTP status code differ while listing the contents of another user's trash bin](https://github.com/owncloud/ocis/issues/3561) - [apiTrashbin/trashbinFilesFolders.feature:199](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L199) - [apiTrashbin/trashbinFilesFolders.feature:223](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L223) diff --git a/tests/acceptance/expected-failures-graphAPI-on-OCIS-storage.md b/tests/acceptance/expected-failures-graphAPI-on-OCIS-storage.md index 85c610d51c3..f513a93f0a1 100644 --- a/tests/acceptance/expected-failures-graphAPI-on-OCIS-storage.md +++ b/tests/acceptance/expected-failures-graphAPI-on-OCIS-storage.md @@ -1639,10 +1639,6 @@ Not everything needs to be implemented for ocis. While the oc10 testsuite covers #### [OCS status code zero](https://github.com/owncloud/ocis/issues/3621) - [apiShareManagementToShares/moveReceivedShare.feature:32](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementToShares/moveReceivedShare.feature#L32) -#### [share_with_user_type is not set in response](https://github.com/owncloud/ocis/issues/3622) -- [apiShareManagementBasicToShares/createShareToSharesFolder.feature:37](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L37) -- [apiShareManagementBasicToShares/createShareToSharesFolder.feature:38](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiShareManagementBasicToShares/createShareToSharesFolder.feature#L38) - #### [HTTP status code differ while listing the contents of another user's trash bin](https://github.com/owncloud/ocis/issues/3561) - [apiTrashbin/trashbinFilesFolders.feature:199](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L199) - [apiTrashbin/trashbinFilesFolders.feature:223](https://github.com/owncloud/core/blob/master/tests/acceptance/features/apiTrashbin/trashbinFilesFolders.feature#L223) diff --git a/tests/acceptance/features/bootstrap/SpacesContext.php b/tests/acceptance/features/bootstrap/SpacesContext.php index 61d8f20b0d3..5f9c23357d0 100644 --- a/tests/acceptance/features/bootstrap/SpacesContext.php +++ b/tests/acceptance/features/bootstrap/SpacesContext.php @@ -220,6 +220,24 @@ public function getSpaceByName(string $user, string $spaceName): array { return $spaces[$spaceName]; } + /** + * The method finds available spaces to the manager user and returns the space by spaceName + * + * @param string $user + * @param string $spaceName + * + * @return array + */ + public function getSpaceByNameManager(string $user, string $spaceName): array { + $this->theUserListsAllAvailableSpacesUsingTheGraphApi($user); + + $spaces = $this->getAvailableSpaces(); + Assert::assertIsArray($spaces[$spaceName], "Space with name $spaceName for user $user not found"); + Assert::assertNotEmpty($spaces[$spaceName]["root"]["webDavUrl"], "WebDavUrl for space with name $spaceName for user $user not found"); + + return $spaces[$spaceName]; + } + /** * The method finds file by fileName and spaceName and returns data of file wich contains in responseHeader * fileName contains the path, if the file is in the folder @@ -349,7 +367,7 @@ public function cleanDataAfterTests(): void /** * The method first disables and then deletes spaces * @param string $driveType - * + * * @return void * * @throws Exception @@ -410,6 +428,33 @@ public function listMySpacesRequest( return HttpRequestHelper::get($fullUrl, $xRequestId, $user, $password, $headers, $body); } + /** + * Send Graph List All Spaces Request + * + * @param string $user + * @param string $password + * @param string $urlArguments + * @param string $xRequestId + * @param array $body + * @param array $headers + * + * @return ResponseInterface + * + * @throws GuzzleException + */ + public function listAllSpacesRequest( + string $user, + string $password, + string $urlArguments = '', + string $xRequestId = '', + array $body = [], + array $headers = [] + ): ResponseInterface { + $fullUrl = $this->baseUrl . "/graph/v1.0/drives/" . $urlArguments; + + return HttpRequestHelper::get($fullUrl, $xRequestId, $user, $password, $headers, $body); + } + /** * Send Graph List Single Space Request * @@ -530,6 +575,24 @@ public function theUserListsAllHisAvailableSpacesUsingTheGraphApi(string $user): $this->rememberTheAvailableSpaces(); } + /** + * + * @param string $user + * + * @return void + * + * @throws GuzzleException + */ + public function theUserListsAllAvailableSpacesUsingTheGraphApi(string $user): void { + $this->featureContext->setResponse( + $this->listAllSpacesRequest( + $user, + $this->featureContext->getPasswordForUser($user) + ) + ); + $this->rememberTheAvailableSpaces(); + } + /** * @When /^user "([^"]*)" lists all available spaces via the GraphApi with query "([^"]*)"$/ * @@ -1145,7 +1208,7 @@ public function findEntryFromPropfindResponse( $results = []; if ($multistatusResults !== null) { foreach ($multistatusResults as $multistatusResult) { - $entryPath = $multistatusResult['value'][0]['value']; + $entryPath = \urldecode($multistatusResult['value'][0]['value']); $entryName = \str_replace($topWebDavPath, "", $entryPath); $entryName = \rawurldecode($entryName); $entryName = \trim($entryName, "/"); @@ -1951,7 +2014,7 @@ public function sendRestoreSpaceRequest( string $userWithManagerRights = '' ): void { if (!empty($userWithManagerRights)) { - $space = $this->getSpaceByName($userWithManagerRights, $spaceName); + $space = $this->getSpaceByNameManager($userWithManagerRights, $spaceName); } else { $space = $this->getSpaceByName($user, $spaceName); }