diff --git a/src/internal/connector/exchange/service_iterators.go b/src/internal/connector/exchange/service_iterators.go index 144d768c6..1ee7654c5 100644 --- a/src/internal/connector/exchange/service_iterators.go +++ b/src/internal/connector/exchange/service_iterators.go @@ -157,28 +157,7 @@ func FilterContainersAndFillCollections( collections[metadataKey] = col } - // TODO(ashmrtn): getFetchIDFunc functions should probably just return a - // multierror and all of the error handling should just use those so that it - // all ends up more consistent. - merrs := multierror.Append(nil, errs) - - col, err = makeMetadataCollection( - qp.Credentials.AzureTenantID, - qp.ResourceOwner, - qp.Category, - deltaTokens, - statusUpdater, - ) - if err != nil { - merrs = multierror.Append( - merrs, - errors.Wrap(err, "making metadata collection"), - ) - } else if col != nil { - collections[metadataKey] = col - } - - return merrs.ErrorOrNil() + return errs } func IterativeCollectContactContainers( diff --git a/src/pkg/selectors/exchange.go b/src/pkg/selectors/exchange.go index b8412a95f..a3e6f11c0 100644 --- a/src/pkg/selectors/exchange.go +++ b/src/pkg/selectors/exchange.go @@ -40,6 +40,7 @@ var ( _ Reducer = &ExchangeRestore{} _ printabler = &ExchangeRestore{} _ resourceOwnerer = &ExchangeRestore{} + _ pathCategorier = &ExchangeRestore{} ) // NewExchange produces a new Selector with the service set to ServiceExchange. @@ -103,6 +104,15 @@ func (s exchange) ResourceOwners() selectorResourceOwners { } } +// PathCategories produces the aggregation of discrete users described by each type of scope. +func (s exchange) PathCategories() selectorPathCategories { + return selectorPathCategories{ + Excludes: pathCategoriesIn[ExchangeScope, exchangeCategory](s.Excludes), + Filters: pathCategoriesIn[ExchangeScope, exchangeCategory](s.Filters), + Includes: pathCategoriesIn[ExchangeScope, exchangeCategory](s.Includes), + } +} + // ------------------- // Exclude/Includes @@ -210,7 +220,7 @@ func (s *exchange) Contacts(users, folders, contacts []string, opts ...option) [ func (s *exchange) ContactFolders(users, folders []string, opts ...option) []ExchangeScope { var ( scopes = []ExchangeScope{} - os = append([]option{pathType()}, opts...) + os = append([]option{pathComparator()}, opts...) ) scopes = append( @@ -247,7 +257,7 @@ func (s *exchange) Events(users, calendars, events []string, opts ...option) []E func (s *exchange) EventCalendars(users, events []string, opts ...option) []ExchangeScope { var ( scopes = []ExchangeScope{} - os = append([]option{pathType()}, opts...) + os = append([]option{pathComparator()}, opts...) ) scopes = append( @@ -283,7 +293,7 @@ func (s *exchange) Mails(users, folders, mails []string, opts ...option) []Excha func (s *exchange) MailFolders(users, folders []string, opts ...option) []ExchangeScope { var ( scopes = []ExchangeScope{} - os = append([]option{pathType()}, opts...) + os = append([]option{pathComparator()}, opts...) ) scopes = append( @@ -663,7 +673,7 @@ func (s ExchangeScope) Get(cat exchangeCategory) []string { func (s ExchangeScope) set(cat exchangeCategory, v []string, opts ...option) ExchangeScope { os := []option{} if cat == ExchangeContactFolder || cat == ExchangeEventCalendar || cat == ExchangeMailFolder { - os = append(os, pathType()) + os = append(os, pathComparator()) } return set(s, cat, v, append(os, opts...)...) diff --git a/src/pkg/selectors/onedrive.go b/src/pkg/selectors/onedrive.go index 5642b131d..3fc07c20a 100644 --- a/src/pkg/selectors/onedrive.go +++ b/src/pkg/selectors/onedrive.go @@ -39,6 +39,7 @@ var ( _ Reducer = &OneDriveRestore{} _ printabler = &OneDriveRestore{} _ resourceOwnerer = &OneDriveRestore{} + _ pathCategorier = &OneDriveRestore{} ) // NewOneDriveBackup produces a new Selector with the service set to ServiceOneDrive. @@ -102,6 +103,15 @@ func (s oneDrive) ResourceOwners() selectorResourceOwners { } } +// PathCategories produces the aggregation of discrete users described by each type of scope. +func (s oneDrive) PathCategories() selectorPathCategories { + return selectorPathCategories{ + Excludes: pathCategoriesIn[OneDriveScope, oneDriveCategory](s.Excludes), + Filters: pathCategoriesIn[OneDriveScope, oneDriveCategory](s.Filters), + Includes: pathCategoriesIn[OneDriveScope, oneDriveCategory](s.Includes), + } +} + // ------------------- // Scope Factories @@ -197,7 +207,7 @@ func (s *oneDrive) Users(users []string) []OneDriveScope { func (s *oneDrive) Folders(users, folders []string, opts ...option) []OneDriveScope { var ( scopes = []OneDriveScope{} - os = append([]option{pathType()}, opts...) + os = append([]option{pathComparator()}, opts...) ) scopes = append( @@ -447,7 +457,7 @@ func (s OneDriveScope) Get(cat oneDriveCategory) []string { func (s OneDriveScope) set(cat oneDriveCategory, v []string, opts ...option) OneDriveScope { os := []option{} if cat == OneDriveFolder { - os = append(os, pathType()) + os = append(os, pathComparator()) } return set(s, cat, v, append(os, opts...)...) diff --git a/src/pkg/selectors/selectors.go b/src/pkg/selectors/selectors.go index 00640cf19..e25f66350 100644 --- a/src/pkg/selectors/selectors.go +++ b/src/pkg/selectors/selectors.go @@ -84,6 +84,19 @@ type resourceOwnerer interface { ResourceOwners() selectorResourceOwners } +// selectorResourceOwners aggregates all discrete path category types described +// in the selector. Category sets are grouped by their scope type (includes, +// excludes, filters). +type selectorPathCategories struct { + Includes []path.CategoryType + Excludes []path.CategoryType + Filters []path.CategoryType +} + +type pathCategorier interface { + PathCategories() selectorPathCategories +} + // --------------------------------------------------------------------------- // Selector // --------------------------------------------------------------------------- @@ -205,6 +218,7 @@ func (s Selector) Reduce(ctx context.Context, deets *details.Details) (*details. return r.Reduce(ctx, deets), nil } +// returns the sets of resource owners identified in each scope set. func (s Selector) ResourceOwners() (selectorResourceOwners, error) { ro, err := selectorAsIface[resourceOwnerer](s) if err != nil { @@ -214,6 +228,16 @@ func (s Selector) ResourceOwners() (selectorResourceOwners, error) { return ro.ResourceOwners(), nil } +// returns the sets of path categories identified in each scope set. +func (s Selector) PathCategories() (selectorPathCategories, error) { + ro, err := selectorAsIface[pathCategorier](s) + if err != nil { + return selectorPathCategories{}, err + } + + return ro.PathCategories(), nil +} + // transformer for arbitrary selector interfaces func selectorAsIface[T any](s Selector) (T, error) { var ( @@ -388,6 +412,30 @@ func resourceOwnersIn(s []scope, rootCat string) []string { return rs } +// produces the discrete set of path categories in the slice of scopes. +func pathCategoriesIn[T scopeT, C categoryT](ss []scope) []path.CategoryType { + rm := map[path.CategoryType]struct{}{} + + for _, s := range ss { + t := T(s) + + lc := t.categorizer().leafCat() + if lc == lc.unknownCat() { + continue + } + + rm[lc.PathType()] = struct{}{} + } + + rs := []path.CategoryType{} + + for k := range rm { + rs = append(rs, k) + } + + return rs +} + // --------------------------------------------------------------------------- // scope helpers // --------------------------------------------------------------------------- @@ -424,10 +472,10 @@ func SuffixMatch() option { } } -// pathType is an internal-facing option. It is assumed that scope -// constructors will provide the pathType option whenever a folder- +// pathComparator is an internal-facing option. It is assumed that scope +// constructors will provide the pathComparator option whenever a folder- // level scope (ie, a scope that compares path hierarchies) is created. -func pathType() option { +func pathComparator() option { return func(sc *scopeConfig) { sc.usePathFilter = true } diff --git a/src/pkg/selectors/selectors_test.go b/src/pkg/selectors/selectors_test.go index 9668e4fb9..b3549c660 100644 --- a/src/pkg/selectors/selectors_test.go +++ b/src/pkg/selectors/selectors_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/alcionai/corso/src/pkg/filters" + "github.com/alcionai/corso/src/pkg/path" ) type SelectorSuite struct { @@ -208,6 +209,39 @@ func (suite *SelectorSuite) TestResourceOwnersIn() { } } +func (suite *SelectorSuite) TestPathCategoriesIn() { + leafCat := leafCatStub.String() + f := filters.Identity(leafCat) + + table := []struct { + name string + input []scope + expect []path.CategoryType + }{ + { + name: "nil", + input: nil, + expect: []path.CategoryType{}, + }, + { + name: "empty", + input: []scope{}, + expect: []path.CategoryType{}, + }, + { + name: "single", + input: []scope{{leafCat: f, scopeKeyCategory: f}}, + expect: []path.CategoryType{leafCatStub.PathType()}, + }, + } + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + result := pathCategoriesIn[mockScope, mockCategorizer](test.input) + assert.ElementsMatch(t, test.expect, result) + }) + } +} + func (suite *SelectorSuite) TestContains() { t := suite.T() key := rootCatStub diff --git a/src/pkg/selectors/sharepoint.go b/src/pkg/selectors/sharepoint.go index 8bd5ec955..579242fa8 100644 --- a/src/pkg/selectors/sharepoint.go +++ b/src/pkg/selectors/sharepoint.go @@ -37,6 +37,7 @@ var ( _ Reducer = &SharePointRestore{} _ printabler = &SharePointRestore{} _ resourceOwnerer = &SharePointRestore{} + _ pathCategorier = &SharePointRestore{} ) // NewSharePointBackup produces a new Selector with the service set to ServiceSharePoint. @@ -100,6 +101,15 @@ func (s sharePoint) ResourceOwners() selectorResourceOwners { } } +// PathCategories produces the aggregation of discrete users described by each type of scope. +func (s sharePoint) PathCategories() selectorPathCategories { + return selectorPathCategories{ + Excludes: pathCategoriesIn[SharePointScope, sharePointCategory](s.Excludes), + Filters: pathCategoriesIn[SharePointScope, sharePointCategory](s.Filters), + Includes: pathCategoriesIn[SharePointScope, sharePointCategory](s.Includes), + } +} + // ------------------- // Scope Factories @@ -210,7 +220,7 @@ func (s *sharePoint) Sites(sites []string) []SharePointScope { func (s *sharePoint) Libraries(sites, libraries []string, opts ...option) []SharePointScope { var ( scopes = []SharePointScope{} - os = append([]option{pathType()}, opts...) + os = append([]option{pathComparator()}, opts...) ) scopes = append( @@ -397,7 +407,7 @@ func (s SharePointScope) Get(cat sharePointCategory) []string { func (s SharePointScope) set(cat sharePointCategory, v []string, opts ...option) SharePointScope { os := []option{} if cat == SharePointLibrary { - os = append(os, pathType()) + os = append(os, pathComparator()) } return set(s, cat, v, append(os, opts...)...)