diff --git a/internal/grpc/services/gateway/storageprovider.go b/internal/grpc/services/gateway/storageprovider.go index 1b6b3b8dcb6..a3778a54be7 100644 --- a/internal/grpc/services/gateway/storageprovider.go +++ b/internal/grpc/services/gateway/storageprovider.go @@ -241,6 +241,9 @@ func (s *svc) ListStorageSpaces(ctx context.Context, req *provider.ListStorageSp filters["owner_id"] = f.GetOwner().OpaqueId case provider.ListStorageSpacesRequest_Filter_TYPE_SPACE_TYPE: filters["space_type"] = f.GetSpaceType() + case provider.ListStorageSpacesRequest_Filter_TYPE_USER: + filters["user_idp"] = f.GetUser().GetIdp() + filters["user_id"] = f.GetUser().GetOpaqueId() default: return &provider.ListStorageSpacesResponse{ Status: status.NewInvalidArg(ctx, fmt.Sprintf("unknown filter %v", f.Type)), diff --git a/pkg/storage/registry/spaces/spaces.go b/pkg/storage/registry/spaces/spaces.go index 1ad2fdf0e1f..c1f517d6251 100644 --- a/pkg/storage/registry/spaces/spaces.go +++ b/pkg/storage/registry/spaces/spaces.go @@ -305,6 +305,17 @@ func (r *registry) buildFilters(filterMap map[string]string) []*providerpb.ListS }) } } + if filterMap["user_id"] != "" && filterMap["user_idp"] != "" { + filters = append(filters, &providerpb.ListStorageSpacesRequest_Filter{ + Type: providerpb.ListStorageSpacesRequest_Filter_TYPE_USER, + Term: &providerpb.ListStorageSpacesRequest_Filter_User{ + User: &userpb.UserId{ + Idp: filterMap["user_idp"], + OpaqueId: filterMap["user_id"], + }, + }, + }) + } if filterMap["owner_id"] != "" && filterMap["owner_idp"] != "" { filters = append(filters, &providerpb.ListStorageSpacesRequest_Filter{ Type: providerpb.ListStorageSpacesRequest_Filter_TYPE_OWNER, diff --git a/pkg/storage/utils/decomposedfs/grants.go b/pkg/storage/utils/decomposedfs/grants.go index b246a39bc8b..75dfae92746 100644 --- a/pkg/storage/utils/decomposedfs/grants.go +++ b/pkg/storage/utils/decomposedfs/grants.go @@ -248,7 +248,7 @@ func (fs *Decomposedfs) storeGrant(ctx context.Context, n *node.Node, g *provide // when a grant is added to a space, do not add a new space under "shares" if spaceGrant := ctx.Value(utils.SpaceGrant); spaceGrant == nil { - err := fs.linkStorageSpaceType(ctx, spaceTypeShare, n.ID) + err := fs.updateIndexes(ctx, g.GetGrantee().GetUserId().GetOpaqueId(), spaceTypeShare, n.ID) if err != nil { return err } diff --git a/pkg/storage/utils/decomposedfs/spaces.go b/pkg/storage/utils/decomposedfs/spaces.go index 52a9e4a06c7..680ced16806 100644 --- a/pkg/storage/utils/decomposedfs/spaces.go +++ b/pkg/storage/utils/decomposedfs/spaces.go @@ -105,7 +105,7 @@ func (fs *Decomposedfs) CreateStorageSpace(ctx context.Context, req *provider.Cr } } - err = fs.linkStorageSpaceType(ctx, req.Type, root.ID) + err = fs.updateIndexes(ctx, req.GetOwner().GetId().GetOpaqueId(), req.Type, root.ID) if err != nil { return nil, err } @@ -250,6 +250,7 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide var ( spaceID = spaceIDAny nodeID = spaceIDAny + userID = ctxpkg.ContextMustGetUser(ctx).GetId().GetOpaqueId() ) spaceTypes := []string{} @@ -270,6 +271,10 @@ func (fs *Decomposedfs) ListStorageSpaces(ctx context.Context, filter []*provide if strings.Contains(nodeID, "/") { return []*provider.StorageSpace{}, nil } + + case provider.ListStorageSpacesRequest_Filter_TYPE_USER: + // TODO: refactor this to GetUserId() in cs3 + userID = filter[i].GetUser() } } if len(spaceTypes) == 0 { @@ -552,7 +557,43 @@ func (fs *Decomposedfs) DeleteStorageSpace(ctx context.Context, req *provider.De return n.SetDTime(&dtime) } +func (fs *Decomposedfs) updateIndexes(ctx context.Context, userID, spaceType, spaceID string) error { + err := fs.linkStorageSpaceType(ctx, spaceType, spaceID) + if err != nil { + return err + } + return fs.linkSpaceByUser(ctx, userID, spaceID) +} + +func (fs *Decomposedfs) linkSpaceByUser(ctx context.Context, userID, spaceID string) error { + if userID == "" { + return nil + } + // create user index dir + if err := os.MkdirAll(filepath.Join(fs.o.Root, "indexes", "by-user-id", userID), 0700); err != nil { + return err + } + + err := os.Symlink("../../../spaces/"+lookup.Pathify(spaceID, 1, 2)+"/nodes/"+lookup.Pathify(spaceID, 4, 2), filepath.Join(fs.o.Root, "indexes/by-user-id", userID, spaceID)) + if err != nil { + if isAlreadyExists(err) { + appctx.GetLogger(ctx).Debug().Err(err).Str("space", spaceID).Str("indexes/by-user-id", userID).Msg("symlink already exists") + // FIXME: is it ok to wipe this err if the symlink already exists? + err = nil + } else { + // TODO how should we handle error cases here? + appctx.GetLogger(ctx).Error().Err(err).Str("space", spaceID).Str("indexes/by-user-id", userID).Msg("could not create symlink") + } + } + return nil +} + +// TODO: implement linkSpaceByGroup + func (fs *Decomposedfs) linkStorageSpaceType(ctx context.Context, spaceType string, spaceID string) error { + if spaceType == "" { + return nil + } // create space type dir if err := os.MkdirAll(filepath.Join(fs.o.Root, "spacetypes", spaceType), 0700); err != nil { return err