From 423c0a8dcea8e82812b3acb411d7a05455725fed Mon Sep 17 00:00:00 2001 From: Giuseppe Lo Presti Date: Tue, 28 Mar 2023 18:12:56 +0200 Subject: [PATCH] Support OCM v1.0 schema but bail out if the options aren't empty --- changelog/unreleased/ocm-reconcile.md | 14 ++++++ internal/http/services/ocmd/config.go | 2 +- internal/http/services/ocmd/protocols.go | 24 +++++++-- internal/http/services/ocmd/protocols_test.go | 50 ++++++++++++------- internal/http/services/ocmd/shares.go | 2 +- pkg/ocm/client/client.go | 4 +- pkg/ocm/share/repository/sql/conversions.go | 13 ++--- pkg/ocm/share/repository/sql/sql.go | 14 +++--- pkg/ocm/share/repository/sql/sql_test.go | 33 ++++++------ pkg/ocm/share/utils.go | 3 +- pkg/utils/utils.go | 17 +++++++ 11 files changed, 122 insertions(+), 54 deletions(-) create mode 100644 changelog/unreleased/ocm-reconcile.md diff --git a/changelog/unreleased/ocm-reconcile.md b/changelog/unreleased/ocm-reconcile.md new file mode 100644 index 00000000000..6e8d5e593ff --- /dev/null +++ b/changelog/unreleased/ocm-reconcile.md @@ -0,0 +1,14 @@ +Enhancement: Support OCM v1.0 schema + +Following cs3org/cs3apis#206, we add the fields to ensure +backwards compatibility with OCM v1.0. However, if the +protocol.options undocumented object is not empty, we bail +out for now. Supporting interoperability with OCM v1.0 +implementations (notably Nextcloud 25) may come in the future +if the undocumented options are fully reverse engineered. + +Also, added viewMode to webapp protocol options +and adapted all SQL code and unit tests. + +https://github.com/cs3org/cs3apis/pull/207 +https://github.com/cs3org/reva/pull/3757 diff --git a/internal/http/services/ocmd/config.go b/internal/http/services/ocmd/config.go index a8666e53f18..5d481c48acb 100644 --- a/internal/http/services/ocmd/config.go +++ b/internal/http/services/ocmd/config.go @@ -52,7 +52,7 @@ type configHandler struct { func (h *configHandler) init(c *config) { h.c = c.Config if h.c.APIVersion == "" { - h.c.APIVersion = "1.0-proposal1" + h.c.APIVersion = "1.1.0" } if h.c.Host == "" { h.c.Host = "localhost" diff --git a/internal/http/services/ocmd/protocols.go b/internal/http/services/ocmd/protocols.go index 1d76dc5ac68..83a463cc657 100644 --- a/internal/http/services/ocmd/protocols.go +++ b/internal/http/services/ocmd/protocols.go @@ -27,6 +27,7 @@ import ( ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1" providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" ocmshare "github.com/cs3org/reva/pkg/ocm/share" + utils "github.com/cs3org/reva/pkg/utils" ) // Protocols is the list of protocols. @@ -73,11 +74,12 @@ func (w *WebDAV) ToOCMProtocol() *ocm.Protocol { // Webapp contains the parameters for the Webapp protocol. type Webapp struct { URITemplate string `json:"uriTemplate" validate:"required"` + ViewMode string `json:"viewMode" validate:"required,dive,required,oneof=view read write"` } // ToOCMProtocol convert the protocol to a ocm Protocol struct. func (w *Webapp) ToOCMProtocol() *ocm.Protocol { - return ocmshare.NewWebappProtocol(w.URITemplate) + return ocmshare.NewWebappProtocol(w.URITemplate, utils.GetAPViewMode(w.ViewMode)) } // Datatx contains the parameters for the Datatx protocol. @@ -109,11 +111,22 @@ func (p *Protocols) UnmarshalJSON(data []byte) error { for name, d := range prot { var res Protocol + + // we do not support the OCM v1.0 properties for now, therefore we just skip them + if name == "name" { + continue + } + if name == "options" { + var opt map[string]any + if err := json.Unmarshal(d, &opt); err != nil || len(opt) > 0 { + return fmt.Errorf("protocol options not supported: %s", string(d)) + } + continue + } ctype, ok := protocolImpl[name] if !ok { return fmt.Errorf("protocol %s not recognised", name) } - res = reflect.New(ctype).Interface().(Protocol) if err := json.Unmarshal(d, &res); err != nil { return err @@ -126,10 +139,15 @@ func (p *Protocols) UnmarshalJSON(data []byte) error { // MarshalJSON implements the Marshaler interface. func (p Protocols) MarshalJSON() ([]byte, error) { - d := make(map[string]Protocol) + d := make(map[string]any) for _, prot := range p { d[getProtocolName(prot)] = prot } + // fill in the OCM v1.0 properties, but only if at least a protocol was defined + if len(p) > 0 { + d["name"] = "multi" + d["options"] = map[string]any{} + } return json.Marshal(d) } diff --git a/internal/http/services/ocmd/protocols_test.go b/internal/http/services/ocmd/protocols_test.go index 20c20f9a9a6..d884858f89e 100644 --- a/internal/http/services/ocmd/protocols_test.go +++ b/internal/http/services/ocmd/protocols_test.go @@ -37,7 +37,11 @@ func TestUnmarshalProtocol(t *testing.T) { expected: []Protocol{}, }, { - raw: `{"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"}}`, + raw: `{"name":"foo", "options":{"unsupported": "value"}}`, + err: `protocol options not supported: {"unsupported": "value"}`, + }, + { + raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"}}`, expected: []Protocol{ &WebDAV{ SharedSecret: "secret", @@ -47,7 +51,7 @@ func TestUnmarshalProtocol(t *testing.T) { }, }, { - raw: `{"webapp":{"uriTemplate":"http://example.org/{test}"}}`, + raw: `{"name":"multi","options":{},"webapp":{"uriTemplate":"http://example.org/{test}"}}`, expected: []Protocol{ &Webapp{ URITemplate: "http://example.org/{test}", @@ -55,7 +59,7 @@ func TestUnmarshalProtocol(t *testing.T) { }, }, { - raw: `{"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`, + raw: `{"name":"multi","options":{},"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`, expected: []Protocol{ &Datatx{ SharedSecret: "secret", @@ -65,7 +69,7 @@ func TestUnmarshalProtocol(t *testing.T) { }, }, { - raw: `{"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"},"webapp":{"uriTemplate":"http://example.org/{test}"},"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`, + raw: `{"name":"multi","options":{},"webdav":{"sharedSecret":"secret","permissions":["read","write"],"url":"http://example.org"},"webapp":{"uriTemplate":"http://example.org/{test}"},"datatx":{"sharedSecret":"secret","srcUri":"http://example.org","size":10}}`, expected: []Protocol{ &WebDAV{ SharedSecret: "secret", @@ -125,11 +129,11 @@ func protocolsEqual(p1, p2 Protocols) bool { func TestMarshalProtocol(t *testing.T) { tests := []struct { in Protocols - expected map[string]map[string]any + expected map[string]any }{ { in: []Protocol{}, - expected: map[string]map[string]any{}, + expected: map[string]any{}, }, { in: []Protocol{ @@ -139,8 +143,10 @@ func TestMarshalProtocol(t *testing.T) { URL: "http://example.org", }, }, - expected: map[string]map[string]any{ - "webdav": { + expected: map[string]any{ + "name": "multi", + "options": map[string]any{}, + "webdav": map[string]any{ "sharedSecret": "secret", "permissions": []any{"read"}, "url": "http://example.org", @@ -151,11 +157,15 @@ func TestMarshalProtocol(t *testing.T) { in: []Protocol{ &Webapp{ URITemplate: "http://example.org", + ViewMode: "read", }, }, - expected: map[string]map[string]any{ - "webapp": { + expected: map[string]any{ + "name": "multi", + "options": map[string]any{}, + "webapp": map[string]any{ "uriTemplate": "http://example.org", + "viewMode": "read", }, }, }, @@ -167,8 +177,10 @@ func TestMarshalProtocol(t *testing.T) { Size: 10, }, }, - expected: map[string]map[string]any{ - "datatx": { + expected: map[string]any{ + "name": "multi", + "options": map[string]any{}, + "datatx": map[string]any{ "sharedSecret": "secret", "srcUri": "http://example.org/source", "size": float64(10), @@ -184,6 +196,7 @@ func TestMarshalProtocol(t *testing.T) { }, &Webapp{ URITemplate: "http://example.org", + ViewMode: "read", }, &Datatx{ SharedSecret: "secret", @@ -191,16 +204,19 @@ func TestMarshalProtocol(t *testing.T) { Size: 10, }, }, - expected: map[string]map[string]any{ - "webdav": { + expected: map[string]any{ + "name": "multi", + "options": map[string]any{}, + "webdav": map[string]any{ "sharedSecret": "secret", "permissions": []any{"read"}, "url": "http://example.org", }, - "webapp": { + "webapp": map[string]any{ "uriTemplate": "http://example.org", + "viewMode": "read", }, - "datatx": { + "datatx": map[string]any{ "sharedSecret": "secret", "srcUri": "http://example.org/source", "size": float64(10), @@ -215,7 +231,7 @@ func TestMarshalProtocol(t *testing.T) { t.Fatal("not expected error", err) } - var got map[string]map[string]any + var got map[string]any if err := json.Unmarshal(d, &got); err != nil { t.Fatal("not expected error", err) } diff --git a/internal/http/services/ocmd/shares.go b/internal/http/services/ocmd/shares.go index e8dec02fede..8ba0861f069 100644 --- a/internal/http/services/ocmd/shares.go +++ b/internal/http/services/ocmd/shares.go @@ -71,7 +71,7 @@ type createShareRequest struct { ShareType string `json:"shareType" validate:"required,oneof=user group"` // recipient share type (user or group) ResourceType string `json:"resourceType" validate:"required,oneof=file folder"` Expiration uint64 `json:"expiration"` - Protocols Protocols `json:"protocols" validate:"required"` + Protocols Protocols `json:"protocol" validate:"required"` } // CreateShare sends all the informations to the consumer needed to start diff --git a/pkg/ocm/client/client.go b/pkg/ocm/client/client.go index 7eb712b8883..a0a91914128 100644 --- a/pkg/ocm/client/client.go +++ b/pkg/ocm/client/client.go @@ -166,7 +166,7 @@ type NewShareRequest struct { ShareType string `json:"shareType"` Expiration uint64 `json:"expiration"` ResourceType string `json:"resourceType"` - Protocols ocmd.Protocols `json:"protocols"` + Protocols ocmd.Protocols `json:"protocol"` } func (r *NewShareRequest) toJSON() (io.Reader, error) { @@ -183,7 +183,7 @@ type NewShareResponse struct { } // NewShare creates a new share. -// https://github.com/cs3org/OCM-API/blob/223285aa4d828ed85c361c7382efd08c42b5e719/spec.yaml +// https://github.com/cs3org/OCM-API/blob/develop/spec.yaml func (c *OCMClient) NewShare(ctx context.Context, endpoint string, r *NewShareRequest) (*NewShareResponse, error) { url, err := url.JoinPath(endpoint, "shares") if err != nil { diff --git a/pkg/ocm/share/repository/sql/conversions.go b/pkg/ocm/share/repository/sql/conversions.go index 1d07f06edb1..b565a09617b 100644 --- a/pkg/ocm/share/repository/sql/conversions.go +++ b/pkg/ocm/share/repository/sql/conversions.go @@ -23,7 +23,7 @@ import ( "strconv" "strings" - providerv1beta1 "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1" + appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" ocm "github.com/cs3org/go-cs3apis/cs3/sharing/ocm/v1beta1" provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" @@ -78,8 +78,8 @@ const ( const ( // WebDAVProtocol is the WebDav protocol. WebDAVProtocol Protocol = iota - // WebappProtcol is the Webapp protocol. - WebappProtcol + // WebappProtocol is the Webapp protocol. + WebappProtocol // TransferProtocol is the Transfer protocol. TransferProtocol ) @@ -171,6 +171,7 @@ type dbProtocol struct { WebDAVSharedSecret *string WebDavPermissions *int WebappURITemplate *string + WebappViewMode *int TransferSourceURI *string TransferSharedSecret *string TransferSize *int @@ -272,7 +273,7 @@ func convertToCS3AccessMethod(m *dbAccessMethod) *ocm.AccessMethod { case WebDAVAccessMethod: return share.NewWebDavAccessMethod(conversions.RoleFromOCSPermissions(conversions.Permissions(*m.WebDAVPermissions)).CS3ResourcePermissions()) case WebappAccessMethod: - return share.NewWebappAccessMethod(providerv1beta1.ViewMode(*m.WebAppViewMode)) + return share.NewWebappAccessMethod(appprovider.ViewMode(*m.WebAppViewMode)) case TransferAccessMethod: return share.NewTransferAccessMethod() } @@ -285,8 +286,8 @@ func convertToCS3Protocol(p *dbProtocol) *ocm.Protocol { return share.NewWebDAVProtocol(*p.WebDAVURI, *p.WebDAVSharedSecret, &ocm.SharePermissions{ Permissions: conversions.RoleFromOCSPermissions(conversions.Permissions(*p.WebDavPermissions)).CS3ResourcePermissions(), }) - case WebappProtcol: - return share.NewWebappProtocol(*p.WebappURITemplate) + case WebappProtocol: + return share.NewWebappProtocol(*p.WebappURITemplate, appprovider.ViewMode(*p.WebappViewMode)) case TransferProtocol: return share.NewTransferProtocol(*p.TransferSourceURI, *p.TransferSharedSecret, uint64(*p.TransferSize)) } diff --git a/pkg/ocm/share/repository/sql/sql.go b/pkg/ocm/share/repository/sql/sql.go index e27bd366c2e..894ca1d778f 100644 --- a/pkg/ocm/share/repository/sql/sql.go +++ b/pkg/ocm/share/repository/sql/sql.go @@ -474,13 +474,13 @@ func storeWebDAVProtocol(tx *sql.Tx, shareID int64, o *ocm.Protocol_WebdavOption } func storeWebappProtocol(tx *sql.Tx, shareID int64, o *ocm.Protocol_WebappOptions) error { - pID, err := storeProtocol(tx, shareID, WebappProtcol) + pID, err := storeProtocol(tx, shareID, WebappProtocol) if err != nil { return err } - query := "INSERT INTO ocm_protocol_webapp SET ocm_protocol_id=?, uri_template=?" - params := []any{pID, o.WebappOptions.UriTemplate} + query := "INSERT INTO ocm_protocol_webapp SET ocm_protocol_id=?, uri_template=?, view_mode=?" + params := []any{pID, o.WebappOptions.UriTemplate, o.WebappOptions.ViewMode} _, err = tx.Exec(query, params...) return err @@ -604,7 +604,7 @@ func (m *mgr) getProtocolsIds(ctx context.Context, ids []any) (map[string][]*ocm if len(ids) == 0 { return protocols, nil } - query := "SELECT p.ocm_received_share_id, p.type, dav.uri, dav.shared_secret, dav.permissions, app.uri_template, tx.source_uri, tx.shared_secret, tx.size FROM ocm_received_share_protocols as p LEFT JOIN ocm_protocol_webdav as dav ON p.id=dav.ocm_protocol_id LEFT JOIN ocm_protocol_webapp as app ON p.id=app.ocm_protocol_id LEFT JOIN ocm_protocol_transfer as tx ON p.id=tx.ocm_protocol_id WHERE p.ocm_received_share_id IN " + query := "SELECT p.ocm_received_share_id, p.type, dav.uri, dav.shared_secret, dav.permissions, app.uri_template, app.view_mode, tx.source_uri, tx.shared_secret, tx.size FROM ocm_received_share_protocols as p LEFT JOIN ocm_protocol_webdav as dav ON p.id=dav.ocm_protocol_id LEFT JOIN ocm_protocol_webapp as app ON p.id=app.ocm_protocol_id LEFT JOIN ocm_protocol_transfer as tx ON p.id=tx.ocm_protocol_id WHERE p.ocm_received_share_id IN " in := strings.Repeat("?,", len(ids)) query += "(" + in[:len(in)-1] + ")" @@ -615,7 +615,7 @@ func (m *mgr) getProtocolsIds(ctx context.Context, ids []any) (map[string][]*ocm var p dbProtocol for rows.Next() { - if err := rows.Scan(&p.ShareID, &p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil { + if err := rows.Scan(&p.ShareID, &p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil { continue } protocols[p.ShareID] = append(protocols[p.ShareID], convertToCS3Protocol(&p)) @@ -683,7 +683,7 @@ func (m *mgr) getReceivedByKey(ctx context.Context, user *userpb.User, key *ocm. } func (m *mgr) getProtocols(ctx context.Context, id int) ([]*ocm.Protocol, error) { - query := "SELECT p.type, dav.uri, dav.shared_secret, dav.permissions, app.uri_template, tx.source_uri, tx.shared_secret, tx.size FROM ocm_received_share_protocols as p LEFT JOIN ocm_protocol_webdav as dav ON p.id=dav.ocm_protocol_id LEFT JOIN ocm_protocol_webapp as app ON p.id=app.ocm_protocol_id LEFT JOIN ocm_protocol_transfer as tx ON p.id=tx.ocm_protocol_id WHERE p.ocm_received_share_id=?" + query := "SELECT p.type, dav.uri, dav.shared_secret, dav.permissions, app.uri_template, app.view_mode, tx.source_uri, tx.shared_secret, tx.size FROM ocm_received_share_protocols as p LEFT JOIN ocm_protocol_webdav as dav ON p.id=dav.ocm_protocol_id LEFT JOIN ocm_protocol_webapp as app ON p.id=app.ocm_protocol_id LEFT JOIN ocm_protocol_transfer as tx ON p.id=tx.ocm_protocol_id WHERE p.ocm_received_share_id=?" var protocols []*ocm.Protocol rows, err := m.db.QueryContext(ctx, query, id) @@ -693,7 +693,7 @@ func (m *mgr) getProtocols(ctx context.Context, id int) ([]*ocm.Protocol, error) var p dbProtocol for rows.Next() { - if err := rows.Scan(&p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil { + if err := rows.Scan(&p.Type, &p.WebDAVURI, &p.WebDAVSharedSecret, &p.WebDavPermissions, &p.WebappURITemplate, &p.WebappViewMode, &p.TransferSourceURI, &p.TransferSharedSecret, &p.TransferSize); err != nil { continue } protocols = append(protocols, convertToCS3Protocol(&p)) diff --git a/pkg/ocm/share/repository/sql/sql_test.go b/pkg/ocm/share/repository/sql/sql_test.go index 66b9032431a..4c9e0226d87 100644 --- a/pkg/ocm/share/repository/sql/sql_test.go +++ b/pkg/ocm/share/repository/sql/sql_test.go @@ -248,6 +248,7 @@ func createReceivedShareTables(ctx *sql.Context, initData []*ocm.ReceivedShare) webapp := memory.NewTable(ocmProtWebappTable, sql.NewPrimaryKeySchema(sql.Schema{ {Name: "ocm_protocol_id", Type: sql.Int64, Source: ocmProtWebappTable, PrimaryKey: true, AutoIncrement: true}, {Name: "uri_template", Type: sql.Text, Source: ocmProtWebappTable, Nullable: false}, + {Name: "view_mode", Type: sql.Int8, Nullable: false, Source: ocmProtWebappTable}, }), &kfProtocols) tables[ocmProtWebappTable] = webapp @@ -276,8 +277,8 @@ func createReceivedShareTables(ctx *sql.Context, initData []*ocm.ReceivedShare) must(protocols.Insert(ctx, sql.NewRow(i, mustInt(share.Id.OpaqueId), int8(WebDAVProtocol)))) must(webdav.Insert(ctx, sql.NewRow(i, prot.WebdavOptions.Uri, prot.WebdavOptions.SharedSecret, int64(conversions.RoleFromResourcePermissions(prot.WebdavOptions.Permissions.Permissions).OCSPermissions())))) case *ocm.Protocol_WebappOptions: - must(protocols.Insert(ctx, sql.NewRow(i, mustInt(share.Id.OpaqueId), int8(WebappProtcol)))) - must(webapp.Insert(ctx, sql.NewRow(i, prot.WebappOptions.UriTemplate))) + must(protocols.Insert(ctx, sql.NewRow(i, mustInt(share.Id.OpaqueId), int8(WebappProtocol)))) + must(webapp.Insert(ctx, sql.NewRow(i, prot.WebappOptions.UriTemplate, int8(prot.WebappOptions.ViewMode)))) case *ocm.Protocol_TransferOptions: must(protocols.Insert(ctx, sql.NewRow(i, mustInt(share.Id.OpaqueId), int8(TransferProtocol)))) must(transfer.Insert(ctx, sql.NewRow(i, prot.TransferOptions.SourceUri, prot.TransferOptions.SharedSecret, int64(prot.TransferOptions.Size)))) @@ -1453,7 +1454,7 @@ func TestGetReceivedShare(t *testing.T) { share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), }), - share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234"), + share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE), share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10), }, }, @@ -1477,7 +1478,7 @@ func TestGetReceivedShare(t *testing.T) { share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), }), - share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234"), + share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE), share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10), }, }, @@ -1548,7 +1549,7 @@ func TestListReceviedShares(t *testing.T) { share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), }), - share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234"), + share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE), share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10), }, }, @@ -1572,7 +1573,7 @@ func TestListReceviedShares(t *testing.T) { share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), }), - share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234"), + share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE), share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10), }, }, @@ -1597,7 +1598,7 @@ func TestListReceviedShares(t *testing.T) { share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), }), - share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234"), + share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE), share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10), }, }, @@ -1614,7 +1615,7 @@ func TestListReceviedShares(t *testing.T) { State: ocm.ShareState_SHARE_STATE_ACCEPTED, ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ - share.NewWebappProtocol("https://cernbox.cern.ch/ocm/54321"), + share.NewWebappProtocol("https://cernbox.cern.ch/ocm/54321", appprovider.ViewMode_VIEW_MODE_READ_ONLY), }, }, }, @@ -1637,7 +1638,7 @@ func TestListReceviedShares(t *testing.T) { share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), }), - share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234"), + share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE), share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10), }, }, @@ -1655,7 +1656,7 @@ func TestListReceviedShares(t *testing.T) { ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Expiration: &typesv1beta1.Timestamp{}, Protocols: []*ocm.Protocol{ - share.NewWebappProtocol("https://cernbox.cern.ch/ocm/54321"), + share.NewWebappProtocol("https://cernbox.cern.ch/ocm/54321", appprovider.ViewMode_VIEW_MODE_READ_ONLY), }, }, }, @@ -1679,7 +1680,7 @@ func TestListReceviedShares(t *testing.T) { share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), }), - share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234"), + share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE), share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10), }, }, @@ -1696,7 +1697,7 @@ func TestListReceviedShares(t *testing.T) { State: ocm.ShareState_SHARE_STATE_ACCEPTED, ResourceType: providerv1beta1.ResourceType_RESOURCE_TYPE_CONTAINER, Protocols: []*ocm.Protocol{ - share.NewWebappProtocol("https://cernbox.cern.ch/ocm/54321"), + share.NewWebappProtocol("https://cernbox.cern.ch/ocm/54321", appprovider.ViewMode_VIEW_MODE_READ_WRITE), }, }, }, @@ -1719,7 +1720,7 @@ func TestListReceviedShares(t *testing.T) { share.NewWebDAVProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", &ocm.SharePermissions{ Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), }), - share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234"), + share.NewWebappProtocol("https://cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE), share.NewTransferProtocol("webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", 10), }, }, @@ -1847,7 +1848,7 @@ func TestStoreReceivedShare(t *testing.T) { Permissions: conversions.NewEditorRole().CS3ResourcePermissions(), }), share.NewTransferProtocol("https://transfer.cernbox.cern.ch/ocm/1234", "secret", 100), - share.NewWebappProtocol("https://app.cernbox.cern.ch/ocm/1234"), + share.NewWebappProtocol("https://app.cernbox.cern.ch/ocm/1234", appprovider.ViewMode_VIEW_MODE_READ_WRITE), }, }, expected: storeReceivedShareExpected{ @@ -1859,14 +1860,14 @@ func TestStoreReceivedShare(t *testing.T) { {int64(1), int64(1), int8(WebDAVProtocol)}, {int64(2), int64(2), int8(WebDAVProtocol)}, {int64(3), int64(2), int8(TransferProtocol)}, - {int64(4), int64(2), int8(WebappProtcol)}, + {int64(4), int64(2), int8(WebappProtocol)}, }, webdav: []sql.Row{ {int64(1), "webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", int64(15)}, {int64(2), "webdav+https//cernbox.cern.ch/dav/ocm/1", "secret", int64(15)}, }, webapp: []sql.Row{ - {int64(4), "https://app.cernbox.cern.ch/ocm/1234"}, + {int64(4), "https://app.cernbox.cern.ch/ocm/1234", int8(3)}, }, transfer: []sql.Row{ {int64(3), "https://transfer.cernbox.cern.ch/ocm/1234", "secret", int64(100)}, diff --git a/pkg/ocm/share/utils.go b/pkg/ocm/share/utils.go index f18bd7ce4f5..63bed64b85f 100644 --- a/pkg/ocm/share/utils.go +++ b/pkg/ocm/share/utils.go @@ -38,11 +38,12 @@ func NewWebDAVProtocol(uri, shareSecred string, perms *ocm.SharePermissions) *oc } // NewWebappProtocol is an abstraction for creating a Webapp protocol. -func NewWebappProtocol(uriTemplate string) *ocm.Protocol { +func NewWebappProtocol(uriTemplate string, viewMode appprovider.ViewMode) *ocm.Protocol { return &ocm.Protocol{ Term: &ocm.Protocol_WebappOptions{ WebappOptions: &ocm.WebappProtocol{ UriTemplate: uriTemplate, + ViewMode: viewMode, }, }, } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 17102c517d1..5a5327c07aa 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -31,6 +31,7 @@ import ( "strings" "time" + appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1" gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" grouppb "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1" userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" @@ -356,6 +357,22 @@ func GetViewMode(viewMode string) gateway.OpenInAppRequest_ViewMode { } } +// GetAPViewMode converts a human-readable string to a appprovider view mode for opening a resource in an app. +func GetAPViewMode(viewMode string) appprovider.ViewMode { + switch viewMode { + case "view": + return appprovider.ViewMode_VIEW_MODE_VIEW_ONLY + case "read": + return appprovider.ViewMode_VIEW_MODE_READ_ONLY + case "write": + return appprovider.ViewMode_VIEW_MODE_READ_WRITE + case "preview": + return appprovider.ViewMode_VIEW_MODE_PREVIEW + default: + return appprovider.ViewMode_VIEW_MODE_INVALID + } +} + // HasPublicShareRole return true if the user has a public share role. // If yes, the string is the type of role, viewer, editor or uploader. func HasPublicShareRole(u *userpb.User) (string, bool) {