From 79b4014aa7c3a6c2b788d39e96374e21c3053332 Mon Sep 17 00:00:00 2001 From: David Christofas Date: Tue, 11 Oct 2022 10:05:18 +0200 Subject: [PATCH] implement share filters for space id and state (#3312) --- changelog/unreleased/share-filters.md | 6 ++ go.mod | 2 +- go.sum | 2 + .../grpc/services/gateway/storageprovider.go | 2 +- pkg/share/manager/jsoncs3/jsoncs3.go | 2 +- pkg/share/share.go | 55 ++++++++++++++----- pkg/share/share_test.go | 12 ++-- 7 files changed, 58 insertions(+), 23 deletions(-) create mode 100644 changelog/unreleased/share-filters.md diff --git a/changelog/unreleased/share-filters.md b/changelog/unreleased/share-filters.md new file mode 100644 index 0000000000..6201141c6b --- /dev/null +++ b/changelog/unreleased/share-filters.md @@ -0,0 +1,6 @@ +Enhancement: Implemented new share filters + +Added share filters for space ID and share state. + +https://github.com/cs3org/reva/pull/3312 +https://github.com/owncloud/ocis/issues/3843 diff --git a/go.mod b/go.mod index 8d284b33a6..164857411b 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/cheggaaa/pb v1.0.29 github.com/coreos/go-oidc v2.2.1+incompatible github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e - github.com/cs3org/go-cs3apis v0.0.0-20220929083235-bb0b1a236d6c + github.com/cs3org/go-cs3apis v0.0.0-20221005085457-19ea8088a512 github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 github.com/dgraph-io/ristretto v0.1.0 github.com/emvi/iso-639-1 v1.0.1 diff --git a/go.sum b/go.sum index 4473e1d566..8a147100e3 100644 --- a/go.sum +++ b/go.sum @@ -193,6 +193,8 @@ github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e h1:tqSPWQeueWTKnJVMJff github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4= github.com/cs3org/go-cs3apis v0.0.0-20220929083235-bb0b1a236d6c h1:b+YTmOGlf43mnF8MzO0fsy8/Ho8JLu44Iq5Y0fKLJMM= github.com/cs3org/go-cs3apis v0.0.0-20220929083235-bb0b1a236d6c/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= +github.com/cs3org/go-cs3apis v0.0.0-20221005085457-19ea8088a512 h1:xTvaIsLu1ezoWOJKnV0ehgiowkOiEhMaylaI1lD/Axw= +github.com/cs3org/go-cs3apis v0.0.0-20221005085457-19ea8088a512/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/internal/grpc/services/gateway/storageprovider.go b/internal/grpc/services/gateway/storageprovider.go index fbeb5dc8cf..43b3abbfd3 100644 --- a/internal/grpc/services/gateway/storageprovider.go +++ b/internal/grpc/services/gateway/storageprovider.go @@ -358,7 +358,7 @@ func (s *svc) DeleteStorageSpace(ctx context.Context, req *provider.DeleteStorag log.Debug().Msg("purging storage space") // List all shares in this storage space lsRes, err := s.ListShares(ctx, &collaborationv1beta1.ListSharesRequest{ - Filters: []*collaborationv1beta1.Filter{share.SpaceIDFilter(id.SpaceId)}, // FIXME rename the filter? @c0rby + Filters: []*collaborationv1beta1.Filter{share.SpaceIDFilter(id.SpaceId)}, }) switch { case err != nil: diff --git a/pkg/share/manager/jsoncs3/jsoncs3.go b/pkg/share/manager/jsoncs3/jsoncs3.go index b507d1b805..7de735da29 100644 --- a/pkg/share/manager/jsoncs3/jsoncs3.go +++ b/pkg/share/manager/jsoncs3/jsoncs3.go @@ -650,7 +650,7 @@ func (m *Manager) ListReceivedShares(ctx context.Context, filters []*collaborati } if share.IsGrantedToUser(s, user) { - if share.MatchesFilters(s, filters) { + if share.MatchesFiltersWithState(s, state.State, filters) { rs := &collaboration.ReceivedShare{ Share: s, State: state.State, diff --git a/pkg/share/share.go b/pkg/share/share.go index f0f69f7689..413a03e2d3 100644 --- a/pkg/share/share.go +++ b/pkg/share/share.go @@ -31,9 +31,8 @@ import ( ) const ( - // SpaceIDFilterType defines a new filter type for space id. - // TODO: Remove once this filter type is in the CS3 API. - SpaceIDFilterType collaboration.Filter_Type = 7 + // NoState can be used to signal the filter matching functions to ignore the share state. + NoState collaboration.ShareState = -1 ) //go:generate make --no-print-directory -C ../.. mockery NAME=Manager @@ -121,11 +120,19 @@ func ResourceIDFilter(id *provider.ResourceId) *collaboration.Filter { // SpaceIDFilter is an abstraction for creating filter by space id. func SpaceIDFilter(id string) *collaboration.Filter { return &collaboration.Filter{ - Type: SpaceIDFilterType, - Term: &collaboration.Filter_ResourceId{ - ResourceId: &provider.ResourceId{ - SpaceId: id, - }, + Type: collaboration.Filter_TYPE_SPACE_ID, + Term: &collaboration.Filter_SpaceId{ + SpaceId: id, + }, + } +} + +// StateFilter is an abstraction for creating filter by share state. +func StateFilter(state collaboration.ShareState) *collaboration.Filter { + return &collaboration.Filter{ + Type: collaboration.Filter_TYPE_STATE, + Term: &collaboration.Filter_State{ + State: state, }, } } @@ -152,7 +159,7 @@ func IsGrantedToUser(share *collaboration.Share, user *userv1beta1.User) bool { } // MatchesFilter tests if the share passes the filter. -func MatchesFilter(share *collaboration.Share, filter *collaboration.Filter) bool { +func MatchesFilter(share *collaboration.Share, state collaboration.ShareState, filter *collaboration.Filter) bool { switch filter.Type { case collaboration.Filter_TYPE_RESOURCE_ID: return utils.ResourceIDEqual(share.ResourceId, filter.GetResourceId()) @@ -162,17 +169,19 @@ func MatchesFilter(share *collaboration.Share, filter *collaboration.Filter) boo // This filter type is used to filter out "denial shares". These are currently implemented by having the permission "0". // I.e. if the permission is 0 we don't want to show it. return int(conversions.RoleFromResourcePermissions(share.Permissions.Permissions).OCSPermissions()) != 0 - case SpaceIDFilterType: - return share.ResourceId.SpaceId == filter.GetResourceId().GetSpaceId() + case collaboration.Filter_TYPE_SPACE_ID: + return share.ResourceId.SpaceId == filter.GetSpaceId() + case collaboration.Filter_TYPE_STATE: + return state == filter.GetState() default: return false } } // MatchesAnyFilter checks if the share passes at least one of the given filters. -func MatchesAnyFilter(share *collaboration.Share, filters []*collaboration.Filter) bool { +func MatchesAnyFilter(share *collaboration.Share, state collaboration.ShareState, filters []*collaboration.Filter) bool { for _, f := range filters { - if MatchesFilter(share, f) { + if MatchesFilter(share, state, f) { return true } } @@ -189,7 +198,25 @@ func MatchesFilters(share *collaboration.Share, filters []*collaboration.Filter) } grouped := GroupFiltersByType(filters) for _, f := range grouped { - if !MatchesAnyFilter(share, f) { + if !MatchesAnyFilter(share, NoState, f) { + return false + } + } + return true +} + +// MatchesFiltersWithState checks if the share passes the given filters. +// This can check filter by share state +// Filters of the same type form a disjuntion, a logical OR. Filters of separate type form a conjunction, a logical AND. +// Here is an example: +// (resource_id=1 OR resource_id=2) AND (grantee_type=USER OR grantee_type=GROUP) +func MatchesFiltersWithState(share *collaboration.Share, state collaboration.ShareState, filters []*collaboration.Filter) bool { + if len(filters) == 0 { + return true + } + grouped := GroupFiltersByType(filters) + for _, f := range grouped { + if !MatchesAnyFilter(share, state, f) { return false } } diff --git a/pkg/share/share_test.go b/pkg/share/share_test.go index ee6b0533f8..b2c45ca059 100644 --- a/pkg/share/share_test.go +++ b/pkg/share/share_test.go @@ -128,16 +128,16 @@ func TestMatchesFilter(t *testing.T) { Permissions: &collaboration.SharePermissions{Permissions: &provider.ResourcePermissions{}}, } - if !MatchesFilter(share, ResourceIDFilter(id)) { + if !MatchesFilter(share, NoState, ResourceIDFilter(id)) { t.Errorf("Expected share to pass the id filter. Share: %v", share) } - if MatchesFilter(share, GroupGranteeFilter()) { + if MatchesFilter(share, NoState, GroupGranteeFilter()) { t.Errorf("Expected share to not pass the grantee type filter. Share: %v", share) } - if MatchesFilter(share, &collaboration.Filter{Type: collaboration.Filter_TYPE_EXCLUDE_DENIALS}) { + if MatchesFilter(share, NoState, &collaboration.Filter{Type: collaboration.Filter_TYPE_EXCLUDE_DENIALS}) { t.Errorf("Expected share to not pass the exclude denials filter. Share: %v", share) } - if MatchesFilter(share, &collaboration.Filter{Type: collaboration.Filter_TYPE_INVALID}) { + if MatchesFilter(share, NoState, &collaboration.Filter{Type: collaboration.Filter_TYPE_INVALID}) { t.Errorf("Expected share to not pass an invalid filter. Share: %v", share) } } @@ -153,12 +153,12 @@ func TestMatchesAnyFilter(t *testing.T) { } f1 := []*collaboration.Filter{UserGranteeFilter(), GroupGranteeFilter()} - if !MatchesAnyFilter(share, f1) { + if !MatchesAnyFilter(share, NoState, f1) { t.Errorf("Expected share to match any of the given filters. Share: %v, Filters: %v", share, f1) } f2 := []*collaboration.Filter{ResourceIDFilter(&provider.ResourceId{StorageId: "something", OpaqueId: "different"}), GroupGranteeFilter()} - if MatchesAnyFilter(share, f2) { + if MatchesAnyFilter(share, NoState, f2) { t.Errorf("Expected share to not match any of the given filters. Share: %v, Filters: %v", share, f2) } }