From 5cefb2bec7d164ddb25af38dc4ffbe0a2fdc8cdd Mon Sep 17 00:00:00 2001 From: David Christofas Date: Wed, 2 Dec 2020 15:37:02 +0100 Subject: [PATCH] return share-types in ocs propfind responses Implements https://github.com/owncloud/ocis/issues/929 --- changelog/unreleased/ocis-ocs-share-types.md | 6 ++++ .../grpc/services/gateway/storageprovider.go | 5 ++-- .../http/services/owncloud/ocdav/propfind.go | 21 ++++++++++---- pkg/storage/fs/ocis/node.go | 29 ++++++++++++++++++- pkg/storage/fs/ocis/ocis.go | 4 +-- 5 files changed, 54 insertions(+), 11 deletions(-) create mode 100644 changelog/unreleased/ocis-ocs-share-types.md diff --git a/changelog/unreleased/ocis-ocs-share-types.md b/changelog/unreleased/ocis-ocs-share-types.md new file mode 100644 index 0000000000..c185458b64 --- /dev/null +++ b/changelog/unreleased/ocis-ocs-share-types.md @@ -0,0 +1,6 @@ +Enhancement: include share types in ocs propfind responses + +Added the share types to the ocs propfind response when a resource has been shared. + +https://github.com/owncloud/ocis/issues/929 +https://github.com/cs3org/reva/pull/1329 diff --git a/internal/grpc/services/gateway/storageprovider.go b/internal/grpc/services/gateway/storageprovider.go index a563201268..3987b1aedd 100644 --- a/internal/grpc/services/gateway/storageprovider.go +++ b/internal/grpc/services/gateway/storageprovider.go @@ -1249,13 +1249,14 @@ func (s *svc) ListContainerStream(_ *provider.ListContainerStreamRequest, _ gate return errtypes.NotSupported("Unimplemented") } -func (s *svc) listHome(ctx context.Context) (*provider.ListContainerResponse, error) { +func (s *svc) listHome(ctx context.Context, req *provider.ListContainerRequest) (*provider.ListContainerResponse, error) { lcr, err := s.listContainer(ctx, &provider.ListContainerRequest{ Ref: &provider.Reference{ Spec: &provider.Reference_Path{ Path: s.getHome(ctx), }, }, + ArbitraryMetadataKeys: req.ArbitraryMetadataKeys, }) if err != nil { return &provider.ListContainerResponse{ @@ -1361,7 +1362,7 @@ func (s *svc) ListContainer(ctx context.Context, req *provider.ListContainerRequ } if path.Clean(p) == s.getHome(ctx) { - return s.listHome(ctx) + return s.listHome(ctx, req) } if s.isSharedFolder(ctx, p) { diff --git a/internal/http/services/owncloud/ocdav/propfind.go b/internal/http/services/owncloud/ocdav/propfind.go index 57fecfebf4..ca781e40c0 100644 --- a/internal/http/services/owncloud/ocdav/propfind.go +++ b/internal/http/services/owncloud/ocdav/propfind.go @@ -108,6 +108,9 @@ func (s *svc) handlePropfind(w http.ResponseWriter, r *http.Request, ns string) if info.Type == provider.ResourceType_RESOURCE_TYPE_CONTAINER && depth == "1" { req := &provider.ListContainerRequest{ Ref: ref, + ArbitraryMetadataKeys: []string{ + "http://owncloud.org/ns/share-types", + }, } res, err := client.ListContainer(ctx, req) if err != nil { @@ -143,6 +146,9 @@ func (s *svc) handlePropfind(w http.ResponseWriter, r *http.Request, ns string) } req := &provider.ListContainerRequest{ Ref: ref, + ArbitraryMetadataKeys: []string{ + "http://owncloud.org/ns/share-types", + }, } res, err := client.ListContainer(ctx, req) if err != nil { @@ -284,7 +290,6 @@ func (s *svc) newProp(key, val string) *propertyXML { // ns is the CS3 namespace that needs to be removed from the CS3 path before // prefixing it with the baseURI func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provider.ResourceInfo, ns string) (*responseXML, error) { - md.Path = strings.TrimPrefix(md.Path, ns) baseURI := ctx.Value(ctxKeyBaseURI).(string) @@ -442,6 +447,15 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide } else { propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:checksums", "")) } + case "share-types": // desktop + k := md.GetArbitraryMetadata() + amd := k.GetMetadata() + if amdv, ok := amd[fmt.Sprintf("%s/%s", pf.Prop[i].Space, pf.Prop[i].Local)]; ok { + st := fmt.Sprintf("%s", amdv) + propstatOK.Prop = append(propstatOK.Prop, s.newProp("oc:share-types", st)) + } else { + propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:"+pf.Prop[i].Local, "")) + } case "owner-display-name": // phoenix only // TODO(jfd): lookup displayname? or let clients do that? They should cache that IMO fallthrough @@ -459,11 +473,6 @@ func (s *svc) mdToPropResponse(ctx context.Context, pf *propfindXML, md *provide // see https://doc.owncloud.com/server/admin_manual/configuration/server/occ_command.html#maintenance-commands // TODO(jfd): double check the client behavior with reva on backup restore fallthrough - case "share-types": // desktop - // - // 1 - // - fallthrough default: propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:"+pf.Prop[i].Local, "")) } diff --git a/pkg/storage/fs/ocis/node.go b/pkg/storage/fs/ocis/node.go index bcde7b28cc..fd24f7771d 100644 --- a/pkg/storage/fs/ocis/node.go +++ b/pkg/storage/fs/ocis/node.go @@ -34,12 +34,18 @@ import ( "github.com/cs3org/reva/pkg/appctx" "github.com/cs3org/reva/pkg/errtypes" "github.com/cs3org/reva/pkg/mime" + "github.com/cs3org/reva/pkg/sdk/common" "github.com/cs3org/reva/pkg/storage/utils/ace" "github.com/pkg/errors" "github.com/pkg/xattr" "github.com/rs/zerolog/log" ) +const ( + _ShareTypesKey = "http://owncloud.org/ns/share-types" + _UserShareType = "0" +) + // Node represents a node in the tree and provides methods to get a Parent or Child instance type Node struct { lu *Lookup @@ -291,7 +297,7 @@ func (n *Node) Owner() (id string, idp string, err error) { } // AsResourceInfo return the node as CS3 ResourceInfo -func (n *Node) AsResourceInfo(ctx context.Context) (ri *provider.ResourceInfo, err error) { +func (n *Node) AsResourceInfo(ctx context.Context, mdKeys []string) (ri *provider.ResourceInfo, err error) { log := appctx.GetLogger(ctx) var fn string @@ -399,6 +405,12 @@ func (n *Node) AsResourceInfo(ctx context.Context) (ri *provider.ResourceInfo, e log.Error().Err(err).Interface("node", n).Msg("could not list attributes") } + if common.FindString(mdKeys, _ShareTypesKey) != -1 { + if n.hasUserShares(ctx) { + ri.ArbitraryMetadata.Metadata[_ShareTypesKey] = _UserShareType + } + } + log.Debug(). Interface("ri", ri). Msg("AsResourceInfo") @@ -469,3 +481,18 @@ func (n *Node) ReadGrant(ctx context.Context, grantee string) (g *provider.Grant } return e.Grant(), nil } + +func (n *Node) hasUserShares(ctx context.Context) bool { + g, err := n.ListGrantees(ctx) + if err != nil { + appctx.GetLogger(ctx).Error().Err(err).Msg("hasUserShares: listGrantees") + return false + } + + for i := range g { + if strings.Contains(g[i], grantPrefix+"u") { + return true + } + } + return false +} diff --git a/pkg/storage/fs/ocis/ocis.go b/pkg/storage/fs/ocis/ocis.go index 59f092997b..2cb9d2be10 100644 --- a/pkg/storage/fs/ocis/ocis.go +++ b/pkg/storage/fs/ocis/ocis.go @@ -371,7 +371,7 @@ func (fs *ocisfs) GetMD(ctx context.Context, ref *provider.Reference, mdKeys []s return nil, errtypes.PermissionDenied(node.ID) } - return node.AsResourceInfo(ctx) + return node.AsResourceInfo(ctx, mdKeys) } func (fs *ocisfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKeys []string) (finfos []*provider.ResourceInfo, err error) { @@ -402,7 +402,7 @@ func (fs *ocisfs) ListFolder(ctx context.Context, ref *provider.Reference, mdKey } for i := range children { - if ri, err := children[i].AsResourceInfo(ctx); err == nil { + if ri, err := children[i].AsResourceInfo(ctx, mdKeys); err == nil { finfos = append(finfos, ri) } }