Support scoping searches in shares

This commit is contained in:
André Duffeck
2023-07-07 09:09:19 +02:00
committed by Roman Perekhod
parent 3487749509
commit 4bb10ebdf3
2 changed files with 60 additions and 36 deletions

View File

@@ -160,13 +160,13 @@ func convertToWebDAVPermissions(isShared, isMountpoint, isDir bool, p *provider.
return b.String()
}
func extractScope(path string) (*searchmsg.Reference, error) {
func extractScope(path string) (*provider.Reference, error) {
ref, err := storagespace.ParseReference(path)
if err != nil {
return nil, err
}
return &searchmsg.Reference{
ResourceId: &searchmsg.ResourceID{
return &provider.Reference{
ResourceId: &provider.ResourceId{
StorageId: ref.ResourceId.StorageId,
SpaceId: ref.ResourceId.SpaceId,
OpaqueId: ref.ResourceId.OpaqueId,

View File

@@ -26,6 +26,7 @@ import (
"github.com/owncloud/ocis/v2/services/search/pkg/content"
"github.com/owncloud/ocis/v2/services/search/pkg/engine"
"golang.org/x/sync/errgroup"
"google.golang.org/protobuf/types/known/fieldmaskpb"
)
//go:generate mockery --name=Searcher
@@ -73,39 +74,53 @@ 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) {
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")
}
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 {
return nil, err
}
currentUser := revactx.ContextMustGetUser(ctx)
filters = append(filters, []*provider.ListStorageSpacesRequest_Filter{
// Extract scope from query if set
query, scope := ParseScope(req.Query)
if query == "" {
return nil, errtypes.BadRequest("empty query provided")
}
req.Query = query
if len(scope) > 0 {
if req.Ref != nil {
return nil, errtypes.BadRequest("cannot scope a search that is limited to a resource")
}
scopeRef, err := extractScope(scope)
if err != nil {
return nil, err
}
// Stat the scope to get the resource id
statRes, err := gatewayClient.Stat(ctx, &provider.StatRequest{
Ref: scopeRef,
FieldMask: &fieldmaskpb.FieldMask{Paths: []string{"space"}},
})
if err != nil {
return nil, err
}
// GetPath the scope to get the full path in the space
gpRes, err := gatewayClient.GetPath(ctx, &provider.GetPathRequest{
ResourceId: statRes.Info.Id,
})
if err != nil {
return nil, err
}
req.Ref = &searchmsg.Reference{
ResourceId: &searchmsg.ResourceID{
StorageId: statRes.Info.Space.Root.StorageId,
SpaceId: statRes.Info.Space.Root.SpaceId,
OpaqueId: statRes.Info.Space.Root.OpaqueId,
},
Path: gpRes.Path,
}
}
filters := []*provider.ListStorageSpacesRequest_Filter{
{
Type: provider.ListStorageSpacesRequest_Filter_TYPE_USER,
Term: &provider.ListStorageSpacesRequest_Filter_User{User: currentUser.GetId()},
@@ -114,19 +129,25 @@ func (s *Service) Search(ctx context.Context, req *searchsvc.SearchRequest) (*se
Type: provider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE,
Term: &provider.ListStorageSpacesRequest_Filter_SpaceType{SpaceType: "+grant"},
},
}...)
}
// Get the spaces to search
spaces := []*provider.StorageSpace{}
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
}
spaces := []*provider.StorageSpace{}
for _, space := range listSpacesRes.StorageSpaces {
if utils.ReadPlainFromOpaque(space.Opaque, "trashed") == _spaceStateTrashed {
// Do not consider disabled spaces
continue
}
if space.SpaceType != "mountpoint" && req.Ref != nil && (req.Ref.GetResourceId().GetSpaceId() != space.Root.GetSpaceId()) {
// Do not search (non-mountpoint) spaces that do not match the given scope (if a scope is set)
// We still need the mountpoint in order to map the result paths to the according share
continue
}
spaces = append(spaces, space)
}
@@ -233,8 +254,7 @@ func (s *Service) Search(ctx context.Context, req *searchsvc.SearchRequest) (*se
func (s *Service) searchIndex(ctx context.Context, req *searchsvc.SearchRequest, space *provider.StorageSpace, mountpointID string) (*searchsvc.SearchIndexResponse, error) {
if req.Ref != nil &&
(req.Ref.ResourceId.StorageId != space.Root.StorageId ||
req.Ref.ResourceId.SpaceId != space.Root.SpaceId ||
req.Ref.ResourceId.OpaqueId != space.Root.OpaqueId) {
req.Ref.ResourceId.SpaceId != space.Root.SpaceId) {
return nil, errSkipSpace
}
@@ -249,7 +269,8 @@ func (s *Service) searchIndex(ctx context.Context, req *searchsvc.SearchRequest,
rootName string
permissions *provider.ResourcePermissions
)
mountpointPrefix := req.GetRef().GetPath()
mountpointPrefix := ""
searchPathPrefix := req.Ref.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
@@ -292,6 +313,9 @@ func (s *Service) searchIndex(ctx context.Context, req *searchsvc.SearchRequest,
return nil, errSkipSpace
}
mountpointPrefix = utils.MakeRelativePath(gpRes.Path)
if searchPathPrefix == "" {
searchPathPrefix = mountpointPrefix
}
sid, spid, oid, err := storagespace.SplitID(mountpointID)
if err != nil {
s.logger.Error().Err(err).Str("space", space.Id.OpaqueId).Str("mountpointId", mountpointID).Msg("invalid mountpoint space id")
@@ -313,7 +337,7 @@ func (s *Service) searchIndex(ctx context.Context, req *searchsvc.SearchRequest,
Query: req.Query,
Ref: &searchmsg.Reference{
ResourceId: searchRootID,
Path: mountpointPrefix,
Path: searchPathPrefix,
},
PageSize: req.PageSize,
}