extract scope from qp

Since scopes are service specific, we cannot
easily house them within the graph QueryParam
struct, unless we bloat the struct with all types.
Alternatively, we could add a generic "scope"
with parsers, much like the Selector itself.  But
really, the most simple solution is to only pass
the scope within the tree of service funcs that
use it.
This commit is contained in:
ryanfkeepers 2022-11-14 16:09:03 -07:00
parent ea65506406
commit 92e109d4eb
7 changed files with 88 additions and 175 deletions

View File

@ -240,12 +240,12 @@ func purgeMailFolders(
uid string, uid string,
) error { ) error {
getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) { getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) {
params, err := exchangeQueryParamFactory(uid, path.EmailCategory) params, scope, err := exchangeQueryParamFactory(uid, path.EmailCategory)
if err != nil { if err != nil {
return nil, err return nil, err
} }
allFolders, err := exchange.GetAllMailFolders(ctx, *params, gs) allFolders, err := exchange.GetAllMailFolders(ctx, *params, gs, scope)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -276,12 +276,12 @@ func purgeCalendarFolders(
uid string, uid string,
) error { ) error {
getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) { getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) {
params, err := exchangeQueryParamFactory(uid, path.EventsCategory) params, scope, err := exchangeQueryParamFactory(uid, path.EventsCategory)
if err != nil { if err != nil {
return nil, err return nil, err
} }
allCalendars, err := exchange.GetAllCalendars(ctx, *params, gs) allCalendars, err := exchange.GetAllCalendars(ctx, *params, gs, scope)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -312,12 +312,12 @@ func purgeContactFolders(
uid string, uid string,
) error { ) error {
getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) { getter := func(gs graph.Service, uid, prefix string) ([]purgable, error) {
params, err := exchangeQueryParamFactory(uid, path.ContactsCategory) params, scope, err := exchangeQueryParamFactory(uid, path.ContactsCategory)
if err != nil { if err != nil {
return nil, err return nil, err
} }
allContainers, err := exchange.GetAllContactFolders(ctx, *params, gs) allContainers, err := exchange.GetAllContactFolders(ctx, *params, gs, scope)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -518,7 +518,10 @@ func containerFilter(nameContains string, containers []graph.CachedContainer) []
return result return result
} }
func exchangeQueryParamFactory(user string, category path.CategoryType) (*graph.QueryParams, error) { func exchangeQueryParamFactory(
user string,
category path.CategoryType,
) (*graph.QueryParams, selectors.ExchangeScope, error) {
var scope selectors.ExchangeScope var scope selectors.ExchangeScope
switch category { switch category {
@ -529,18 +532,17 @@ func exchangeQueryParamFactory(user string, category path.CategoryType) (*graph.
case path.EventsCategory: case path.EventsCategory:
scope = selectors.NewExchangeBackup().EventCalendars([]string{user}, selectors.Any())[0] scope = selectors.NewExchangeBackup().EventCalendars([]string{user}, selectors.Any())[0]
default: default:
return nil, fmt.Errorf("category %s not supported", category) return nil, scope, fmt.Errorf("category %s not supported", category)
} }
params := &graph.QueryParams{ params := &graph.QueryParams{
User: user, ResourceOwner: user,
Scope: scope, FailFast: false,
FailFast: false,
Credentials: account.M365Config{ Credentials: account.M365Config{
M365: credentials.GetM365(), M365: credentials.GetM365(),
AzureTenantID: common.First(tenant, os.Getenv(account.AzureTenantID)), AzureTenantID: common.First(tenant, os.Getenv(account.AzureTenantID)),
}, },
} }
return params, nil return params, scope, nil
} }

View File

@ -114,23 +114,17 @@ func (gc *GraphConnector) createExchangeCollections(
collections := make(map[string]*exchange.Collection) collections := make(map[string]*exchange.Collection)
qp := graph.QueryParams{ qp := graph.QueryParams{
User: user, Category: scope.Category().PathType(),
Scope: scope, ResourceOwner: user,
FailFast: gc.failFast, FailFast: gc.failFast,
Credentials: gc.credentials, Credentials: gc.credentials,
} }
itemCategory := qp.Scope.Category().PathType() foldersComplete, closer := observe.MessageWithCompletion(fmt.Sprintf("∙ %s - %s:", qp.Category, user))
foldersComplete, closer := observe.MessageWithCompletion(fmt.Sprintf("∙ %s - %s:", itemCategory.String(), user))
defer closer() defer closer()
defer close(foldersComplete) defer close(foldersComplete)
resolver, err := exchange.PopulateExchangeContainerResolver( resolver, err := exchange.PopulateExchangeContainerResolver(ctx, qp)
ctx,
qp,
qp.Scope.Category().PathType(),
)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "getting folder cache") return nil, errors.Wrap(err, "getting folder cache")
} }
@ -140,7 +134,8 @@ func (gc *GraphConnector) createExchangeCollections(
qp, qp,
collections, collections,
gc.UpdateStatus, gc.UpdateStatus,
resolver) resolver,
scope)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "filling collections") return nil, errors.Wrap(err, "filling collections")
@ -264,26 +259,17 @@ func (gc *GraphConnector) createSharePointCollections(
collections := make(map[string]*sharepoint.Collection) collections := make(map[string]*sharepoint.Collection)
qp := graph.QueryParams{ qp := graph.QueryParams{
// TODO: Resource owner, not user/site. Category: scope.Category().PathType(),
User: site, ResourceOwner: site,
// TODO: generic scope handling in query params. FailFast: gc.failFast,
// - or, break scope out of QP. Credentials: gc.credentials,
// Scope: scope,
FailFast: gc.failFast,
Credentials: gc.credentials,
} }
itemCategory := qp.Scope.Category().PathType() foldersComplete, closer := observe.MessageWithCompletion(fmt.Sprintf("∙ %s - %s:", qp.Category, site))
foldersComplete, closer := observe.MessageWithCompletion(fmt.Sprintf("∙ %s - %s:", itemCategory.String(), site))
defer closer() defer closer()
defer close(foldersComplete) defer close(foldersComplete)
resolver, err := exchange.PopulateExchangeContainerResolver( resolver, err := exchange.PopulateExchangeContainerResolver(ctx, qp)
ctx,
qp,
qp.Scope.Category().PathType(),
)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "getting folder cache") return nil, errors.Wrap(err, "getting folder cache")
} }
@ -293,7 +279,8 @@ func (gc *GraphConnector) createSharePointCollections(
qp, qp,
collections, collections,
gc.UpdateStatus, gc.UpdateStatus,
resolver) resolver,
scope)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "filling collections") return nil, errors.Wrap(err, "filling collections")

