mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-02-28 17:38:59 -06:00
Provide Search filter for locations #OCIS-3705
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
Enhancement: Provide Search filter for locations
|
||||
|
||||
The search result REPORT response now can be restricted the by the current folder via api (recursive)
|
||||
The scope needed for "current folder" (default is to search all available spaces) - part of the oc:pattern:"scope:<uuid>
|
||||
/Test"
|
||||
|
||||
https://github.com/owncloud/ocis/pull/6713
|
||||
OCIS-3705
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
|
||||
"github.com/cs3org/reva/v2/pkg/errtypes"
|
||||
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/cs3org/reva/v2/pkg/storagespace"
|
||||
"github.com/cs3org/reva/v2/pkg/utils"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/log"
|
||||
searchmsg "github.com/owncloud/ocis/v2/protogen/gen/ocis/messages/search/v0"
|
||||
@@ -20,6 +22,8 @@ import (
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
var scopeRegex = regexp.MustCompile(`scope:\s*([^" "\n\r]*)`)
|
||||
|
||||
// ResolveReference makes sure the path is relative to the space root
|
||||
func ResolveReference(ctx context.Context, ref *provider.Reference, ri *provider.ResourceInfo, gatewaySelector pool.Selectable[gateway.GatewayAPIClient]) (*provider.Reference, error) {
|
||||
if ref.GetResourceId().GetOpaqueId() == ref.GetResourceId().GetSpaceId() {
|
||||
@@ -155,3 +159,28 @@ func convertToWebDAVPermissions(isShared, isMountpoint, isDir bool, p *provider.
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func extractScope(path string) (*searchmsg.Reference, error) {
|
||||
ref, err := storagespace.ParseReference(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &searchmsg.Reference{
|
||||
ResourceId: &searchmsg.ResourceID{
|
||||
StorageId: ref.ResourceId.StorageId,
|
||||
SpaceId: ref.ResourceId.SpaceId,
|
||||
OpaqueId: ref.ResourceId.OpaqueId,
|
||||
},
|
||||
Path: ref.GetPath(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ParseScope extract a scope value from the query string and returns search, scope strings
|
||||
func ParseScope(query string) (string, string) {
|
||||
match := scopeRegex.FindStringSubmatch(query)
|
||||
if len(match) >= 2 {
|
||||
cut := match[0]
|
||||
return strings.TrimSpace(strings.ReplaceAll(query, cut, "")), strings.TrimSpace(match[1])
|
||||
}
|
||||
return query, ""
|
||||
}
|
||||
|
||||
@@ -72,10 +72,31 @@ func NewService(gatewaySelector pool.Selectable[gateway.GatewayAPIClient], eng e
|
||||
|
||||
// Search processes a search request and passes it down to the engine.
|
||||
func (s *Service) Search(ctx context.Context, req *searchsvc.SearchRequest) (*searchsvc.SearchResponse, error) {
|
||||
if req.Query == "" {
|
||||
s.logger.Debug().Str("query", req.Query).Msg("performing a search")
|
||||
query, scope := ParseScope(req.Query)
|
||||
if query == "" {
|
||||
return nil, errtypes.BadRequest("empty query provided")
|
||||
}
|
||||
s.logger.Debug().Str("query", req.Query).Msg("performing a search")
|
||||
req.Query = query
|
||||
var filters []*provider.ListStorageSpacesRequest_Filter
|
||||
if len(scope) > 0 {
|
||||
scopeRef, err := extractScope(scope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.Ref == nil {
|
||||
req.Ref = scopeRef
|
||||
}
|
||||
req.Ref.Path = scopeRef.GetPath()
|
||||
if scopeRef.GetResourceId().OpaqueId != "" {
|
||||
filters = []*provider.ListStorageSpacesRequest_Filter{
|
||||
{
|
||||
Type: provider.ListStorageSpacesRequest_Filter_TYPE_ID,
|
||||
Term: &provider.ListStorageSpacesRequest_Filter_Id{Id: &provider.StorageSpaceId{OpaqueId: scopeRef.GetResourceId().OpaqueId}},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
@@ -84,18 +105,17 @@ func (s *Service) Search(ctx context.Context, req *searchsvc.SearchRequest) (*se
|
||||
|
||||
currentUser := revactx.ContextMustGetUser(ctx)
|
||||
|
||||
listSpacesRes, err := gatewayClient.ListStorageSpaces(ctx, &provider.ListStorageSpacesRequest{
|
||||
Filters: []*provider.ListStorageSpacesRequest_Filter{
|
||||
{
|
||||
Type: provider.ListStorageSpacesRequest_Filter_TYPE_USER,
|
||||
Term: &provider.ListStorageSpacesRequest_Filter_User{User: currentUser.GetId()},
|
||||
},
|
||||
{
|
||||
Type: provider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE,
|
||||
Term: &provider.ListStorageSpacesRequest_Filter_SpaceType{SpaceType: "+grant"},
|
||||
},
|
||||
filters = append(filters, []*provider.ListStorageSpacesRequest_Filter{
|
||||
{
|
||||
Type: provider.ListStorageSpacesRequest_Filter_TYPE_USER,
|
||||
Term: &provider.ListStorageSpacesRequest_Filter_User{User: currentUser.GetId()},
|
||||
},
|
||||
})
|
||||
{
|
||||
Type: provider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE,
|
||||
Term: &provider.ListStorageSpacesRequest_Filter_SpaceType{SpaceType: "+grant"},
|
||||
},
|
||||
}...)
|
||||
listSpacesRes, err := gatewayClient.ListStorageSpaces(ctx, &provider.ListStorageSpacesRequest{Filters: filters})
|
||||
if err != nil {
|
||||
s.logger.Error().Err(err).Msg("failed to list the user's storage spaces")
|
||||
return nil, err
|
||||
@@ -229,7 +249,7 @@ func (s *Service) searchIndex(ctx context.Context, req *searchsvc.SearchRequest,
|
||||
rootName string
|
||||
permissions *provider.ResourcePermissions
|
||||
)
|
||||
mountpointPrefix := ""
|
||||
mountpointPrefix := req.GetRef().GetPath()
|
||||
switch space.SpaceType {
|
||||
case "mountpoint":
|
||||
return nil, errSkipSpace // mountpoint spaces are only "links" to the shared spaces. we have to search the shared "grant" space instead
|
||||
|
||||
@@ -391,3 +391,51 @@ var _ = Describe("Searchprovider", func() {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
var _ = DescribeTable("Parse Scope",
|
||||
func(pattern, wantSearch, wantScope string) {
|
||||
gotSearch, gotScope := search.ParseScope(pattern)
|
||||
Expect(gotSearch).To(Equal(wantSearch))
|
||||
Expect(gotScope).To(Equal(wantScope))
|
||||
},
|
||||
Entry("When scope is at the end of the line",
|
||||
`+Name:*file* +Tags:"foo" scope:<uuid>/folder/subfolder`,
|
||||
`+Name:*file* +Tags:"foo"`,
|
||||
`<uuid>/folder/subfolder`,
|
||||
),
|
||||
Entry("When scope is at the end of the line 2",
|
||||
`+Name:*file* +Tags:"foo" scope:<uuid>/folder`,
|
||||
`+Name:*file* +Tags:"foo"`,
|
||||
`<uuid>/folder`,
|
||||
),
|
||||
Entry("When scope is at the end of the line 3",
|
||||
`file scope:<uuid>/folder/subfolder`,
|
||||
`file`,
|
||||
`<uuid>/folder/subfolder`,
|
||||
),
|
||||
Entry("When scope is at the end of the line with a space",
|
||||
`+Name:*file* +Tags:"foo" scope: <uuid>/folder/subfolder`,
|
||||
`+Name:*file* +Tags:"foo"`,
|
||||
`<uuid>/folder/subfolder`,
|
||||
),
|
||||
Entry("When scope is in the middle of the line",
|
||||
`+Name:*file* scope:<uuid>/folder/subfolder +Tags:"foo"`,
|
||||
`+Name:*file* +Tags:"foo"`,
|
||||
`<uuid>/folder/subfolder`,
|
||||
),
|
||||
Entry("When scope is at the end of the line",
|
||||
`scope:<uuid>/folder/subfolder +Name:*file*`,
|
||||
`+Name:*file*`,
|
||||
`<uuid>/folder/subfolder`,
|
||||
),
|
||||
Entry("When scope is at the begging of the line",
|
||||
`scope:<uuid>/folder/subfolder file`,
|
||||
`file`,
|
||||
`<uuid>/folder/subfolder`,
|
||||
),
|
||||
Entry("When no scope",
|
||||
`+Name:*file* +Tags:"foo"`,
|
||||
`+Name:*file* +Tags:"foo"`,
|
||||
``,
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user