From c8c60929c954ac42504144d00d42fe0494bd0e04 Mon Sep 17 00:00:00 2001 From: David Christofas Date: Wed, 25 Nov 2020 13:08:33 +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 | 31 ++++++++++++++++++- pkg/storage/fs/ocis/ocis.go | 4 +-- 5 files changed, 56 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 00000000000..c185458b644 --- /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 399ab087a4f..7e376eea2bd 100644 --- a/internal/grpc/services/gateway/storageprovider.go +++ b/internal/grpc/services/gateway/storageprovider.go @@ -1586,13 +1586,14 @@ func (s *svc) ListContainerStream(_ *provider.ListContainerStreamRequest, _ gate return errors.New("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{ @@ -1726,7 +1727,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 e6fbdd591f3..58f8659ddc8 100644 --- a/internal/http/services/owncloud/ocdav/propfind.go +++ b/internal/http/services/owncloud/ocdav/propfind.go @@ -107,6 +107,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 { @@ -142,6 +145,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 { @@ -283,7 +289,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) @@ -441,6 +446,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 @@ -458,11 +472,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 2a6d32ed678..f2215b4a942 100644 --- a/pkg/storage/fs/ocis/node.go +++ b/pkg/storage/fs/ocis/node.go @@ -34,12 +34,17 @@ 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" +) + // Node represents a node in the tree and provides methods to get a Parent or Child instance type Node struct { lu *Lookup @@ -279,7 +284,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 @@ -376,6 +381,9 @@ func (n *Node) AsResourceInfo(ctx context.Context) (ri *provider.ResourceInfo, e for i := range attrs { if strings.HasPrefix(attrs[i], metadataPrefix) { k := strings.TrimPrefix(attrs[i], metadataPrefix) + if common.FindString(mdKeys, k) == -1 { + continue + } if v, err := xattr.Get(nodePath, attrs[i]); err == nil { ri.ArbitraryMetadata.Metadata[k] = string(v) } else { @@ -387,6 +395,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] = "0" + } + } + log.Debug(). Interface("ri", ri). Msg("AsResourceInfo") @@ -455,3 +469,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 59f092997b6..2cb9d2be101 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) } }