View File

@ -137,10 +137,11 @@ func GetAllMailFolders(
ctx context.Context, ctx context.Context,
qp graph.QueryParams, qp graph.QueryParams,
gs graph.Service, gs graph.Service,
scope selectors.ExchangeScope,
) ([]graph.CachedContainer, error) { ) ([]graph.CachedContainer, error) {
containers := make([]graph.CachedContainer, 0) containers := make([]graph.CachedContainer, 0)
resolver, err := PopulateExchangeContainerResolver(ctx, qp, path.EmailCategory) resolver, err := PopulateExchangeContainerResolver(ctx, qp)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "building directory resolver in GetAllMailFolders") return nil, errors.Wrap(err, "building directory resolver in GetAllMailFolders")
} }
@ -151,7 +152,7 @@ func GetAllMailFolders(
continue continue
} }
if qp.Scope.Matches(selectors.ExchangeMailFolder, directory) { if scope.Matches(selectors.ExchangeMailFolder, directory) {
containers = append(containers, c) containers = append(containers, c)
} }
} }
@ -166,10 +167,11 @@ func GetAllCalendars(
ctx context.Context, ctx context.Context,
qp graph.QueryParams, qp graph.QueryParams,
gs graph.Service, gs graph.Service,
scope selectors.ExchangeScope,
) ([]graph.CachedContainer, error) { ) ([]graph.CachedContainer, error) {
containers := make([]graph.CachedContainer, 0) containers := make([]graph.CachedContainer, 0)
resolver, err := PopulateExchangeContainerResolver(ctx, qp, path.EventsCategory) resolver, err := PopulateExchangeContainerResolver(ctx, qp)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "building calendar resolver in GetAllCalendars") return nil, errors.Wrap(err, "building calendar resolver in GetAllCalendars")
} }
@ -177,7 +179,7 @@ func GetAllCalendars(
for _, c := range resolver.Items() { for _, c := range resolver.Items() {
directory := c.Path().String() directory := c.Path().String()
if qp.Scope.Matches(selectors.ExchangeEventCalendar, directory) { if scope.Matches(selectors.ExchangeEventCalendar, directory) {
containers = append(containers, c) containers = append(containers, c)
} }
} }
@ -193,12 +195,13 @@ func GetAllContactFolders(
ctx context.Context, ctx context.Context,
qp graph.QueryParams, qp graph.QueryParams,
gs graph.Service, gs graph.Service,
scope selectors.ExchangeScope,
) ([]graph.CachedContainer, error) { ) ([]graph.CachedContainer, error) {
var query string var query string
containers := make([]graph.CachedContainer, 0) containers := make([]graph.CachedContainer, 0)
resolver, err := PopulateExchangeContainerResolver(ctx, qp, path.ContactsCategory) resolver, err := PopulateExchangeContainerResolver(ctx, qp)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "building directory resolver in GetAllContactFolders") return nil, errors.Wrap(err, "building directory resolver in GetAllContactFolders")
} }
@ -212,7 +215,7 @@ func GetAllContactFolders(
query = directory query = directory
} }
if qp.Scope.Matches(selectors.ExchangeContactFolder, query) { if scope.Matches(selectors.ExchangeContactFolder, query) {
containers = append(containers, c) containers = append(containers, c)
} }
} }
@ -220,25 +223,6 @@ func GetAllContactFolders(
return containers, err return containers, err
} }
func GetContainers(
ctx context.Context,
qp graph.QueryParams,
gs graph.Service,
) ([]graph.CachedContainer, error) {
category := qp.Scope.Category().PathType()
switch category {
case path.ContactsCategory:
return GetAllContactFolders(ctx, qp, gs)
case path.EmailCategory:
return GetAllMailFolders(ctx, qp, gs)
case path.EventsCategory:
return GetAllCalendars(ctx, qp, gs)
default:
return nil, fmt.Errorf("path.Category %s not supported", category)
}
}
// PopulateExchangeContainerResolver gets a folder resolver if one is available for // PopulateExchangeContainerResolver gets a folder resolver if one is available for
// this category of data. If one is not available, returns nil so that other // this category of data. If one is not available, returns nil so that other
// logic in the caller can complete as long as they check if the resolver is not // logic in the caller can complete as long as they check if the resolver is not
@ -246,7 +230,6 @@ func GetContainers(
func PopulateExchangeContainerResolver( func PopulateExchangeContainerResolver(
ctx context.Context, ctx context.Context,
qp graph.QueryParams, qp graph.QueryParams,
category path.CategoryType,
) (graph.ContainerResolver, error) { ) (graph.ContainerResolver, error) {
var ( var (
res graph.ContainerResolver res graph.ContainerResolver
@ -258,30 +241,30 @@ func PopulateExchangeContainerResolver(
return nil, err return nil, err
} }
switch category { switch qp.Category {
case path.EmailCategory: case path.EmailCategory:
res = &mailFolderCache{ res = &mailFolderCache{
userID: qp.User, userID: qp.ResourceOwner,
gs: service, gs: service,
} }
cacheRoot = rootFolderAlias cacheRoot = rootFolderAlias
case path.ContactsCategory: case path.ContactsCategory:
res = &contactFolderCache{ res = &contactFolderCache{
userID: qp.User, userID: qp.ResourceOwner,
gs: service, gs: service,
} }
cacheRoot = DefaultContactFolder cacheRoot = DefaultContactFolder
case path.EventsCategory: case path.EventsCategory:
res = &eventCalendarCache{ res = &eventCalendarCache{
userID: qp.User, userID: qp.ResourceOwner,
gs: service, gs: service,
} }
cacheRoot = DefaultCalendar cacheRoot = DefaultCalendar
default: default:
return nil, fmt.Errorf("ContainerResolver not present for %s type", category) return nil, fmt.Errorf("ContainerResolver not present for %s type", qp.Category)
} }
if err := res.Populate(ctx, cacheRoot); err != nil { if err := res.Populate(ctx, cacheRoot); err != nil {
@ -291,8 +274,13 @@ func PopulateExchangeContainerResolver(
return res, nil return res, nil
} }
func pathAndMatch(qp graph.QueryParams, category path.CategoryType, c graph.CachedContainer) (path.Path, bool) { func pathAndMatch(
qp graph.QueryParams,
c graph.CachedContainer,
scope selectors.ExchangeScope,
) (path.Path, bool) {
var ( var (
category = scope.Category().PathType()
directory string directory string
pb = c.Path() pb = c.Path()
) )
@ -304,7 +292,7 @@ func pathAndMatch(qp graph.QueryParams, category path.CategoryType, c graph.Cach
dirPath, err := pb.ToDataLayerExchangePathForCategory( dirPath, err := pb.ToDataLayerExchangePathForCategory(
qp.Credentials.AzureTenantID, qp.Credentials.AzureTenantID,
qp.User, qp.ResourceOwner,
category, category,
false, false,
) )
@ -320,11 +308,11 @@ func pathAndMatch(qp graph.QueryParams, category path.CategoryType, c graph.Cach
switch category { switch category {
case path.EmailCategory: case path.EmailCategory:
return dirPath, qp.Scope.Matches(selectors.ExchangeMailFolder, directory) return dirPath, scope.Matches(selectors.ExchangeMailFolder, directory)
case path.ContactsCategory: case path.ContactsCategory:
return dirPath, qp.Scope.Matches(selectors.ExchangeContactFolder, directory) return dirPath, scope.Matches(selectors.ExchangeContactFolder, directory)
case path.EventsCategory: case path.EventsCategory:
return dirPath, qp.Scope.Matches(selectors.ExchangeEventCalendar, directory) return dirPath, scope.Matches(selectors.ExchangeEventCalendar, directory)
default: default:
return nil, false return nil, false
} }

View File

@ -115,13 +115,14 @@ func (suite *ServiceFunctionsIntegrationSuite) TestGetAllCalendars() {
} }
for _, test := range table { for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) { suite.T().Run(test.name, func(t *testing.T) {
scope := test.getScope(t)
params := graph.QueryParams{ params := graph.QueryParams{
User: test.user, Category: scope.Category().PathType(),
Scope: test.getScope(t), ResourceOwner: test.user,
FailFast: false, FailFast: false,
Credentials: suite.creds, Credentials: suite.creds,
} }
cals, err := GetAllCalendars(ctx, params, gs) cals, err := GetAllCalendars(ctx, params, gs, scope)
test.expectErr(t, err) test.expectErr(t, err)
test.expectCount(t, len(cals), 0) test.expectCount(t, len(cals), 0)
}) })
@ -199,13 +200,14 @@ func (suite *ServiceFunctionsIntegrationSuite) TestGetAllContactFolders() {
} }
for _, test := range table { for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) { suite.T().Run(test.name, func(t *testing.T) {
scope := test.getScope(t)
params := graph.QueryParams{ params := graph.QueryParams{
User: test.user, Category: scope.Category().PathType(),
Scope: test.getScope(t), ResourceOwner: test.user,
FailFast: false, FailFast: false,
Credentials: suite.creds, Credentials: suite.creds,
} }
cals, err := GetAllContactFolders(ctx, params, gs) cals, err := GetAllContactFolders(ctx, params, gs, scope)
test.expectErr(t, err) test.expectErr(t, err)
test.expectCount(t, len(cals), 0) test.expectCount(t, len(cals), 0)
}) })
@ -283,84 +285,16 @@ func (suite *ServiceFunctionsIntegrationSuite) TestGetAllMailFolders() {
} }
for _, test := range table { for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) { suite.T().Run(test.name, func(t *testing.T) {
scope := test.getScope(t)
params := graph.QueryParams{ params := graph.QueryParams{
User: test.user, Category: scope.Category().PathType(),
Scope: test.getScope(t), ResourceOwner: test.user,
FailFast: false, FailFast: false,
Credentials: suite.creds, Credentials: suite.creds,
} }
cals, err := GetAllMailFolders(ctx, params, gs) cals, err := GetAllMailFolders(ctx, params, gs, scope)
test.expectErr(t, err) test.expectErr(t, err)
test.expectCount(t, len(cals), 0) test.expectCount(t, len(cals), 0)
}) })
} }
} }
func (suite *ServiceFunctionsIntegrationSuite) TestCollectContainers() {
ctx, flush := tester.NewContext()
defer flush()
failFast := false
containerCount := 1
t := suite.T()
user := tester.M365UserID(t)
a := tester.NewM365Account(t)
service := loadService(t)
credentials, err := a.M365Config()
require.NoError(t, err)
tests := []struct {
name, contains string
getScope func() selectors.ExchangeScope
expectedCount assert.ComparisonAssertionFunc
}{
{
name: "All Events",
contains: "Birthdays",
expectedCount: assert.Greater,
getScope: func() selectors.ExchangeScope {
return selectors.
NewExchangeBackup().
EventCalendars([]string{user}, selectors.Any())[0]
},
}, {
name: "Default Calendar",
contains: DefaultCalendar,
expectedCount: assert.Equal,
getScope: func() selectors.ExchangeScope {
return selectors.
NewExchangeBackup().
EventCalendars([]string{user}, []string{DefaultCalendar}, selectors.PrefixMatch())[0]
},
}, {
name: "Default Mail",
contains: DefaultMailFolder,
expectedCount: assert.Equal,
getScope: func() selectors.ExchangeScope {
return selectors.
NewExchangeBackup().
MailFolders([]string{user}, []string{DefaultMailFolder}, selectors.PrefixMatch())[0]
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
qp := graph.QueryParams{
User: user,
Scope: test.getScope(),
FailFast: failFast,
Credentials: credentials,
}
collections, err := GetContainers(ctx, qp, service)
assert.NoError(t, err)
test.expectedCount(t, len(collections), containerCount)
keys := make([]string, 0, len(collections))
for _, k := range collections {
keys = append(keys, *k.GetDisplayName())
}
assert.Contains(t, keys, test.contains)
})
}
}

