Skip to content

Commit

Permalink
return share-types in ocs propfind responses (#1329)
Browse files Browse the repository at this point in the history
  • Loading branch information
C0rby authored Dec 9, 2020
1 parent c1dba53 commit 80ba33a
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 16 deletions.
6 changes: 6 additions & 0 deletions changelog/unreleased/ocis-ocs-share-types.md
Original file line number Diff line number Diff line change
@@ -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
5 changes: 3 additions & 2 deletions internal/grpc/services/gateway/storageprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1265,13 +1265,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{
Expand Down Expand Up @@ -1377,7 +1378,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) {
Expand Down
21 changes: 15 additions & 6 deletions internal/http/services/owncloud/ocdav/propfind.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,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 {
Expand All @@ -124,6 +127,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 {
Expand Down Expand Up @@ -255,7 +261,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)
Expand Down Expand Up @@ -413,6 +418,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("<oc:share-type>%s</oc:share-type>", 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
Expand All @@ -430,11 +444,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
// <oc:share-types>
// <oc:share-type>1</oc:share-type>
// </oc:share-types>
fallthrough
default:
propstatNotFound.Prop = append(propstatNotFound.Prop, s.newProp("oc:"+pf.Prop[i].Local, ""))
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/storage/fs/ocis/grants.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@ func (fs *ocisfs) RemoveGrant(ctx context.Context, ref *provider.Reference, g *p

var attr string
if g.Grantee.Type == provider.GranteeType_GRANTEE_TYPE_GROUP {
attr = grantPrefix + "g:" + g.Grantee.Id.OpaqueId
attr = grantPrefix + _groupAcePrefix + g.Grantee.Id.OpaqueId
} else {
attr = grantPrefix + "u:" + g.Grantee.Id.OpaqueId
attr = grantPrefix + _userAcePrefix + g.Grantee.Id.OpaqueId
}

np := fs.lu.toInternalPath(node.ID)
Expand Down
29 changes: 28 additions & 1 deletion pkg/storage/fs/ocis/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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+_userAcePrefix) {
return true
}
}
return false
}
4 changes: 2 additions & 2 deletions pkg/storage/fs/ocis/ocis.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
}
}
Expand Down
11 changes: 8 additions & 3 deletions pkg/storage/fs/ocis/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ import (
"github.com/pkg/xattr"
)

const (
_userAcePrefix = "u:"
_groupAcePrefix = "g:"
)

var defaultPermissions *provider.ResourcePermissions = &provider.ResourcePermissions{
// no permissions
}
Expand Down Expand Up @@ -100,15 +105,15 @@ func (p *Permissions) HasPermission(ctx context.Context, n *Node, check func(*pr
return false, err
}

userace := grantPrefix + "u:" + u.Id.OpaqueId
userace := grantPrefix + _userAcePrefix + u.Id.OpaqueId
userFound := false
for i := range grantees {
// we only need the find the user once per node
switch {
case !userFound && grantees[i] == userace:
g, err = cn.ReadGrant(ctx, grantees[i])
case strings.HasPrefix(grantees[i], grantPrefix+"g:"):
gr := strings.TrimPrefix(grantees[i], grantPrefix+"g:")
case strings.HasPrefix(grantees[i], grantPrefix+_groupAcePrefix):
gr := strings.TrimPrefix(grantees[i], grantPrefix+_groupAcePrefix)
if groupsMap[gr] {
g, err = cn.ReadGrant(ctx, grantees[i])
} else {
Expand Down

0 comments on commit 80ba33a

Please sign in to comment.