diff --git a/changelog/unreleased/ocm-mount-received-shares.md b/changelog/unreleased/ocm-mount-received-shares.md new file mode 100644 index 0000000000..28408f5563 --- /dev/null +++ b/changelog/unreleased/ocm-mount-received-shares.md @@ -0,0 +1,3 @@ +Enhancement: Expose OCM received shares as a local mount + +https://github.com/cs3org/reva/pull/3668 \ No newline at end of file diff --git a/go.mod b/go.mod index d67f2f138e..cd782bd66e 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/cheggaaa/pb v1.0.29 github.com/coreos/go-oidc v2.2.1+incompatible github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e - github.com/cs3org/go-cs3apis v0.0.0-20230220105024-9b045290a172 + github.com/cs3org/go-cs3apis v0.0.0-20230221082129-bcf2b5cf8870 github.com/dgraph-io/ristretto v0.1.1 github.com/dolthub/go-mysql-server v0.14.0 github.com/eventials/go-tus v0.0.0-20200718001131-45c7ec8f5d59 diff --git a/go.sum b/go.sum index 6719b80065..faba1f1292 100644 --- a/go.sum +++ b/go.sum @@ -305,10 +305,10 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e h1:tqSPWQeueWTKnJVMJffz4pz0o1WuQxJ28+5x5JgaHD8= github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4= -github.com/cs3org/go-cs3apis v0.0.0-20230214162720-ac2ceb2ad50e h1:w4A601AS6pC+3eHb9XDZe5Ctpi4cFyoFnsed2Yisd8Q= -github.com/cs3org/go-cs3apis v0.0.0-20230214162720-ac2ceb2ad50e/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= github.com/cs3org/go-cs3apis v0.0.0-20230220105024-9b045290a172 h1:S2WbxNSNhrrQGIlvfNkMAmekcQtINvmU51gsKFZEKPo= github.com/cs3org/go-cs3apis v0.0.0-20230220105024-9b045290a172/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= +github.com/cs3org/go-cs3apis v0.0.0-20230221082129-bcf2b5cf8870 h1:MUYOLg0HxBYDmrtZONje+49yanhqGKmYvishv7GaSvw= +github.com/cs3org/go-cs3apis v0.0.0-20230221082129-bcf2b5cf8870/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= diff --git a/internal/grpc/services/ocmcore/ocmcore.go b/internal/grpc/services/ocmcore/ocmcore.go index 2d25848551..7e7425eca7 100644 --- a/internal/grpc/services/ocmcore/ocmcore.go +++ b/internal/grpc/services/ocmcore/ocmcore.go @@ -121,12 +121,13 @@ func (s *service) CreateOCMCoreShare(ctx context.Context, req *ocmcore.CreateOCM UserId: req.ShareWith, }, }, - ShareType: req.ShareType, - Owner: req.Owner, - Creator: req.Sender, - Protocols: req.Protocols, - Expiration: req.Expiration, - State: ocm.ShareState_SHARE_STATE_PENDING, + ResourceType: req.ResourceType, + ShareType: req.ShareType, + Owner: req.Owner, + Creator: req.Sender, + Protocols: req.Protocols, + Expiration: req.Expiration, + State: ocm.ShareState_SHARE_STATE_PENDING, }) if err != nil { // TODO: identify errors diff --git a/pkg/ocm/share/repository/sql/conversions.go b/pkg/ocm/share/repository/sql/conversions.go index 6e2bdf64c8..716624d87c 100644 --- a/pkg/ocm/share/repository/sql/conversions.go +++ b/pkg/ocm/share/repository/sql/conversions.go @@ -34,6 +34,9 @@ import ( // ShareType is the type of the share. type ShareType int +// ItemType is the type of the shares resource. +type ItemType int + // AccessMethod is method granted by the sharer to access // the shared resource. type AccessMethod int @@ -80,6 +83,13 @@ const ( TransferProtocol ) +const ( + // ItemTypeFile is used when the shared resource is a file. + ItemTypeFile ItemType = iota + // ItemTypeFolder is used when the shared resource is a folder. + ItemTypeFolder +) + func convertFromCS3OCMShareType(shareType ocm.ShareType) ShareType { switch shareType { case ocm.ShareType_SHARE_TYPE_USER: @@ -141,6 +151,7 @@ type dbReceivedShare struct { Name string Prefix string ItemSource string + ItemType ItemType ShareWith string Owner string Initiator string @@ -242,9 +253,10 @@ func convertToCS3OCMReceivedShare(s *dbReceivedShare, p []*ocm.Protocol) *ocm.Re Mtime: &types.Timestamp{ Seconds: uint64(s.Mtime), }, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: convertToCS3OCMShareState(s.State), - Protocols: p, + ResourceType: convertToCS3ResourceType(s.ItemType), + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: convertToCS3OCMShareState(s.State), + Protocols: p, } if s.Expiration != 0 { share.Expiration = &types.Timestamp{ @@ -279,3 +291,23 @@ func convertToCS3Protocol(p *dbProtocol) *ocm.Protocol { } return nil } + +func convertToCS3ResourceType(t ItemType) provider.ResourceType { + switch t { + case ItemTypeFile: + return provider.ResourceType_RESOURCE_TYPE_FILE + case ItemTypeFolder: + return provider.ResourceType_RESOURCE_TYPE_CONTAINER + } + return provider.ResourceType_RESOURCE_TYPE_INVALID +} + +func convertFromCS3ResourceType(t provider.ResourceType) ItemType { + switch t { + case provider.ResourceType_RESOURCE_TYPE_FILE: + return ItemTypeFile + case provider.ResourceType_RESOURCE_TYPE_CONTAINER: + return ItemTypeFolder + } + return -1 +} diff --git a/pkg/ocm/share/repository/sql/init.sql b/pkg/ocm/share/repository/sql/init.sql index ec94701d84..73f6b3b464 100644 --- a/pkg/ocm/share/repository/sql/init.sql +++ b/pkg/ocm/share/repository/sql/init.sql @@ -40,6 +40,7 @@ CREATE TABLE IF NOT EXISTS ocm_received_shares ( name VARCHAR(255) NOT NULL, fileid_prefix VARCHAR(255) NOT NULL, item_source VARCHAR(255) NOT NULL, + item_type TINYINT NOT NULL, share_with VARCHAR(255) NOT NULL, owner VARCHAR(255) NOT NULL, initiator VARCHAR(255) NOT NULL, diff --git a/pkg/ocm/share/repository/sql/sql.go b/pkg/ocm/share/repository/sql/sql.go index 6bf58ddd0e..984c1e59f5 100644 --- a/pkg/ocm/share/repository/sql/sql.go +++ b/pkg/ocm/share/repository/sql/sql.go @@ -493,8 +493,8 @@ func storeProtocol(tx *sql.Tx, shareID int64, p Protocol) (int64, error) { // StoreReceivedShare stores a received share. func (m *mgr) StoreReceivedShare(ctx context.Context, s *ocm.ReceivedShare) (*ocm.ReceivedShare, error) { if err := transaction(ctx, m.db, func(tx *sql.Tx) error { - query := "INSERT INTO ocm_received_shares SET name=?,fileid_prefix=?,item_source=?,share_with=?,owner=?,initiator=?,ctime=?,mtime=?,type=?,state=?" - params := []any{s.Name, s.ResourceId.StorageId, s.ResourceId.OpaqueId, s.Grantee.GetUserId().OpaqueId, formatUserID(s.Owner), formatUserID(s.Creator), s.Ctime.Seconds, s.Mtime.Seconds, convertFromCS3OCMShareType(s.ShareType), convertFromCS3OCMShareState(s.State)} + query := "INSERT INTO ocm_received_shares SET name=?,fileid_prefix=?,item_source=?,item_type=?,share_with=?,owner=?,initiator=?,ctime=?,mtime=?,type=?,state=?" + params := []any{s.Name, s.ResourceId.StorageId, s.ResourceId.OpaqueId, convertFromCS3ResourceType(s.ResourceType), s.Grantee.GetUserId().OpaqueId, formatUserID(s.Owner), formatUserID(s.Creator), s.Ctime.Seconds, s.Mtime.Seconds, convertFromCS3OCMShareType(s.ShareType), convertFromCS3OCMShareState(s.State)} if s.Expiration != nil { query += ",expiration=?" @@ -545,7 +545,7 @@ func (m *mgr) StoreReceivedShare(ctx context.Context, s *ocm.ReceivedShare) (*oc // ListReceivedShares returns the list of shares the user has access. func (m *mgr) ListReceivedShares(ctx context.Context, user *userpb.User) ([]*ocm.ReceivedShare, error) { - query := "SELECT id, name, fileid_prefix, item_source, share_with, owner, initiator, ctime, mtime, expiration, type, state FROM ocm_received_shares WHERE share_with=?" + query := "SELECT id, name, fileid_prefix, item_source, item_type, share_with, owner, initiator, ctime, mtime, expiration, type, state FROM ocm_received_shares WHERE share_with=?" rows, err := m.db.QueryContext(ctx, query, user.Id.OpaqueId) if err != nil { @@ -556,7 +556,7 @@ func (m *mgr) ListReceivedShares(ctx context.Context, user *userpb.User) ([]*ocm shares := []*ocm.ReceivedShare{} var ids []any for rows.Next() { - if err := rows.Scan(&s.ID, &s.Name, &s.Prefix, &s.ItemSource, &s.ShareWith, &s.Owner, &s.Initiator, &s.Ctime, &s.Mtime, &s.Expiration, &s.Type, &s.State); err != nil { + if err := rows.Scan(&s.ID, &s.Name, &s.Prefix, &s.ItemSource, &s.ItemType, &s.ShareWith, &s.Owner, &s.Initiator, &s.Ctime, &s.Mtime, &s.Expiration, &s.Type, &s.State); err != nil { continue } shares = append(shares, convertToCS3OCMReceivedShare(&s, nil)) @@ -623,11 +623,11 @@ func (m *mgr) GetReceivedShare(ctx context.Context, user *userpb.User, ref *ocm. } func (m *mgr) getReceivedByID(ctx context.Context, user *userpb.User, id *ocm.ShareId) (*ocm.ReceivedShare, error) { - query := "SELECT id, name, fileid_prefix, item_source, share_with, owner, initiator, ctime, mtime, expiration, type, state FROM ocm_received_shares WHERE id=? AND share_with=?" + query := "SELECT id, name, fileid_prefix, item_source, item_type, share_with, owner, initiator, ctime, mtime, expiration, type, state FROM ocm_received_shares WHERE id=? AND share_with=?" params := []any{id.OpaqueId, user.Id.OpaqueId} var s dbReceivedShare - if err := m.db.QueryRowContext(ctx, query, params...).Scan(&s.ID, &s.Name, &s.Prefix, &s.ItemSource, &s.ShareWith, &s.Owner, &s.Initiator, &s.Ctime, &s.Mtime, &s.Expiration, &s.Type, &s.State); err != nil { + if err := m.db.QueryRowContext(ctx, query, params...).Scan(&s.ID, &s.Name, &s.Prefix, &s.ItemSource, &s.ItemType, &s.ShareWith, &s.Owner, &s.Initiator, &s.Ctime, &s.Mtime, &s.Expiration, &s.Type, &s.State); err != nil { if err == sql.ErrNoRows { return nil, share.ErrShareNotFound } @@ -643,11 +643,11 @@ func (m *mgr) getReceivedByID(ctx context.Context, user *userpb.User, id *ocm.Sh } func (m *mgr) getReceivedByKey(ctx context.Context, user *userpb.User, key *ocm.ShareKey) (*ocm.ReceivedShare, error) { - query := "SELECT id, name, fileid_prefix, item_source, share_with, owner, initiator, ctime, mtime, expiration, type, state FROM ocm_received_shares WHERE owner=? AND fileid_prefix=? AND item_source=? AND share_with=?" + query := "SELECT id, name, fileid_prefix, item_source, item_type, share_with, owner, initiator, ctime, mtime, expiration, type, state FROM ocm_received_shares WHERE owner=? AND fileid_prefix=? AND item_source=? AND share_with=?" params := []any{formatUserID(key.Owner), key.ResourceId.StorageId, key.ResourceId.OpaqueId, key.Grantee.GetUserId().OpaqueId} var s dbReceivedShare - if err := m.db.QueryRowContext(ctx, query, params...).Scan(&s.ID, &s.Name, &s.Prefix, &s.ItemSource, &s.ShareWith, &s.Owner, &s.Initiator, &s.Ctime, &s.Mtime, &s.Expiration, &s.Type, &s.State); err != nil { + if err := m.db.QueryRowContext(ctx, query, params...).Scan(&s.ID, &s.Name, &s.Prefix, &s.ItemSource, &s.ItemType, &s.ShareWith, &s.Owner, &s.Initiator, &s.Ctime, &s.Mtime, &s.Expiration, &s.Type, &s.State); err != nil { if err == sql.ErrNoRows { return nil, share.ErrShareNotFound } diff --git a/pkg/ocm/share/repository/sql/sql_test.go b/pkg/ocm/share/repository/sql/sql_test.go index 379b379379..ffafe1ef6b 100644 --- a/pkg/ocm/share/repository/sql/sql_test.go +++ b/pkg/ocm/share/repository/sql/sql_test.go @@ -203,6 +203,7 @@ func createReceivedShareTables(ctx *sql.Context, initData []*ocm.ReceivedShare) {Name: "name", Type: sql.Text, Nullable: false, Source: ocmReceivedShareTable}, {Name: "fileid_prefix", Type: sql.Text, Nullable: false, Source: ocmReceivedShareTable}, {Name: "item_source", Type: sql.Text, Nullable: false, Source: ocmReceivedShareTable}, + {Name: "item_type", Type: sql.Int8, Nullable: false, Source: ocmReceivedShareTable}, {Name: "share_with", Type: sql.Text, Nullable: false, Source: ocmReceivedShareTable}, {Name: "owner", Type: sql.Text, Nullable: false, Source: ocmReceivedShareTable}, {Name: "initiator", Type: sql.Text, Nullable: false, Source: ocmReceivedShareTable}, @@ -266,7 +267,7 @@ func createReceivedShareTables(ctx *sql.Context, initData []*ocm.ReceivedShare) expiration = share.Expiration.Seconds } - must(tableShares.Insert(ctx, sql.NewRow(mustInt(share.Id.OpaqueId), share.Name, share.ResourceId.StorageId, share.ResourceId.OpaqueId, share.Grantee.GetUserId().OpaqueId, fmt.Sprintf("%s@%s", share.Owner.OpaqueId, share.Owner.Idp), fmt.Sprintf("%s@%s", share.Creator.OpaqueId, share.Creator.Idp), share.Ctime.Seconds, share.Mtime.Seconds, expiration, int8(convertFromCS3OCMShareType(share.ShareType)), int8(convertFromCS3OCMShareState(share.State))))) + must(tableShares.Insert(ctx, sql.NewRow(mustInt(share.Id.OpaqueId), share.Name, share.ResourceId.StorageId, share.ResourceId.OpaqueId, int8(convertFromCS3ResourceType(share.ResourceType)), share.Grantee.GetUserId().OpaqueId, fmt.Sprintf("%s@%s", share.Owner.OpaqueId, share.Owner.Idp), fmt.Sprintf("%s@%s", share.Creator.OpaqueId, share.Creator.Idp), share.Ctime.Seconds, share.Mtime.Seconds, expiration, int8(convertFromCS3OCMShareType(share.ShareType)), int8(convertFromCS3OCMShareState(share.State))))) for _, p := range share.Protocols { i := id() @@ -1205,16 +1206,17 @@ func TestGetReceivedShare(t *testing.T) { description: "query by id", shares: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1225,16 +1227,17 @@ func TestGetReceivedShare(t *testing.T) { query: &ocm.ShareReference{Spec: &ocm.ShareReference_Id{Id: &ocm.ShareId{OpaqueId: "1"}}}, user: &userpb.User{Id: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}, expected: &ocm.ReceivedShare{ - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1246,16 +1249,17 @@ func TestGetReceivedShare(t *testing.T) { description: "query by key", shares: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_FILE, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1274,16 +1278,17 @@ func TestGetReceivedShare(t *testing.T) { }, user: &userpb.User{Id: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}, expected: &ocm.ReceivedShare{ - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_FILE, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1295,16 +1300,17 @@ func TestGetReceivedShare(t *testing.T) { description: "query by key", shares: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1328,16 +1334,17 @@ func TestGetReceivedShare(t *testing.T) { description: "query by id - different user", shares: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_FILE, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1353,16 +1360,17 @@ func TestGetReceivedShare(t *testing.T) { description: "all protocols", shares: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_FILE, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1375,16 +1383,17 @@ func TestGetReceivedShare(t *testing.T) { query: &ocm.ShareReference{Spec: &ocm.ShareReference_Id{Id: &ocm.ShareId{OpaqueId: "1"}}}, user: &userpb.User{Id: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}, expected: &ocm.ReceivedShare{ - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_FILE, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1445,16 +1454,17 @@ func TestListReceviedShares(t *testing.T) { description: "share belong to user", shares: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1467,16 +1477,17 @@ func TestListReceviedShares(t *testing.T) { user: &userpb.User{Id: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}, expected: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1491,16 +1502,17 @@ func TestListReceviedShares(t *testing.T) { description: "all shares belong to user", shares: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_FILE, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1510,16 +1522,17 @@ func TestListReceviedShares(t *testing.T) { }, }, { - Id: &ocm.ShareId{OpaqueId: "2"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "2"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebappProtocol("https://cernbox.cern.ch/ocm/54321"), }, @@ -1528,16 +1541,17 @@ func TestListReceviedShares(t *testing.T) { user: &userpb.User{Id: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}, expected: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_FILE, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1547,16 +1561,17 @@ func TestListReceviedShares(t *testing.T) { }, }, { - Id: &ocm.ShareId{OpaqueId: "2"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "2"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebappProtocol("https://cernbox.cern.ch/ocm/54321"), }, @@ -1567,16 +1582,17 @@ func TestListReceviedShares(t *testing.T) { description: "select share by user", shares: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1586,16 +1602,17 @@ func TestListReceviedShares(t *testing.T) { }, }, { - Id: &ocm.ShareId{OpaqueId: "2"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "einstein"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "2"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "einstein"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "richard"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebappProtocol("https://cernbox.cern.ch/ocm/54321"), }, @@ -1604,16 +1621,17 @@ func TestListReceviedShares(t *testing.T) { user: &userpb.User{Id: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}, expected: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein", Type: userpb.UserType_USER_TYPE_FEDERATED}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1684,15 +1702,16 @@ func TestStoreReceivedShare(t *testing.T) { description: "empty table", shares: []*ocm.ReceivedShare{}, toStore: &ocm.ReceivedShare{ - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1700,7 +1719,7 @@ func TestStoreReceivedShare(t *testing.T) { }, }, expected: storeReceivedShareExpected{ - shares: []sql.Row{{int64(1), "file-name", "storage", "opaque-id", "marie", "einstein@cernbox", "einstein@cernbox", uint64(1670859468), uint64(1670859468), nil, int8(ShareTypeUser), int8(ShareStateAccepted)}}, + shares: []sql.Row{{int64(1), "file-name", "storage", "opaque-id", int8(1), "marie", "einstein@cernbox", "einstein@cernbox", uint64(1670859468), uint64(1670859468), nil, int8(ShareTypeUser), int8(ShareStateAccepted)}}, protocols: []sql.Row{{int64(1), int64(1), int8(0)}}, webdav: []sql.Row{{int64(1), "webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", int64(15)}}, webapp: []sql.Row{}, @@ -1711,16 +1730,17 @@ func TestStoreReceivedShare(t *testing.T) { description: "non empty table", shares: []*ocm.ReceivedShare{ { - Id: &ocm.ShareId{OpaqueId: "1"}, - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_ACCEPTED, + Id: &ocm.ShareId{OpaqueId: "1"}, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "opaque-id"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "marie"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "einstein"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_ACCEPTED, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_FILE, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1729,15 +1749,16 @@ func TestStoreReceivedShare(t *testing.T) { }, }, toStore: &ocm.ReceivedShare{ - ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "new-resource"}, - Name: "file-name", - Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "richard"}}}, - Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "marie"}, - Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "marie"}, - Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, - ShareType: ocm.ShareType_SHARE_TYPE_USER, - State: ocm.ShareState_SHARE_STATE_PENDING, + ResourceId: &providerv1beta1.ResourceId{StorageId: "storage", OpaqueId: "new-resource"}, + Name: "file-name", + Grantee: &providerv1beta1.Grantee{Type: providerv1beta1.GranteeType_GRANTEE_TYPE_USER, Id: &providerv1beta1.Grantee_UserId{UserId: &userpb.UserId{Idp: "cesnet", OpaqueId: "richard"}}}, + Owner: &userpb.UserId{Idp: "cernbox", OpaqueId: "marie"}, + Creator: &userpb.UserId{Idp: "cernbox", OpaqueId: "marie"}, + Ctime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + Mtime: &typesv1beta1.Timestamp{Seconds: 1670859468}, + ShareType: ocm.ShareType_SHARE_TYPE_USER, + State: ocm.ShareState_SHARE_STATE_PENDING, + ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), @@ -1748,8 +1769,8 @@ func TestStoreReceivedShare(t *testing.T) { }, expected: storeReceivedShareExpected{ shares: []sql.Row{ - {int64(1), "file-name", "storage", "opaque-id", "marie", "einstein@cernbox", "einstein@cernbox", uint64(1670859468), uint64(1670859468), uint64(0), int8(ShareTypeUser), int8(ShareStateAccepted)}, - {int64(2), "file-name", "storage", "new-resource", "richard", "marie@cernbox", "marie@cernbox", uint64(1670859468), uint64(1670859468), nil, int8(ShareTypeUser), int8(ShareStatePending)}, + {int64(1), "file-name", "storage", "opaque-id", int8(0), "marie", "einstein@cernbox", "einstein@cernbox", uint64(1670859468), uint64(1670859468), uint64(0), int8(ShareTypeUser), int8(ShareStateAccepted)}, + {int64(2), "file-name", "storage", "new-resource", int8(1), "richard", "marie@cernbox", "marie@cernbox", uint64(1670859468), uint64(1670859468), nil, int8(ShareTypeUser), int8(ShareStatePending)}, }, protocols: []sql.Row{ {int64(1), int64(1), int8(WebDAVProtocol)}, diff --git a/pkg/ocm/storage/ocm.go b/pkg/ocm/storage/ocm.go new file mode 100644 index 0000000000..3351c68006 --- /dev/null +++ b/pkg/ocm/storage/ocm.go @@ -0,0 +1,413 @@ +// Copyright 2018-2023 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package ocm + +import ( + "context" + "fmt" + "io" + "io/fs" + "net/url" + "path/filepath" + "strings" + + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" + ocmpb "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1" + provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" + typepb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" + "github.com/cs3org/reva/internal/http/services/owncloud/ocdav" + "github.com/cs3org/reva/pkg/errtypes" + "github.com/cs3org/reva/pkg/mime" + "github.com/cs3org/reva/pkg/rgrpc/todo/pool" + "github.com/cs3org/reva/pkg/rhttp/router" + "github.com/cs3org/reva/pkg/sharedconf" + "github.com/cs3org/reva/pkg/storage" + "github.com/cs3org/reva/pkg/storage/fs/registry" + "github.com/mitchellh/mapstructure" + "github.com/pkg/errors" + "github.com/studio-b12/gowebdav" +) + +func init() { + registry.Register("ocm", New) +} + +type driver struct { + c *config + gateway gateway.GatewayAPIClient +} + +type config struct { + GatewaySVC string +} + +func parseConfig(c map[string]interface{}) (*config, error) { + var conf config + err := mapstructure.Decode(c, &conf) + return &conf, err +} + +func (c *config) init() { + c.GatewaySVC = sharedconf.GetGatewaySVC(c.GatewaySVC) +} + +// New creates an OCM storage driver. +func New(c map[string]interface{}) (storage.FS, error) { + conf, err := parseConfig(c) + if err != nil { + return nil, errors.Wrapf(err, "error decoding config") + } + conf.init() + + gateway, err := pool.GetGatewayServiceClient(pool.Endpoint(conf.GatewaySVC)) + if err != nil { + return nil, err + } + + d := &driver{ + c: conf, + gateway: gateway, + } + + return d, nil +} + +func shareInfoFromPath(path string) (*ocmpb.ShareId, string) { + // the path is of the type /share_id[/rel_path] + shareID, rel := router.ShiftPath(path) + return &ocmpb.ShareId{OpaqueId: shareID}, rel +} + +func shareInfoFromReference(ref *provider.Reference) (*ocmpb.ShareId, string) { + if ref.ResourceId == nil { + return shareInfoFromPath(ref.Path) + } + + s := strings.SplitN(ref.ResourceId.OpaqueId, ":", 2) + shareID := &ocmpb.ShareId{OpaqueId: s[0]} + var path string + if len(s) == 2 { + path = s[1] + } + path = filepath.Join(path, ref.Path) + + return shareID, path +} + +func (d *driver) getWebDAVFromShare(ctx context.Context, shareID *ocmpb.ShareId) (*ocmpb.ReceivedShare, string, string, error) { + // TODO: we may want to cache the share + res, err := d.gateway.GetReceivedOCMShare(ctx, &ocmpb.GetReceivedOCMShareRequest{ + Ref: &ocmpb.ShareReference{ + Spec: &ocmpb.ShareReference_Id{ + Id: shareID, + }, + }, + }) + if err != nil { + return nil, "", "", err + } + + if res.Status.Code != rpc.Code_CODE_OK { + if res.Status.Code == rpc.Code_CODE_NOT_FOUND { + return nil, "", "", errtypes.NotFound("share not found") + } + return nil, "", "", errtypes.InternalError(res.Status.Message) + } + + dav, ok := getWebDAVProtocol(res.Share.Protocols) + if !ok { + return nil, "", "", errtypes.NotFound("share does not contain a WebDAV endpoint") + } + + return res.Share, dav.Uri, dav.SharedSecret, nil +} + +func getWebDAVProtocol(protocols []*ocmpb.Protocol) (*ocmpb.WebDAVProtocol, bool) { + for _, p := range protocols { + if dav, ok := p.Term.(*ocmpb.Protocol_WebdavOptions); ok { + return dav.WebdavOptions, true + } + } + return nil, false +} + +func (d *driver) webdavClient(ctx context.Context, ref *provider.Reference) (*gowebdav.Client, *ocmpb.ReceivedShare, string, error) { + id, rel := shareInfoFromReference(ref) + + share, endpoint, secret, err := d.getWebDAVFromShare(ctx, id) + if err != nil { + return nil, nil, "", err + } + + // FIXME: it's still not clear from the OCM APIs how to use the shared secret + // will use as a token in the bearer authentication as this is the reva implementation + c := gowebdav.NewClient(endpoint, "", "") + c.SetHeader("Authorization", "Bearer "+secret) + + return c, share, rel, nil +} + +func (d *driver) CreateDir(ctx context.Context, ref *provider.Reference) error { + client, _, rel, err := d.webdavClient(ctx, ref) + if err != nil { + return err + } + return client.MkdirAll(rel, 0) +} + +func (d *driver) Delete(ctx context.Context, ref *provider.Reference) error { + client, _, rel, err := d.webdavClient(ctx, ref) + if err != nil { + return err + } + return client.RemoveAll(rel) +} + +func (d *driver) TouchFile(ctx context.Context, ref *provider.Reference) error { + client, _, rel, err := d.webdavClient(ctx, ref) + if err != nil { + return err + } + return client.Write(rel, []byte{}, 0) +} + +func (d *driver) Move(ctx context.Context, oldRef, newRef *provider.Reference) error { + client, _, relOld, err := d.webdavClient(ctx, oldRef) + if err != nil { + return err + } + _, relNew := shareInfoFromReference(newRef) + + return client.Rename(relOld, relNew, false) +} + +func getResourceInfo(shareID *ocmpb.ShareId, relPath string) *provider.ResourceId { + return &provider.ResourceId{ + OpaqueId: fmt.Sprintf("%s:%s", shareID.OpaqueId, relPath), + } +} + +func getPathFromShareIDAndRelPath(shareID *ocmpb.ShareId, relPath string) string { + return filepath.Join("/", shareID.OpaqueId, relPath) +} + +func convertStatToResourceInfo(f fs.FileInfo, share *ocmpb.ReceivedShare, relPath string) *provider.ResourceInfo { + t := provider.ResourceType_RESOURCE_TYPE_FILE + if f.IsDir() { + t = provider.ResourceType_RESOURCE_TYPE_CONTAINER + } + + var name string + if share.ResourceType == provider.ResourceType_RESOURCE_TYPE_FILE { + name = share.Name + } else { + name = f.Name() + } + + webdav, _ := getWebDAVProtocol(share.Protocols) + + return &provider.ResourceInfo{ + Type: t, + Id: getResourceInfo(share.Id, relPath), + MimeType: mime.Detect(f.IsDir(), f.Name()), + Path: getPathFromShareIDAndRelPath(share.Id, relPath), + Name: name, + Size: uint64(f.Size()), + Mtime: &typepb.Timestamp{ + Seconds: uint64(f.ModTime().Unix()), + }, + Owner: share.Creator, + PermissionSet: webdav.Permissions.Permissions, + Checksum: &provider.ResourceChecksum{ + Type: provider.ResourceChecksumType_RESOURCE_CHECKSUM_TYPE_INVALID, + }, + } +} + +func (d *driver) GetMD(ctx context.Context, ref *provider.Reference, _ []string) (*provider.ResourceInfo, error) { + client, share, rel, err := d.webdavClient(ctx, ref) + if err != nil { + return nil, err + } + + info, err := client.Stat(rel) + if err != nil { + return nil, err + } + + return convertStatToResourceInfo(info, share, rel), nil +} + +func (d *driver) ListFolder(ctx context.Context, ref *provider.Reference, _ []string) ([]*provider.ResourceInfo, error) { + client, share, rel, err := d.webdavClient(ctx, ref) + if err != nil { + return nil, err + } + + list, err := client.ReadDir(rel) + if err != nil { + return nil, err + } + + res := make([]*provider.ResourceInfo, 0, len(list)) + for _, r := range list { + res = append(res, convertStatToResourceInfo(r, share, filepath.Join(rel, r.Name()))) + } + return res, nil +} + +func (d *driver) InitiateUpload(ctx context.Context, ref *provider.Reference, _ int64, _ map[string]string) (map[string]string, error) { + shareID, rel := shareInfoFromReference(ref) + p := getPathFromShareIDAndRelPath(shareID, rel) + + return map[string]string{ + "simple": p, + }, nil +} + +func (d *driver) Upload(ctx context.Context, ref *provider.Reference, r io.ReadCloser) error { + client, _, rel, err := d.webdavClient(ctx, ref) + if err != nil { + return err + } + + client.SetHeader(ocdav.HeaderUploadLength, "-1") + return client.WriteStream(rel, r, 0) +} + +func (d *driver) Download(ctx context.Context, ref *provider.Reference) (io.ReadCloser, error) { + client, _, rel, err := d.webdavClient(ctx, ref) + if err != nil { + return nil, err + } + + return client.ReadStream(rel) +} + +func (d *driver) GetPathByID(ctx context.Context, id *provider.ResourceId) (string, error) { + shareID, rel := shareInfoFromReference(&provider.Reference{ + ResourceId: id, + }) + return getPathFromShareIDAndRelPath(shareID, rel), nil +} + +func (d *driver) Shutdown(ctx context.Context) error { + return nil +} + +func (d *driver) CreateHome(ctx context.Context) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) GetHome(ctx context.Context) (string, error) { + return "", errtypes.NotSupported("operation not supported") +} + +func (d *driver) ListRevisions(ctx context.Context, ref *provider.Reference) ([]*provider.FileVersion, error) { + return nil, errtypes.NotSupported("operation not supported") +} + +func (d *driver) DownloadRevision(ctx context.Context, ref *provider.Reference, key string) (io.ReadCloser, error) { + return nil, errtypes.NotSupported("operation not supported") +} + +func (d *driver) RestoreRevision(ctx context.Context, ref *provider.Reference, key string) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) ListRecycle(ctx context.Context, basePath, key, relativePath string) ([]*provider.RecycleItem, error) { + return nil, errtypes.NotSupported("operation not supported") +} + +func (d *driver) RestoreRecycleItem(ctx context.Context, basePath, key, relativePath string, restoreRef *provider.Reference) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) PurgeRecycleItem(ctx context.Context, basePath, key, relativePath string) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) EmptyRecycle(ctx context.Context) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) AddGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) DenyGrant(ctx context.Context, ref *provider.Reference, g *provider.Grantee) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) RemoveGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) UpdateGrant(ctx context.Context, ref *provider.Reference, g *provider.Grant) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) ListGrants(ctx context.Context, ref *provider.Reference) ([]*provider.Grant, error) { + return nil, errtypes.NotSupported("operation not supported") +} + +func (d *driver) GetQuota(ctx context.Context, ref *provider.Reference) ( /*TotalBytes*/ uint64 /*UsedBytes*/, uint64, error) { + return 0, 0, errtypes.NotSupported("operation not supported") +} + +func (d *driver) CreateReference(ctx context.Context, path string, targetURI *url.URL) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) SetArbitraryMetadata(ctx context.Context, ref *provider.Reference, md *provider.ArbitraryMetadata) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) UnsetArbitraryMetadata(ctx context.Context, ref *provider.Reference, keys []string) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) SetLock(ctx context.Context, ref *provider.Reference, lock *provider.Lock) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) GetLock(ctx context.Context, ref *provider.Reference) (*provider.Lock, error) { + return nil, errtypes.NotSupported("operation not supported") +} + +func (d *driver) RefreshLock(ctx context.Context, ref *provider.Reference, lock *provider.Lock, existingLockID string) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) Unlock(ctx context.Context, ref *provider.Reference, lock *provider.Lock) error { + return errtypes.NotSupported("operation not supported") +} + +func (d *driver) ListStorageSpaces(ctx context.Context, filter []*provider.ListStorageSpacesRequest_Filter) ([]*provider.StorageSpace, error) { + return nil, errtypes.NotSupported("operation not supported") +} + +func (d *driver) CreateStorageSpace(ctx context.Context, req *provider.CreateStorageSpaceRequest) (*provider.CreateStorageSpaceResponse, error) { + return nil, errtypes.NotSupported("operation not supported") +} + +func (d *driver) UpdateStorageSpace(ctx context.Context, req *provider.UpdateStorageSpaceRequest) (*provider.UpdateStorageSpaceResponse, error) { + return nil, errtypes.NotSupported("operation not supported") +} diff --git a/pkg/storage/fs/loader/loader.go b/pkg/storage/fs/loader/loader.go index ceb30fff77..54ae50cfd0 100644 --- a/pkg/storage/fs/loader/loader.go +++ b/pkg/storage/fs/loader/loader.go @@ -20,6 +20,7 @@ package loader import ( // Load core storage filesystem backends. + _ "github.com/cs3org/reva/pkg/ocm/storage" _ "github.com/cs3org/reva/pkg/storage/fs/cback" _ "github.com/cs3org/reva/pkg/storage/fs/cephfs" _ "github.com/cs3org/reva/pkg/storage/fs/eos" diff --git a/tests/helpers/helpers.go b/tests/helpers/helpers.go index 8cdef23785..7a7ab6f641 100644 --- a/tests/helpers/helpers.go +++ b/tests/helpers/helpers.go @@ -22,7 +22,6 @@ import ( "bytes" "context" "encoding/json" - "errors" "fmt" "io" "net/http" @@ -30,6 +29,8 @@ import ( "path/filepath" "runtime" + "github.com/pkg/errors" + gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" @@ -108,6 +109,81 @@ func Upload(ctx context.Context, fs storage.FS, ref *provider.Reference, content return err } +// UploadGateway uploads in one step a the content in a file. +func UploadGateway(ctx context.Context, gw gatewayv1beta1.GatewayAPIClient, ref *provider.Reference, content []byte) error { + res, err := gw.InitiateFileUpload(ctx, &provider.InitiateFileUploadRequest{ + Ref: ref, + }) + if err != nil { + return errors.Wrap(err, "error initiating file upload") + } + if res.Status.Code != rpcv1beta1.Code_CODE_OK { + return errors.Errorf("error initiating file upload: %s", res.Status.Message) + } + + var token, endpoint string + for _, p := range res.Protocols { + if p.Protocol == "simple" { + token, endpoint = p.Token, p.UploadEndpoint + } + } + httpReq, err := rhttp.NewRequest(ctx, http.MethodPut, endpoint, bytes.NewReader(content)) + if err != nil { + return errors.Wrap(err, "error creating new request") + } + + httpReq.Header.Set(datagateway.TokenTransportHeader, token) + + httpRes, err := http.DefaultClient.Do(httpReq) + if err != nil { + return errors.Wrap(err, "error doing put request") + } + defer httpRes.Body.Close() + + if httpRes.StatusCode != http.StatusOK { + return errors.Errorf("error doing put request: %s", httpRes.Status) + } + + return nil +} + +// Download downloads the content of a file in one step. +func Download(ctx context.Context, gw gatewayv1beta1.GatewayAPIClient, ref *provider.Reference) ([]byte, error) { + res, err := gw.InitiateFileDownload(ctx, &provider.InitiateFileDownloadRequest{ + Ref: ref, + }) + if err != nil { + return nil, err + } + if res.Status.Code != rpcv1beta1.Code_CODE_OK { + return nil, errors.New(res.Status.Message) + } + + var token, endpoint string + for _, p := range res.Protocols { + if p.Protocol == "simple" { + token, endpoint = p.Token, p.DownloadEndpoint + } + } + httpReq, err := rhttp.NewRequest(ctx, http.MethodGet, endpoint, nil) + if err != nil { + return nil, err + } + httpReq.Header.Set(datagateway.TokenTransportHeader, token) + + httpRes, err := http.DefaultClient.Do(httpReq) + if err != nil { + return nil, err + } + defer httpRes.Body.Close() + + if httpRes.StatusCode != http.StatusOK { + return nil, errors.New(httpRes.Status) + } + + return io.ReadAll(httpRes.Body) +} + // Resource represents a general resource (file or folder). type Resource interface { isResource() diff --git a/tests/integration/grpc/fixtures/ocm-share/ocm-server-cesnet-grpc.toml b/tests/integration/grpc/fixtures/ocm-share/ocm-server-cesnet-grpc.toml index aad74a3153..d55986a814 100644 --- a/tests/integration/grpc/fixtures/ocm-share/ocm-server-cesnet-grpc.toml +++ b/tests/integration/grpc/fixtures/ocm-share/ocm-server-cesnet-grpc.toml @@ -14,6 +14,7 @@ ocminvitemanagersvc = "{{grpc_address}}" ocmproviderauthorizersvc = "{{grpc_address}}" ocmshareprovidersvc = "{{grpc_address}}" ocmcoresvc = "{{grpc_address}}" +datagateway = "http://{{cesnethttp_address}}/datagateway" [grpc.services.authregistry] driver = "static" @@ -56,3 +57,17 @@ driver = "json" [grpc.services.userprovider.drivers.json] users = "fixtures/ocm-users.demo.json" + +[grpc.services.storageregistry] +[grpc.services.storageregistry.drivers.static] +[grpc.services.storageregistry.drivers.static.rules] +"/ocm" = {"address" = "{{grpc_address}}"} +"984e7351-2729-4417-99b4-ab5e6d41fa97" = {"address" = "{{grpc_address}}"} + +[grpc.services.storageprovider] +driver = "ocm" +mount_path = "/ocm" +mount_id = "984e7351-2729-4417-99b4-ab5e6d41fa97" +data_server_url = "http://{{cesnethttp_address}}/data" + +[grpc.services.storageprovider.drivers.ocm] diff --git a/tests/integration/grpc/fixtures/ocm-share/ocm-server-cesnet-http.toml b/tests/integration/grpc/fixtures/ocm-share/ocm-server-cesnet-http.toml index ce607e3648..a17d3d0183 100644 --- a/tests/integration/grpc/fixtures/ocm-share/ocm-server-cesnet-http.toml +++ b/tests/integration/grpc/fixtures/ocm-share/ocm-server-cesnet-http.toml @@ -17,4 +17,11 @@ address = "{{grpc_address}}" driver = "json" [http.middlewares.providerauthorizer.drivers.json] -providers = "fixtures/ocm-providers.demo.json" \ No newline at end of file +providers = "fixtures/ocm-providers.demo.json" + +[http.services.datagateway] + +[http.services.dataprovider] +driver = "ocm" + +[http.services.dataprovider.drivers.ocm] diff --git a/tests/integration/grpc/ocm_share_test.go b/tests/integration/grpc/ocm_share_test.go index da74e0788a..c8be79f7bc 100644 --- a/tests/integration/grpc/ocm_share_test.go +++ b/tests/integration/grpc/ocm_share_test.go @@ -22,6 +22,7 @@ import ( "context" "io" "net/http" + "path/filepath" "strconv" "strings" @@ -47,6 +48,22 @@ import ( "github.com/studio-b12/gowebdav" ) +var ( + editorPermissions = &provider.ResourcePermissions{ + InitiateFileDownload: true, + InitiateFileUpload: true, + ListContainer: true, + GetPath: true, + Stat: true, + } + viewerPermissions = &provider.ResourcePermissions{ + Stat: true, + InitiateFileDownload: true, + GetPath: true, + ListContainer: true, + } +) + var _ = Describe("ocm share", func() { var ( revads = map[string]*Revad{} @@ -211,6 +228,30 @@ var _ = Describe("ocm share", func() { // TODO: enable once we don't send anymore the owner token // err = webdavClient.Write(".", []byte("will-never-be-written"), 0) // Expect(err).To(HaveOccurred()) + + By("marie access the share using the ocm mount") + ref := &provider.Reference{Path: ocmPath(share.Id, "")} + statRes, err := cesnetgw.Stat(ctxMarie, &provider.StatRequest{Ref: ref}) + Expect(err).ToNot(HaveOccurred()) + Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK)) + checkResourceInfo(statRes.Info, &provider.ResourceInfo{ + Id: &provider.ResourceId{ + StorageId: "984e7351-2729-4417-99b4-ab5e6d41fa97", + OpaqueId: share.Id.OpaqueId + ":/", + }, + Name: "new-file", + Path: ocmPath(share.Id, ""), + Size: 4, + Type: provider.ResourceType_RESOURCE_TYPE_FILE, + PermissionSet: viewerPermissions, + }) + + data, err := helpers.Download(ctxMarie, cesnetgw, ref) + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal([]byte("test"))) + + // TODO: enable once we don't send anymore the owner token + // Expect(helpers.UploadGateway(ctxMarie, cesnetgw, ref, []byte("will-never-be-written"))).ToNot(Succeed()) }) }) @@ -273,6 +314,32 @@ var _ = Describe("ocm share", func() { newContent, err := download(ctxEinstein, cernboxgw, fileToShare) Expect(err).ToNot(HaveOccurred()) Expect(newContent).To(Equal([]byte("new-content"))) + + By("marie access the share using the ocm mount") + ref := &provider.Reference{Path: ocmPath(share.Id, "")} + statRes, err := cesnetgw.Stat(ctxMarie, &provider.StatRequest{Ref: ref}) + Expect(err).ToNot(HaveOccurred()) + Expect(statRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK)) + checkResourceInfo(statRes.Info, &provider.ResourceInfo{ + Id: &provider.ResourceId{ + StorageId: "984e7351-2729-4417-99b4-ab5e6d41fa97", + OpaqueId: share.Id.OpaqueId + ":/", + }, + Name: "new-file", + Path: ocmPath(share.Id, ""), + Size: uint64(len(data)), + Type: provider.ResourceType_RESOURCE_TYPE_FILE, + PermissionSet: editorPermissions, + }) + + data, err = helpers.Download(ctxMarie, cesnetgw, ref) + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal([]byte("new-content"))) + + Expect(helpers.UploadGateway(ctxMarie, cesnetgw, ref, []byte("uploaded-from-ocm-mount"))).To(Succeed()) + newContent, err = download(ctxEinstein, cernboxgw, fileToShare) + Expect(err).ToNot(HaveOccurred()) + Expect(newContent).To(Equal([]byte("uploaded-from-ocm-mount"))) }) }) @@ -282,7 +349,12 @@ var _ = Describe("ocm share", func() { "foo": helpers.File{ Content: "foo", }, - "dir": helpers.Folder{}, + "dir": helpers.Folder{ + "foo": helpers.File{ + Content: "dir/foo", + }, + "bar": helpers.Folder{}, + }, } fileToShare := &provider.Reference{Path: "/home/ocm-share-folder"} Expect(helpers.CreateStructure(ctxEinstein, cernboxgw, fileToShare.Path, structure)).To(Succeed()) @@ -336,6 +408,42 @@ var _ = Describe("ocm share", func() { // By("check that marie does not have permissions to create files") // Expect(webdavClient.Write("new-file", []byte("new-file"), 0)).ToNot(Succeed()) + + By("marie access the share using the ocm mount") + ref := &provider.Reference{Path: ocmPath(share.Id, "dir")} + listFolderRes, err := cesnetgw.ListContainer(ctxMarie, &provider.ListContainerRequest{ + Ref: ref, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(listFolderRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK)) + checkResourceInfoList(listFolderRes.Infos, []*provider.ResourceInfo{ + { + Id: &provider.ResourceId{ + StorageId: "984e7351-2729-4417-99b4-ab5e6d41fa97", + OpaqueId: share.Id.OpaqueId + ":/dir/foo", + }, + Name: "foo", + Path: ocmPath(share.Id, "dir/foo"), + Size: 7, + Type: provider.ResourceType_RESOURCE_TYPE_FILE, + PermissionSet: viewerPermissions, + }, + { + Id: &provider.ResourceId{ + StorageId: "984e7351-2729-4417-99b4-ab5e6d41fa97", + OpaqueId: share.Id.OpaqueId + ":/dir/bar", + }, + Name: "bar", + Path: ocmPath(share.Id, "dir/bar"), + Size: 0, + Type: provider.ResourceType_RESOURCE_TYPE_CONTAINER, + PermissionSet: viewerPermissions, + }, + }) + + // TODO: enable once we don't send anymore the owner token + // newFile := &provider.Reference{Path: ocmPath(share.Id, "dir/new")} + // Expect(helpers.UploadGateway(ctxMarie, cesnetgw, newFile, []byte("uploaded-from-ocm-mount"))).ToNot(Succeed()) }) }) @@ -345,7 +453,12 @@ var _ = Describe("ocm share", func() { "foo": helpers.File{ Content: "foo", }, - "dir": helpers.Folder{}, + "dir": helpers.Folder{ + "foo": helpers.File{ + Content: "dir/foo", + }, + "bar": helpers.Folder{}, + }, } fileToShare := &provider.Reference{Path: "/home/ocm-share-folder"} @@ -403,7 +516,91 @@ var _ = Describe("ocm share", func() { "foo": helpers.File{ Content: "foo", }, - "dir": helpers.Folder{}, + "dir": helpers.Folder{ + "foo": helpers.File{ + Content: "dir/foo", + }, + "bar": helpers.Folder{}, + }, + "new-file": helpers.File{ + Content: "new-file", + }, + })) + + By("marie access the share using the ocm mount") + ref := &provider.Reference{Path: ocmPath(share.Id, "dir")} + listFolderRes, err := cesnetgw.ListContainer(ctxMarie, &provider.ListContainerRequest{ + Ref: ref, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(listFolderRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK)) + checkResourceInfoList(listFolderRes.Infos, []*provider.ResourceInfo{ + { + Id: &provider.ResourceId{ + StorageId: "984e7351-2729-4417-99b4-ab5e6d41fa97", + OpaqueId: share.Id.OpaqueId + ":/dir/foo", + }, + Name: "foo", + Path: ocmPath(share.Id, "dir/foo"), + Size: 7, + Type: provider.ResourceType_RESOURCE_TYPE_FILE, + PermissionSet: editorPermissions, + }, + { + Id: &provider.ResourceId{ + StorageId: "984e7351-2729-4417-99b4-ab5e6d41fa97", + OpaqueId: share.Id.OpaqueId + ":/dir/bar", + }, + Name: "bar", + Path: ocmPath(share.Id, "dir/bar"), + Size: 0, + Type: provider.ResourceType_RESOURCE_TYPE_CONTAINER, + PermissionSet: editorPermissions, + }, + }) + + // create a new file + newFile := &provider.Reference{Path: ocmPath(share.Id, "dir/new-file")} + Expect(helpers.UploadGateway(ctxMarie, cesnetgw, newFile, []byte("uploaded-from-ocm-mount"))).To(Succeed()) + Expect(helpers.SameContentWebDAV(webdavClient, fileToShare.Path, helpers.Folder{ + "foo": helpers.File{ + Content: "foo", + }, + "dir": helpers.Folder{ + "foo": helpers.File{ + Content: "dir/foo", + }, + "bar": helpers.Folder{}, + "new-file": helpers.File{ + Content: "uploaded-from-ocm-mount", + }, + }, + "new-file": helpers.File{ + Content: "new-file", + }, + })) + + // create a new directory + newDir := &provider.Reference{Path: ocmPath(share.Id, "dir/new-dir")} + createDirRes, err := cesnetgw.CreateContainer(ctxMarie, &provider.CreateContainerRequest{ + Ref: newDir, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(createDirRes.Status.Code).To(Equal(rpcv1beta1.Code_CODE_OK)) + Expect(helpers.SameContentWebDAV(webdavClient, fileToShare.Path, helpers.Folder{ + "foo": helpers.File{ + Content: "foo", + }, + "dir": helpers.Folder{ + "foo": helpers.File{ + Content: "dir/foo", + }, + "bar": helpers.Folder{}, + "new-file": helpers.File{ + Content: "uploaded-from-ocm-mount", + }, + "new-dir": helpers.Folder{}, + }, "new-file": helpers.File{ Content: "new-file", }, @@ -527,3 +724,35 @@ func download(ctx context.Context, gw gatewaypb.GatewayAPIClient, ref *provider. return io.ReadAll(httpRes.Body) } + +func ocmPath(id *ocmv1beta1.ShareId, p string) string { + return filepath.Join("/ocm", id.OpaqueId, p) +} + +func checkResourceInfo(info, target *provider.ResourceInfo) { + Expect(info.Id).To(Equal(target.Id)) + Expect(info.Name).To(Equal(target.Name)) + Expect(info.Path).To(Equal(target.Path)) + Expect(info.Size).To(Equal(target.Size)) + Expect(info.Type).To(Equal(target.Type)) + Expect(info.PermissionSet).To(Equal(target.PermissionSet)) +} + +func mapResourceInfos(l []*provider.ResourceInfo) map[string]*provider.ResourceInfo { + m := make(map[string]*provider.ResourceInfo) + for _, e := range l { + m[e.Path] = e + } + return m +} + +func checkResourceInfoList(l1, l2 []*provider.ResourceInfo) { + m1, m2 := mapResourceInfos(l1), mapResourceInfos(l2) + Expect(l1).To(HaveLen(len(l2))) + + for k, ri1 := range m1 { + ri2, ok := m2[k] + Expect(ok).To(BeTrue()) + checkResourceInfo(ri1, ri2) + } +}