View File

@ -13,6 +13,7 @@ import (
"github.com/alcionai/corso/src/internal/connector/graph" "github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/internal/connector/support" "github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/selectors"
) )
// FilterContainersAndFillCollections is a utility function // FilterContainersAndFillCollections is a utility function
@ -26,21 +27,21 @@ func FilterContainersAndFillCollections(
collections map[string]*Collection, collections map[string]*Collection,
statusUpdater support.StatusUpdater, statusUpdater support.StatusUpdater,
resolver graph.ContainerResolver, resolver graph.ContainerResolver,
scope selectors.ExchangeScope,
) error { ) error {
var ( var (
category = qp.Scope.Category().PathType() collectionType = CategoryToOptionIdentifier(scope.Category().PathType())
collectionType = CategoryToOptionIdentifier(category)
errs error errs error
) )
for _, c := range resolver.Items() { for _, c := range resolver.Items() {
dirPath, ok := pathAndMatch(qp, category, c) dirPath, ok := pathAndMatch(qp, c, scope)
if ok { if ok {
// Create only those that match // Create only those that match
service, err := createService(qp.Credentials, qp.FailFast) service, err := createService(qp.Credentials, qp.FailFast)
if err != nil { if err != nil {
errs = support.WrapAndAppend( errs = support.WrapAndAppend(
qp.User+" FilterContainerAndFillCollection", qp.ResourceOwner+" FilterContainerAndFillCollection",
err, err,
errs) errs)
@ -50,7 +51,7 @@ func FilterContainersAndFillCollections(
} }
edc := NewCollection( edc := NewCollection(
qp.User, qp.ResourceOwner,
dirPath, dirPath,
collectionType, collectionType,
service, service,
@ -61,10 +62,10 @@ func FilterContainersAndFillCollections(
} }
for directoryID, col := range collections { for directoryID, col := range collections {
fetchFunc, err := getFetchIDFunc(category) fetchFunc, err := getFetchIDFunc(scope.Category().PathType())
if err != nil { if err != nil {
errs = support.WrapAndAppend( errs = support.WrapAndAppend(
qp.User, qp.ResourceOwner,
err, err,
errs) errs)
@ -75,10 +76,10 @@ func FilterContainersAndFillCollections(
continue continue
} }
jobs, err := fetchFunc(ctx, col.service, qp.User, directoryID) jobs, err := fetchFunc(ctx, col.service, qp.ResourceOwner, directoryID)
if err != nil { if err != nil {
errs = support.WrapAndAppend( errs = support.WrapAndAppend(
qp.User, qp.ResourceOwner,
err, err,
errs, errs,
) )

View File

@ -7,14 +7,13 @@ import (
"github.com/alcionai/corso/src/pkg/account" "github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/selectors"
) )
type QueryParams struct { type QueryParams struct {
User string Category path.CategoryType
Scope selectors.ExchangeScope ResourceOwner string
Credentials account.M365Config Credentials account.M365Config
FailFast bool FailFast bool
} }
type Service interface { type Service interface {

View File

@ -5,6 +5,7 @@ import (
"github.com/alcionai/corso/src/internal/connector/graph" "github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/internal/connector/support" "github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/pkg/selectors"
) )
// FilterContainersAndFillCollections is a utility function // FilterContainersAndFillCollections is a utility function
@ -17,6 +18,7 @@ func FilterContainersAndFillCollections(
collections map[string]*Collection, collections map[string]*Collection,
statusUpdater support.StatusUpdater, statusUpdater support.StatusUpdater,
resolver graph.ContainerResolver, resolver graph.ContainerResolver,
scope selectors.SharePointScope,
) error { ) error {
return nil return nil
} }