mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-05 11:51:16 -06:00
adjust REPORT to PROPFIND endpoint
Signed-off-by: jkoberg <jkoberg@owncloud.com>
This commit is contained in:
12
changelog/unreleased/fix-search-report.md
Normal file
12
changelog/unreleased/fix-search-report.md
Normal file
@@ -0,0 +1,12 @@
|
||||
Bugfix: Fix search report
|
||||
|
||||
There were multiple issues with REPORT search responses from webdav. Also we want it to be consistent with PROPFIND responses.
|
||||
* the `remote.php` prefix was missing from the href (added even though not neccessary)
|
||||
* the ids were formatted wrong, they should look different for shares and spaces.
|
||||
* the name of the resource was missing
|
||||
* the shareid was missing (for shares)
|
||||
* the prop `shareroot` (containing the name of the share root) was missing
|
||||
* the permissions prop was empty
|
||||
|
||||
https://github.com/owncloud/web/issues/7557
|
||||
https://github.com/owncloud/ocis/pull/4484
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -28,6 +29,25 @@ import (
|
||||
searchsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/search/v0"
|
||||
)
|
||||
|
||||
// Permissions is copied from reva internal conversion pkg
|
||||
type Permissions uint
|
||||
|
||||
// consts are copied from reva internal conversion pkg
|
||||
const (
|
||||
// PermissionInvalid represents an invalid permission
|
||||
PermissionInvalid Permissions = 0
|
||||
// PermissionRead grants read permissions on a resource
|
||||
PermissionRead Permissions = 1 << (iota - 1)
|
||||
// PermissionWrite grants write permissions on a resource
|
||||
PermissionWrite
|
||||
// PermissionCreate grants create permissions on a resource
|
||||
PermissionCreate
|
||||
// PermissionDelete grants delete permissions on a resource
|
||||
PermissionDelete
|
||||
// PermissionShare grants share permissions on a resource
|
||||
PermissionShare
|
||||
)
|
||||
|
||||
var ListenEvents = []events.Unmarshaller{
|
||||
events.ItemTrashed{},
|
||||
events.ItemRestored{},
|
||||
@@ -119,7 +139,11 @@ func (p *Provider) Search(ctx context.Context, req *searchsvc.SearchRequest) (*s
|
||||
SpaceId: space.Root.SpaceId,
|
||||
OpaqueId: space.Root.OpaqueId,
|
||||
}
|
||||
var mountpointRootId *searchmsg.ResourceID
|
||||
var (
|
||||
mountpointRootID *searchmsg.ResourceID
|
||||
rootName string
|
||||
permissions *provider.ResourcePermissions
|
||||
)
|
||||
mountpointPrefix := ""
|
||||
switch space.SpaceType {
|
||||
case "mountpoint":
|
||||
@@ -127,7 +151,7 @@ func (p *Provider) Search(ctx context.Context, req *searchsvc.SearchRequest) (*s
|
||||
case "grant":
|
||||
// In case of grant spaces we search the root of the outer space and translate the paths to the according mountpoint
|
||||
searchRootId.OpaqueId = space.Root.SpaceId
|
||||
mountpointId, ok := mountpointMap[space.Id.OpaqueId]
|
||||
mountpointID, ok := mountpointMap[space.Id.OpaqueId]
|
||||
if !ok {
|
||||
p.logger.Warn().Interface("space", space).Msg("could not find mountpoint space for grant space")
|
||||
continue
|
||||
@@ -144,17 +168,19 @@ func (p *Provider) Search(ctx context.Context, req *searchsvc.SearchRequest) (*s
|
||||
continue
|
||||
}
|
||||
mountpointPrefix = utils.MakeRelativePath(gpRes.Path)
|
||||
sid, spid, oid, err := storagespace.SplitID(mountpointId)
|
||||
sid, spid, oid, err := storagespace.SplitID(mountpointID)
|
||||
if err != nil {
|
||||
p.logger.Error().Err(err).Str("space", space.Id.OpaqueId).Str("mountpointId", mountpointId).Msg("invalid mountpoint space id")
|
||||
p.logger.Error().Err(err).Str("space", space.Id.OpaqueId).Str("mountpointId", mountpointID).Msg("invalid mountpoint space id")
|
||||
continue
|
||||
}
|
||||
mountpointRootId = &searchmsg.ResourceID{
|
||||
mountpointRootID = &searchmsg.ResourceID{
|
||||
StorageId: sid,
|
||||
SpaceId: spid,
|
||||
OpaqueId: oid,
|
||||
}
|
||||
p.logger.Debug().Interface("grantSpace", space).Interface("mountpointRootId", mountpointRootId).Msg("searching a grant")
|
||||
rootName = space.GetRootInfo().GetPath()
|
||||
permissions = space.GetRootInfo().GetPermissionSet()
|
||||
p.logger.Debug().Interface("grantSpace", space).Interface("mountpointRootId", mountpointRootID).Msg("searching a grant")
|
||||
}
|
||||
|
||||
res, err := p.indexClient.Search(ctx, &searchsvc.SearchIndexRequest{
|
||||
@@ -176,9 +202,11 @@ func (p *Provider) Search(ctx context.Context, req *searchsvc.SearchRequest) (*s
|
||||
if mountpointPrefix != "" {
|
||||
match.Entity.Ref.Path = utils.MakeRelativePath(strings.TrimPrefix(match.Entity.Ref.Path, mountpointPrefix))
|
||||
}
|
||||
if mountpointRootId != nil {
|
||||
match.Entity.Ref.ResourceId = mountpointRootId
|
||||
if mountpointRootID != nil {
|
||||
match.Entity.Ref.ResourceId = mountpointRootID
|
||||
}
|
||||
match.Entity.ShareRootName = rootName
|
||||
match.Entity.Permissions = convertToOCS(permissions)
|
||||
matches = append(matches, match)
|
||||
}
|
||||
}
|
||||
@@ -279,3 +307,40 @@ func formatQuery(q string) string {
|
||||
// this is a basic filename search
|
||||
return "Name:*" + strings.ReplaceAll(strings.ToLower(query), " ", `\ `) + "*"
|
||||
}
|
||||
|
||||
// NOTE: this converts cs3 to ocs permissions
|
||||
// since conversions pkg is reva internal we have no other choice than to duplicate the logic
|
||||
func convertToOCS(p *provider.ResourcePermissions) string {
|
||||
var ocs Permissions
|
||||
if p == nil {
|
||||
return ""
|
||||
}
|
||||
if p.ListContainer &&
|
||||
p.ListFileVersions &&
|
||||
p.ListRecycle &&
|
||||
p.Stat &&
|
||||
p.GetPath &&
|
||||
p.GetQuota &&
|
||||
p.InitiateFileDownload {
|
||||
ocs |= PermissionRead
|
||||
}
|
||||
if p.InitiateFileUpload &&
|
||||
p.RestoreFileVersion &&
|
||||
p.RestoreRecycleItem {
|
||||
ocs |= PermissionWrite
|
||||
}
|
||||
if p.ListContainer &&
|
||||
p.Stat &&
|
||||
p.CreateContainer &&
|
||||
p.InitiateFileUpload {
|
||||
ocs |= PermissionCreate
|
||||
}
|
||||
if p.Delete &&
|
||||
p.PurgeRecycle {
|
||||
ocs |= PermissionDelete
|
||||
}
|
||||
if p.AddGrant {
|
||||
ocs |= PermissionShare
|
||||
}
|
||||
return strconv.FormatUint(uint64(ocs), 10)
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
revactx "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
searchmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/search/v0"
|
||||
searchsvc "github.com/owncloud/ocis/v2/protogen/gen/ocis/services/search/v0"
|
||||
"github.com/owncloud/ocis/v2/services/webdav/pkg/net"
|
||||
@@ -102,8 +104,39 @@ func multistatusResponse(ctx context.Context, matches []*searchmsg.Match) ([]byt
|
||||
}
|
||||
|
||||
func matchToPropResponse(ctx context.Context, match *searchmsg.Match) (*propfind.ResponseXML, error) {
|
||||
// unfortunately search uses own versions of ResourceId and Ref. So we need to assert them here
|
||||
var (
|
||||
ref string
|
||||
err error
|
||||
)
|
||||
|
||||
// to copy PROPFIND behaviour we need to deliver different ids
|
||||
// for shares it needs to be sharestorageproviderid!shareid
|
||||
// for other spaces it needs to be storageproviderid$spaceid
|
||||
switch match.Entity.Ref.ResourceId.StorageId {
|
||||
default:
|
||||
ref, err = storagespace.FormatReference(&provider.Reference{
|
||||
ResourceId: &provider.ResourceId{
|
||||
StorageId: match.Entity.Ref.ResourceId.StorageId,
|
||||
SpaceId: match.Entity.Ref.ResourceId.SpaceId,
|
||||
},
|
||||
Path: match.Entity.Ref.Path,
|
||||
})
|
||||
case utils.ShareStorageProviderID:
|
||||
ref, err = storagespace.FormatReference(&provider.Reference{
|
||||
ResourceId: &provider.ResourceId{
|
||||
//StorageId: match.Entity.Ref.ResourceId.StorageId,
|
||||
SpaceId: match.Entity.Ref.ResourceId.SpaceId,
|
||||
OpaqueId: match.Entity.Ref.ResourceId.OpaqueId,
|
||||
},
|
||||
Path: match.Entity.Ref.Path,
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response := propfind.ResponseXML{
|
||||
Href: net.EncodePath(path.Join("/dav/spaces/", match.Entity.Ref.ResourceId.StorageId+"!"+match.Entity.Ref.ResourceId.OpaqueId, match.Entity.Ref.Path)),
|
||||
Href: net.EncodePath(path.Join("/remote.php/dav/spaces/", ref)),
|
||||
Propstat: []propfind.PropstatXML{},
|
||||
}
|
||||
|
||||
@@ -112,10 +145,22 @@ func matchToPropResponse(ctx context.Context, match *searchmsg.Match) (*propfind
|
||||
Prop: []prop.PropertyXML{},
|
||||
}
|
||||
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:fileid", match.Entity.Id.StorageId+"!"+match.Entity.Id.OpaqueId))
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("d:getetag", match.Entity.Etag))
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:fileid", storagespace.FormatResourceID(provider.ResourceId{
|
||||
StorageId: match.Entity.Id.StorageId,
|
||||
SpaceId: match.Entity.Id.SpaceId,
|
||||
OpaqueId: match.Entity.Id.OpaqueId,
|
||||
})))
|
||||
if match.Entity.Ref.ResourceId.StorageId == utils.ShareStorageProviderID {
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:shareid", match.Entity.Ref.ResourceId.OpaqueId))
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:shareroot", match.Entity.ShareRootName))
|
||||
}
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:name", match.Entity.Name))
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("d:getlastmodified", match.Entity.LastModifiedTime.AsTime().Format(time.RFC3339)))
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("d:getcontenttype", match.Entity.MimeType))
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("oc:permissions", match.Entity.Permissions))
|
||||
|
||||
// those seem empty - bug?
|
||||
propstatOK.Prop = append(propstatOK.Prop, prop.Escaped("d:getetag", match.Entity.Etag))
|
||||
|
||||
size := strconv.FormatUint(match.Entity.Size, 10)
|
||||
if match.Entity.Type == uint64(provider.ResourceType_RESOURCE_TYPE_CONTAINER) {
|
||||
|
||||
Reference in New Issue
Block a user