methodize all api funcs to the Client

In order to use the api layer as an interface, we
need the functions therein to be methods, so
that callers can leverage local interfaces.  This
change introduces the api.Client, and begins
to spread it throughout the exchange package,
largely in place of graph servicers.
This commit is contained in:
ryanfkeepers 2022-12-30 11:22:41 -07:00
parent 94134bf013
commit 5ebbdd1b4e
24 changed files with 387 additions and 227 deletions

View File

@ -77,12 +77,12 @@ func handleGetCommand(cmd *cobra.Command, args []string) error {
return nil
}
gc, err := getGC(ctx)
gc, creds, err := getGC(ctx)
if err != nil {
return err
}
err = runDisplayM365JSON(ctx, gc.Service)
err = runDisplayM365JSON(ctx, gc.Service, creds)
if err != nil {
return Only(ctx, errors.Wrapf(err, "unable to create mock from M365: %s", m365ID))
}
@ -93,6 +93,7 @@ func handleGetCommand(cmd *cobra.Command, args []string) error {
func runDisplayM365JSON(
ctx context.Context,
gs graph.Servicer,
creds account.M365Config,
) error {
var (
get api.GraphRetrievalFunc
@ -100,9 +101,11 @@ func runDisplayM365JSON(
cat = graph.StringToPathCategory(category)
)
ac := api.Client{Credentials: creds}
switch cat {
case path.EmailCategory, path.EventsCategory, path.ContactsCategory:
get, serializeFunc = exchange.GetQueryAndSerializeFunc(cat)
get, serializeFunc = exchange.GetQueryAndSerializeFunc(ac, cat)
default:
return fmt.Errorf("unable to process category: %s", cat)
}
@ -111,7 +114,7 @@ func runDisplayM365JSON(
sw := kw.NewJsonSerializationWriter()
response, err := get(ctx, gs, user, m365ID)
response, err := get(ctx, user, m365ID)
if err != nil {
return errors.Wrap(err, support.ConnectorStackErrorTrace(err))
}
@ -159,7 +162,7 @@ func runDisplayM365JSON(
// Helpers
//-------------------------------------------------------------------------------
func getGC(ctx context.Context) (*connector.GraphConnector, error) {
func getGC(ctx context.Context) (*connector.GraphConnector, account.M365Config, error) {
// get account info
m365Cfg := account.M365Config{
M365: credentials.GetM365(),
@ -168,13 +171,13 @@ func getGC(ctx context.Context) (*connector.GraphConnector, error) {
acct, err := account.NewAccount(account.ProviderM365, m365Cfg)
if err != nil {
return nil, Only(ctx, errors.Wrap(err, "finding m365 account details"))
return nil, m365Cfg, Only(ctx, errors.Wrap(err, "finding m365 account details"))
}
gc, err := connector.NewGraphConnector(ctx, acct, connector.Users)
if err != nil {
return nil, Only(ctx, errors.Wrap(err, "connecting to graph API"))
return nil, m365Cfg, Only(ctx, errors.Wrap(err, "connecting to graph API"))
}
return gc, nil
return gc, m365Cfg, nil
}

View File

@ -4,8 +4,10 @@ import (
"context"
"github.com/microsoft/kiota-abstractions-go/serialization"
"github.com/pkg/errors"
"github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/pkg/account"
)
// ---------------------------------------------------------------------------
@ -26,14 +28,13 @@ type DeltaUpdate struct {
// into M365 backstore. Responses -> returned items will only contain the information
// that is included in the options
// TODO: use selector or path for granularity into specific folders or specific date ranges
type GraphQuery func(ctx context.Context, gs graph.Servicer, userID string) (serialization.Parsable, error)
type GraphQuery func(ctx context.Context, userID string) (serialization.Parsable, error)
// GraphRetrievalFunctions are functions from the Microsoft Graph API that retrieve
// the default associated data of a M365 object. This varies by object. Additional
// Queries must be run to obtain the omitted fields.
type GraphRetrievalFunc func(
ctx context.Context,
gs graph.Servicer,
user, m365ID string,
) (serialization.Parsable, error)
@ -41,10 +42,25 @@ type GraphRetrievalFunc func(
// interfaces
// ---------------------------------------------------------------------------
// API is a struct used to fulfill the interface for exchange
// Client is used to fulfill the interface for exchange
// queries that are traditionally backed by GraphAPI. A
// struct is used in this case, instead of deferring to
// pure function wrappers, so that the boundary separates the
// granular implementation of the graphAPI and kiota away
// from the exchange package's broader intents.
// type API struct{}
type Client struct {
Credentials account.M365Config
}
func (c Client) service() (*graph.Service, error) {
adapter, err := graph.CreateAdapter(
c.Credentials.AzureTenantID,
c.Credentials.AzureClientID,
c.Credentials.AzureClientSecret,
)
if err != nil {
return nil, errors.Wrap(err, "generating graph api service client")
}
return graph.NewService(adapter), nil
}

View File

@ -164,6 +164,8 @@ func (suite *ExchangeServiceSuite) TestGraphQueryFunctions() {
ctx, flush := tester.NewContext()
defer flush()
c := Client{suite.credentials}
userID := tester.M365UserID(suite.T())
tests := []struct {
name string
@ -171,17 +173,17 @@ func (suite *ExchangeServiceSuite) TestGraphQueryFunctions() {
}{
{
name: "GraphQuery: Get All ContactFolders",
function: GetAllContactFolderNamesForUser,
function: c.GetAllContactFolderNamesForUser,
},
{
name: "GraphQuery: Get All Calendars for User",
function: GetAllCalendarNamesForUser,
function: c.GetAllCalendarNamesForUser,
},
}
for _, test := range tests {
suite.T().Run(test.name, func(t *testing.T) {
response, err := test.function(ctx, suite.gs, userID)
response, err := test.function(ctx, userID)
assert.NoError(t, err)
assert.NotNil(t, response)
})

View File

@ -15,55 +15,79 @@ import (
// CreateContactFolder makes a contact folder with the displayName of folderName.
// If successful, returns the created folder object.
func CreateContactFolder(
func (c Client) CreateContactFolder(
ctx context.Context,
gs graph.Servicer,
user, folderName string,
) (models.ContactFolderable, error) {
service, err := c.service()
if err != nil {
return nil, err
}
requestBody := models.NewContactFolder()
temp := folderName
requestBody.SetDisplayName(&temp)
return gs.Client().UsersById(user).ContactFolders().Post(ctx, requestBody, nil)
return service.Client().UsersById(user).ContactFolders().Post(ctx, requestBody, nil)
}
// DeleteContactFolder deletes the ContactFolder associated with the M365 ID if permissions are valid.
// Errors returned if the function call was not successful.
func DeleteContactFolder(ctx context.Context, gs graph.Servicer, user, folderID string) error {
return gs.Client().UsersById(user).ContactFoldersById(folderID).Delete(ctx, nil)
func (c Client) DeleteContactFolder(
ctx context.Context,
user, folderID string,
) error {
service, err := c.service()
if err != nil {
return err
}
return service.Client().UsersById(user).ContactFoldersById(folderID).Delete(ctx, nil)
}
// RetrieveContactDataForUser is a GraphRetrievalFun that returns all associated fields.
func RetrieveContactDataForUser(
func (c Client) RetrieveContactDataForUser(
ctx context.Context,
gs graph.Servicer,
user, m365ID string,
) (serialization.Parsable, error) {
return gs.Client().UsersById(user).ContactsById(m365ID).Get(ctx, nil)
service, err := c.service()
if err != nil {
return nil, err
}
return service.Client().UsersById(user).ContactsById(m365ID).Get(ctx, nil)
}
// GetAllContactFolderNamesForUser is a GraphQuery function for getting
// ContactFolderId and display names for contacts. All other information is omitted.
// Does not return the default Contact Folder
func GetAllContactFolderNamesForUser(
func (c Client) GetAllContactFolderNamesForUser(
ctx context.Context,
gs graph.Servicer,
user string,
) (serialization.Parsable, error) {
service, err := c.service()
if err != nil {
return nil, err
}
options, err := optionsForContactFolders([]string{"displayName", "parentFolderId"})
if err != nil {
return nil, err
}
return gs.Client().UsersById(user).ContactFolders().Get(ctx, options)
return service.Client().UsersById(user).ContactFolders().Get(ctx, options)
}
func GetContactFolderByID(
func (c Client) GetContactFolderByID(
ctx context.Context,
gs graph.Servicer,
userID, dirID string,
optionalFields ...string,
) (models.ContactFolderable, error) {
service, err := c.service()
if err != nil {
return nil, err
}
fields := append([]string{"displayName", "parentFolderId"}, optionalFields...)
ofcf, err := optionsForContactFolderByID(fields)
@ -71,7 +95,7 @@ func GetContactFolderByID(
return nil, errors.Wrapf(err, "options for contact folder: %v", fields)
}
return gs.Client().
return service.Client().
UsersById(userID).
ContactFoldersById(dirID).
Get(ctx, ofcf)
@ -79,38 +103,47 @@ func GetContactFolderByID(
// TODO: we want this to be the full handler, not only the builder.
// but this halfway point minimizes changes for now.
func GetContactChildFoldersBuilder(
func (c Client) GetContactChildFoldersBuilder(
ctx context.Context,
gs graph.Servicer,
userID, baseDirID string,
optionalFields ...string,
) (
*users.ItemContactFoldersItemChildFoldersRequestBuilder,
*users.ItemContactFoldersItemChildFoldersRequestBuilderGetRequestConfiguration,
*graph.Service,
error,
) {
service, err := c.service()
if err != nil {
return nil, nil, nil, err
}
fields := append([]string{"displayName", "parentFolderId"}, optionalFields...)
ofcf, err := optionsForContactChildFolders(fields)
if err != nil {
return nil, nil, errors.Wrapf(err, "options for contact child folders: %v", fields)
return nil, nil, nil, errors.Wrapf(err, "options for contact child folders: %v", fields)
}
builder := gs.Client().
builder := service.Client().
UsersById(userID).
ContactFoldersById(baseDirID).
ChildFolders()
return builder, ofcf, nil
return builder, ofcf, service, nil
}
// FetchContactIDsFromDirectory function that returns a list of all the m365IDs of the contacts
// of the targeted directory
func FetchContactIDsFromDirectory(
func (c Client) FetchContactIDsFromDirectory(
ctx context.Context,
gs graph.Servicer,
user, directoryID, oldDelta string,
) ([]string, []string, DeltaUpdate, error) {
service, err := c.service()
if err != nil {
return nil, nil, DeltaUpdate{}, err
}
var (
errs *multierror.Error
ids []string
@ -167,14 +200,14 @@ func FetchContactIDsFromDirectory(
break
}
builder = users.NewItemContactFoldersItemContactsDeltaRequestBuilder(*nextLink, gs.Adapter())
builder = users.NewItemContactFoldersItemContactsDeltaRequestBuilder(*nextLink, service.Adapter())
}
return nil
}
if len(oldDelta) > 0 {
err := getIDs(users.NewItemContactFoldersItemContactsDeltaRequestBuilder(oldDelta, gs.Adapter()))
err := getIDs(users.NewItemContactFoldersItemContactsDeltaRequestBuilder(oldDelta, service.Adapter()))
// note: happy path, not the error condition
if err == nil {
return ids, removedIDs, DeltaUpdate{deltaURL, false}, errs.ErrorOrNil()
@ -189,7 +222,7 @@ func FetchContactIDsFromDirectory(
errs = nil
}
builder := gs.Client().
builder := service.Client().
UsersById(user).
ContactFoldersById(directoryID).
Contacts().

View File

@ -15,68 +15,103 @@ import (
// CreateCalendar makes an event Calendar with the name in the user's M365 exchange account
// Reference: https://docs.microsoft.com/en-us/graph/api/user-post-calendars?view=graph-rest-1.0&tabs=go
func CreateCalendar(ctx context.Context, gs graph.Servicer, user, calendarName string) (models.Calendarable, error) {
func (c Client) CreateCalendar(
ctx context.Context,
user, calendarName string,
) (models.Calendarable, error) {
service, err := c.service()
if err != nil {
return nil, err
}
requestbody := models.NewCalendar()
requestbody.SetName(&calendarName)
return gs.Client().UsersById(user).Calendars().Post(ctx, requestbody, nil)
return service.Client().UsersById(user).Calendars().Post(ctx, requestbody, nil)
}
// DeleteCalendar removes calendar from user's M365 account
// Reference: https://docs.microsoft.com/en-us/graph/api/calendar-delete?view=graph-rest-1.0&tabs=go
func DeleteCalendar(ctx context.Context, gs graph.Servicer, user, calendarID string) error {
return gs.Client().UsersById(user).CalendarsById(calendarID).Delete(ctx, nil)
func (c Client) DeleteCalendar(
ctx context.Context,
user, calendarID string,
) error {
service, err := c.service()
if err != nil {
return err
}
return service.Client().UsersById(user).CalendarsById(calendarID).Delete(ctx, nil)
}
// RetrieveEventDataForUser is a GraphRetrievalFunc that returns event data.
// Calendarable and attachment fields are omitted due to size
func RetrieveEventDataForUser(
func (c Client) RetrieveEventDataForUser(
ctx context.Context,
gs graph.Servicer,
user, m365ID string,
) (serialization.Parsable, error) {
return gs.Client().UsersById(user).EventsById(m365ID).Get(ctx, nil)
service, err := c.service()
if err != nil {
return nil, err
}
return service.Client().UsersById(user).EventsById(m365ID).Get(ctx, nil)
}
func GetAllCalendarNamesForUser(ctx context.Context, gs graph.Servicer, user string) (serialization.Parsable, error) {
func (c Client) GetAllCalendarNamesForUser(
ctx context.Context,
user string,
) (serialization.Parsable, error) {
service, err := c.service()
if err != nil {
return nil, err
}
options, err := optionsForCalendars([]string{"name", "owner"})
if err != nil {
return nil, err
}
return gs.Client().UsersById(user).Calendars().Get(ctx, options)
return service.Client().UsersById(user).Calendars().Get(ctx, options)
}
// TODO: we want this to be the full handler, not only the builder.
// but this halfway point minimizes changes for now.
func GetCalendarsBuilder(
func (c Client) GetCalendarsBuilder(
ctx context.Context,
gs graph.Servicer,
userID string,
optionalFields ...string,
) (
*users.ItemCalendarsRequestBuilder,
*users.ItemCalendarsRequestBuilderGetRequestConfiguration,
*graph.Service,
error,
) {
ofcf, err := optionsForCalendars(optionalFields)
service, err := c.service()
if err != nil {
return nil, nil, errors.Wrapf(err, "options for event calendars: %v", optionalFields)
return nil, nil, nil, err
}
builder := gs.Client().
UsersById(userID).
Calendars()
ofcf, err := optionsForCalendars(optionalFields)
if err != nil {
return nil, nil, nil, errors.Wrapf(err, "options for event calendars: %v", optionalFields)
}
return builder, ofcf, nil
builder := service.Client().UsersById(userID).Calendars()
return builder, ofcf, service, nil
}
// FetchEventIDsFromCalendar returns a list of all M365IDs of events of the targeted Calendar.
func FetchEventIDsFromCalendar(
func (c Client) FetchEventIDsFromCalendar(
ctx context.Context,
gs graph.Servicer,
user, calendarID, oldDelta string,
) ([]string, []string, DeltaUpdate, error) {
service, err := c.service()
if err != nil {
return nil, nil, DeltaUpdate{}, err
}
var (
errs *multierror.Error
ids []string
@ -87,10 +122,7 @@ func FetchEventIDsFromCalendar(
return nil, nil, DeltaUpdate{}, err
}
builder := gs.Client().
UsersById(user).
CalendarsById(calendarID).
Events()
builder := service.Client().UsersById(user).CalendarsById(calendarID).Events()
for {
resp, err := builder.Get(ctx, options)
@ -121,7 +153,7 @@ func FetchEventIDsFromCalendar(
break
}
builder = users.NewItemCalendarsItemEventsRequestBuilder(*nextLink, gs.Adapter())
builder = users.NewItemCalendarsItemEventsRequestBuilder(*nextLink, service.Adapter())
}
// Events don't have a delta endpoint so just return an empty string.

View File

@ -15,26 +15,39 @@ import (
// CreateMailFolder makes a mail folder iff a folder of the same name does not exist
// Reference: https://docs.microsoft.com/en-us/graph/api/user-post-mailfolders?view=graph-rest-1.0&tabs=http
func CreateMailFolder(ctx context.Context, gs graph.Servicer, user, folder string) (models.MailFolderable, error) {
func (c Client) CreateMailFolder(
ctx context.Context,
user, folder string,
) (models.MailFolderable, error) {
service, err := c.service()
if err != nil {
return nil, err
}
isHidden := false
requestBody := models.NewMailFolder()
requestBody.SetDisplayName(&folder)
requestBody.SetIsHidden(&isHidden)
return gs.Client().UsersById(user).MailFolders().Post(ctx, requestBody, nil)
return service.Client().UsersById(user).MailFolders().Post(ctx, requestBody, nil)
}
func CreateMailFolderWithParent(
func (c Client) CreateMailFolderWithParent(
ctx context.Context,
gs graph.Servicer,
user, folder, parentID string,
) (models.MailFolderable, error) {
service, err := c.service()
if err != nil {
return nil, err
}
isHidden := false
requestBody := models.NewMailFolder()
requestBody.SetDisplayName(&folder)
requestBody.SetIsHidden(&isHidden)
return gs.Client().
return service.
Client().
UsersById(user).
MailFoldersById(parentID).
ChildFolders().
@ -43,18 +56,30 @@ func CreateMailFolderWithParent(
// DeleteMailFolder removes a mail folder with the corresponding M365 ID from the user's M365 Exchange account
// Reference: https://docs.microsoft.com/en-us/graph/api/mailfolder-delete?view=graph-rest-1.0&tabs=http
func DeleteMailFolder(ctx context.Context, gs graph.Servicer, user, folderID string) error {
return gs.Client().UsersById(user).MailFoldersById(folderID).Delete(ctx, nil)
func (c Client) DeleteMailFolder(
ctx context.Context,
user, folderID string,
) error {
service, err := c.service()
if err != nil {
return err
}
return service.Client().UsersById(user).MailFoldersById(folderID).Delete(ctx, nil)
}
// RetrieveMessageDataForUser is a GraphRetrievalFunc that returns message data.
// Attachment field is omitted due to size.
func RetrieveMessageDataForUser(
func (c Client) RetrieveMessageDataForUser(
ctx context.Context,
gs graph.Servicer,
user, m365ID string,
) (serialization.Parsable, error) {
return gs.Client().UsersById(user).MessagesById(m365ID).Get(ctx, nil)
service, err := c.service()
if err != nil {
return nil, err
}
return service.Client().UsersById(user).MessagesById(m365ID).Get(ctx, nil)
}
// GetMailFoldersBuilder retrieves all of the users current mail folders.
@ -62,41 +87,56 @@ func RetrieveMessageDataForUser(
// not contain historical data.
// TODO: we want this to be the full handler, not only the builder.
// but this halfway point minimizes changes for now.
func GetAllMailFoldersBuilder(
func (c Client) GetAllMailFoldersBuilder(
ctx context.Context,
gs graph.Servicer,
userID string,
) *users.ItemMailFoldersDeltaRequestBuilder {
return gs.Client().
) (
*users.ItemMailFoldersDeltaRequestBuilder,
*graph.Service,
error,
) {
service, err := c.service()
if err != nil {
return nil, nil, err
}
builder := service.Client().
UsersById(userID).
MailFolders().
Delta()
return builder, service, nil
}
func GetMailFolderByID(
func (c Client) GetMailFolderByID(
ctx context.Context,
gs graph.Servicer,
userID, dirID string,
optionalFields ...string,
) (models.MailFolderable, error) {
service, err := c.service()
if err != nil {
return nil, err
}
ofmf, err := optionsForMailFoldersItem(optionalFields)
if err != nil {
return nil, errors.Wrapf(err, "options for mail folder: %v", optionalFields)
}
return gs.Client().
UsersById(userID).
MailFoldersById(dirID).
Get(ctx, ofmf)
return service.Client().UsersById(userID).MailFoldersById(dirID).Get(ctx, ofmf)
}
// FetchMessageIDsFromDirectory function that returns a list of all the m365IDs of the exchange.Mail
// of the targeted directory
func FetchMessageIDsFromDirectory(
func (c Client) FetchMessageIDsFromDirectory(
ctx context.Context,
gs graph.Servicer,
user, directoryID, oldDelta string,
) ([]string, []string, DeltaUpdate, error) {
service, err := c.service()
if err != nil {
return nil, nil, DeltaUpdate{}, err
}
var (
errs *multierror.Error
ids []string
@ -153,14 +193,14 @@ func FetchMessageIDsFromDirectory(
break
}
builder = users.NewItemMailFoldersItemMessagesDeltaRequestBuilder(*nextLink, gs.Adapter())
builder = users.NewItemMailFoldersItemMessagesDeltaRequestBuilder(*nextLink, service.Adapter())
}
return nil
}
if len(oldDelta) > 0 {
err := getIDs(users.NewItemMailFoldersItemMessagesDeltaRequestBuilder(oldDelta, gs.Adapter()))
err := getIDs(users.NewItemMailFoldersItemMessagesDeltaRequestBuilder(oldDelta, service.Adapter()))
// note: happy path, not the error condition
if err == nil {
return ids, removedIDs, DeltaUpdate{deltaURL, false}, errs.ErrorOrNil()
@ -175,11 +215,7 @@ func FetchMessageIDsFromDirectory(
errs = nil
}
builder := gs.Client().
UsersById(user).
MailFoldersById(directoryID).
Messages().
Delta()
builder := service.Client().UsersById(user).MailFoldersById(directoryID).Messages().Delta()
if err := getIDs(builder); err != nil {
return nil, nil, DeltaUpdate{}, err

View File

@ -16,7 +16,8 @@ var _ graph.ContainerResolver = &contactFolderCache{}
type contactFolderCache struct {
*containerResolver
gs graph.Servicer
ac api.Client
// gs graph.Servicer
userID string
}
@ -25,7 +26,7 @@ func (cfc *contactFolderCache) populateContactRoot(
directoryID string,
baseContainerPath []string,
) error {
f, err := api.GetContactFolderByID(ctx, cfc.gs, cfc.userID, directoryID)
f, err := cfc.ac.GetContactFolderByID(ctx, cfc.userID, directoryID)
if err != nil {
return errors.Wrapf(
err,
@ -56,9 +57,8 @@ func (cfc *contactFolderCache) Populate(
var errs error
builder, options, err := api.GetContactChildFoldersBuilder(
builder, options, servicer, err := cfc.ac.GetContactChildFoldersBuilder(
ctx,
cfc.gs,
cfc.userID,
baseID)
if err != nil {
@ -97,7 +97,7 @@ func (cfc *contactFolderCache) Populate(
break
}
builder = msuser.NewItemContactFoldersItemChildFoldersRequestBuilder(*resp.GetOdataNextLink(), cfc.gs.Adapter())
builder = msuser.NewItemContactFoldersItemChildFoldersRequestBuilder(*resp.GetOdataNextLink(), servicer.Adapter())
}
if err := cfc.populatePaths(ctx); err != nil {

View File

@ -494,9 +494,6 @@ func (suite *FolderCacheIntegrationSuite) TestCreateContainerDestination() {
m365, err := a.M365Config()
require.NoError(suite.T(), err)
connector, err := createService(m365)
require.NoError(suite.T(), err)
var (
user = tester.M365UserID(suite.T())
directoryCaches = make(map[path.CategoryType]graph.ContainerResolver)
@ -596,11 +593,10 @@ func (suite *FolderCacheIntegrationSuite) TestCreateContainerDestination() {
suite.T().Run(test.name, func(t *testing.T) {
folderID, err := CreateContainerDestinaion(
ctx,
connector,
m365,
test.pathFunc1(t),
folderName,
directoryCaches,
)
directoryCaches)
require.NoError(t, err)
resolver := directoryCaches[test.category]
@ -609,11 +605,10 @@ func (suite *FolderCacheIntegrationSuite) TestCreateContainerDestination() {
secondID, err := CreateContainerDestinaion(
ctx,
connector,
m365,
test.pathFunc2(t),
folderName,
directoryCaches,
)
directoryCaches)
require.NoError(t, err)
_, err = resolver.IDToPath(ctx, secondID)

View File

@ -16,7 +16,8 @@ var _ graph.ContainerResolver = &eventCalendarCache{}
type eventCalendarCache struct {
*containerResolver
gs graph.Servicer
// gs graph.Servicer
ac api.Client
userID string
}
@ -32,7 +33,7 @@ func (ecc *eventCalendarCache) Populate(
ecc.containerResolver = newContainerResolver()
}
builder, options, err := api.GetCalendarsBuilder(ctx, ecc.gs, ecc.userID, "name")
builder, options, servicer, err := ecc.ac.GetCalendarsBuilder(ctx, ecc.userID, "name")
if err != nil {
return err
}
@ -67,7 +68,7 @@ func (ecc *eventCalendarCache) Populate(
break
}
builder = msuser.NewItemCalendarsRequestBuilder(*resp.GetOdataNextLink(), ecc.gs.Adapter())
builder = msuser.NewItemCalendarsRequestBuilder(*resp.GetOdataNextLink(), servicer.Adapter())
}
for _, container := range directories {

View File

@ -59,6 +59,7 @@ type Collection struct {
// service - client/adapter pair used to access M365 back store
service graph.Servicer
ac api.Client
category path.CategoryType
statusUpdater support.StatusUpdater
@ -88,12 +89,14 @@ func NewCollection(
user string,
curr, prev path.Path,
category path.CategoryType,
ac api.Client,
service graph.Servicer,
statusUpdater support.StatusUpdater,
ctrlOpts control.Options,
doNotMergeItems bool,
) Collection {
collection := Collection{
ac: ac,
category: category,
ctrl: ctrlOpts,
data: make(chan data.Stream, collectionChannelBufferSize),
@ -136,14 +139,14 @@ func (col *Collection) Items() <-chan data.Stream {
// GetQueryAndSerializeFunc helper function that returns the two functions functions
// required to convert M365 identifier into a byte array filled with the serialized data
func GetQueryAndSerializeFunc(category path.CategoryType) (api.GraphRetrievalFunc, GraphSerializeFunc) {
func GetQueryAndSerializeFunc(ac api.Client, category path.CategoryType) (api.GraphRetrievalFunc, GraphSerializeFunc) {
switch category {
case path.ContactsCategory:
return api.RetrieveContactDataForUser, serializeAndStreamContact
return ac.RetrieveContactDataForUser, serializeAndStreamContact
case path.EventsCategory:
return api.RetrieveEventDataForUser, serializeAndStreamEvent
return ac.RetrieveEventDataForUser, serializeAndStreamEvent
case path.EmailCategory:
return api.RetrieveMessageDataForUser, serializeAndStreamMessage
return ac.RetrieveMessageDataForUser, serializeAndStreamMessage
// Unsupported options returns nil, nil
default:
return nil, nil
@ -204,7 +207,7 @@ func (col *Collection) streamItems(ctx context.Context) {
// get QueryBasedonIdentifier
// verify that it is the correct type in called function
// serializationFunction
query, serializeFunc := GetQueryAndSerializeFunc(col.category)
query, serializeFunc := GetQueryAndSerializeFunc(col.ac, col.category)
if query == nil {
errs = fmt.Errorf("unrecognized collection type: %s", col.category)
return
@ -263,7 +266,7 @@ func (col *Collection) streamItems(ctx context.Context) {
)
for i := 1; i <= numberOfRetries; i++ {
response, err = query(ctx, col.service, user, id)
response, err = query(ctx, user, id)
if err == nil {
break
}

View File

@ -8,6 +8,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/connector/exchange/api"
"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/path"
@ -136,7 +137,7 @@ func (suite *ExchangeDataCollectionSuite) TestNewCollection_state() {
c := NewCollection(
"u",
test.curr, test.prev,
0, nil, nil, control.Options{},
0, api.Client{}, nil, nil, control.Options{},
false)
assert.Equal(t, test.expect, c.State())
})

View File

@ -7,13 +7,15 @@ import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/connector/exchange/api"
"github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/account"
)
type CacheResolverSuite struct {
suite.Suite
gs graph.Servicer
credentials account.M365Config
}
func TestCacheResolverIntegrationSuite(t *testing.T) {
@ -35,10 +37,7 @@ func (suite *CacheResolverSuite) SetupSuite() {
m365, err := a.M365Config()
require.NoError(t, err)
service, err := createService(m365)
require.NoError(t, err)
suite.gs = service
suite.credentials = m365
}
func (suite *CacheResolverSuite) TestPopulate() {
@ -48,14 +47,14 @@ func (suite *CacheResolverSuite) TestPopulate() {
eventFunc := func(t *testing.T) graph.ContainerResolver {
return &eventCalendarCache{
userID: tester.M365UserID(t),
gs: suite.gs,
ac: api.Client{Credentials: suite.credentials},
}
}
contactFunc := func(t *testing.T) graph.ContainerResolver {
return &contactFolderCache{
userID: tester.M365UserID(t),
gs: suite.gs,
ac: api.Client{Credentials: suite.credentials},
}
}

View File

@ -15,6 +15,7 @@ import (
"github.com/alcionai/corso/src/internal/connector/mockconnector"
"github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/selectors"
)
@ -84,7 +85,7 @@ func (suite *ExchangeIteratorSuite) TestCollectionFunctions() {
tests := []struct {
name string
queryFunc api.GraphQuery
queryFunc func(account.M365Config) api.GraphQuery
scope selectors.ExchangeScope
iterativeFunction func(
container map[string]graph.Container,
@ -94,13 +95,17 @@ func (suite *ExchangeIteratorSuite) TestCollectionFunctions() {
}{
{
name: "Contacts Iterative Check",
queryFunc: api.GetAllContactFolderNamesForUser,
queryFunc: func(amc account.M365Config) api.GraphQuery {
return api.Client{Credentials: amc}.GetAllContactFolderNamesForUser
},
transformer: models.CreateContactFolderCollectionResponseFromDiscriminatorValue,
iterativeFunction: IterativeCollectContactContainers,
},
{
name: "Events Iterative Check",
queryFunc: api.GetAllCalendarNamesForUser,
queryFunc: func(amc account.M365Config) api.GraphQuery {
return api.Client{Credentials: amc}.GetAllCalendarNamesForUser
},
transformer: models.CreateCalendarCollectionResponseFromDiscriminatorValue,
iterativeFunction: IterativeCollectCalendarContainers,
},
@ -114,7 +119,7 @@ func (suite *ExchangeIteratorSuite) TestCollectionFunctions() {
service, err := createService(m365)
require.NoError(t, err)
response, err := test.queryFunc(ctx, service, userID)
response, err := test.queryFunc(m365)(ctx, userID)
require.NoError(t, err)
// Iterator Creation

View File

@ -20,7 +20,8 @@ var _ graph.ContainerResolver = &mailFolderCache{}
// nameLookup map: Key: DisplayName Value: ID
type mailFolderCache struct {
*containerResolver
gs graph.Servicer
// gs graph.Servicer
ac api.Client
userID string
}
@ -35,7 +36,7 @@ func (mc *mailFolderCache) populateMailRoot(
for _, fldr := range []string{rootFolderAlias, DefaultMailFolder} {
var directory string
f, err := api.GetMailFolderByID(ctx, mc.gs, mc.userID, fldr, "displayName", "parentFolderId")
f, err := mc.ac.GetMailFolderByID(ctx, mc.userID, fldr, "displayName", "parentFolderId")
if err != nil {
return errors.Wrap(err, "fetching root folder"+support.ConnectorStackErrorTrace(err))
}
@ -67,7 +68,10 @@ func (mc *mailFolderCache) Populate(
return err
}
query := api.GetAllMailFoldersBuilder(ctx, mc.gs, mc.userID)
query, servicer, err := mc.ac.GetAllMailFoldersBuilder(ctx, mc.userID)
if err != nil {
return err
}
var errs *multierror.Error
@ -94,7 +98,7 @@ func (mc *mailFolderCache) Populate(
break
}
query = msfolderdelta.NewItemMailFoldersDeltaRequestBuilder(*link, mc.gs.Adapter())
query = msfolderdelta.NewItemMailFoldersDeltaRequestBuilder(*link, servicer.Adapter())
}
if err := mc.populatePaths(ctx); err != nil {

View File

@ -8,8 +8,9 @@ import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/internal/connector/exchange/api"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/account"
)
const (
@ -26,7 +27,7 @@ const (
type MailFolderCacheIntegrationSuite struct {
suite.Suite
gs graph.Servicer
credentials account.M365Config
}
func TestMailFolderCacheIntegrationSuite(t *testing.T) {
@ -48,10 +49,7 @@ func (suite *MailFolderCacheIntegrationSuite) SetupSuite() {
m365, err := a.M365Config()
require.NoError(t, err)
service, err := createService(m365)
require.NoError(t, err)
suite.gs = service
suite.credentials = m365
}
func (suite *MailFolderCacheIntegrationSuite) TestDeltaFetch() {
@ -85,7 +83,7 @@ func (suite *MailFolderCacheIntegrationSuite) TestDeltaFetch() {
suite.T().Run(test.name, func(t *testing.T) {
mfc := mailFolderCache{
userID: userID,
gs: suite.gs,
ac: api.Client{Credentials: suite.credentials},
}
require.NoError(t, mfc.Populate(ctx, test.root, test.path...))

View File

@ -15,6 +15,7 @@ import (
"github.com/alcionai/corso/src/internal/connector/mockconnector"
"github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/path"
)
@ -22,6 +23,8 @@ import (
type ExchangeRestoreSuite struct {
suite.Suite
gs graph.Servicer
credentials account.M365Config
ac api.Client
}
func TestExchangeRestoreSuite(t *testing.T) {
@ -41,13 +44,16 @@ func (suite *ExchangeRestoreSuite) SetupSuite() {
m365, err := a.M365Config()
require.NoError(t, err)
adpt, err := graph.CreateAdapter(
m365.AzureTenantID,
m365.AzureClientID,
m365.AzureClientSecret)
require.NoError(t, err)
suite.credentials = m365
suite.ac = api.Client{Credentials: m365}
suite.gs = graph.NewService(adpt)
// adpt, err := graph.CreateAdapter(
// m365.AzureTenantID,
// m365.AzureClientID,
// m365.AzureClientSecret)
// require.NoError(t, err)
// suite.gs = graph.NewService(adpt)
require.NoError(suite.T(), err)
}
@ -65,14 +71,14 @@ func (suite *ExchangeRestoreSuite) TestRestoreContact() {
folderName = "TestRestoreContact: " + common.FormatSimpleDateTime(now)
)
aFolder, err := api.CreateContactFolder(ctx, suite.gs, userID, folderName)
aFolder, err := suite.ac.CreateContactFolder(ctx, userID, folderName)
require.NoError(t, err)
folderID := *aFolder.GetId()
defer func() {
// Remove the folder containing contact prior to exiting test
err = api.DeleteContactFolder(ctx, suite.gs, userID, folderID)
err = suite.ac.DeleteContactFolder(ctx, userID, folderID)
assert.NoError(t, err)
}()
@ -98,14 +104,14 @@ func (suite *ExchangeRestoreSuite) TestRestoreEvent() {
name = "TestRestoreEvent: " + common.FormatSimpleDateTime(time.Now())
)
calendar, err := api.CreateCalendar(ctx, suite.gs, userID, name)
calendar, err := suite.ac.CreateCalendar(ctx, userID, name)
require.NoError(t, err)
calendarID := *calendar.GetId()
defer func() {
// Removes calendar containing events created during the test
err = api.DeleteCalendar(ctx, suite.gs, userID, calendarID)
err = suite.ac.DeleteCalendar(ctx, userID, calendarID)
assert.NoError(t, err)
}()
@ -134,17 +140,17 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() {
name string
bytes []byte
category path.CategoryType
cleanupFunc func(context.Context, graph.Servicer, string, string) error
cleanupFunc func(context.Context, string, string) error
destination func(*testing.T, context.Context) string
}{
{
name: "Test Mail",
bytes: mockconnector.GetMockMessageBytes("Restore Exchange Object"),
category: path.EmailCategory,
cleanupFunc: api.DeleteMailFolder,
cleanupFunc: suite.ac.DeleteMailFolder,
destination: func(t *testing.T, ctx context.Context) string {
folderName := "TestRestoreMailObject: " + common.FormatSimpleDateTime(now)
folder, err := api.CreateMailFolder(ctx, suite.gs, userID, folderName)
folder, err := suite.ac.CreateMailFolder(ctx, userID, folderName)
require.NoError(t, err)
return *folder.GetId()
@ -154,10 +160,10 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() {
name: "Test Mail: One Direct Attachment",
bytes: mockconnector.GetMockMessageWithDirectAttachment("Restore 1 Attachment"),
category: path.EmailCategory,
cleanupFunc: api.DeleteMailFolder,
cleanupFunc: suite.ac.DeleteMailFolder,
destination: func(t *testing.T, ctx context.Context) string {
folderName := "TestRestoreMailwithAttachment: " + common.FormatSimpleDateTime(now)
folder, err := api.CreateMailFolder(ctx, suite.gs, userID, folderName)
folder, err := suite.ac.CreateMailFolder(ctx, userID, folderName)
require.NoError(t, err)
return *folder.GetId()
@ -167,10 +173,10 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() {
name: "Test Mail: One Large Attachment",
bytes: mockconnector.GetMockMessageWithLargeAttachment("Restore Large Attachment"),
category: path.EmailCategory,
cleanupFunc: api.DeleteMailFolder,
cleanupFunc: suite.ac.DeleteMailFolder,
destination: func(t *testing.T, ctx context.Context) string {
folderName := "TestRestoreMailwithLargeAttachment: " + common.FormatSimpleDateTime(now)
folder, err := api.CreateMailFolder(ctx, suite.gs, userID, folderName)
folder, err := suite.ac.CreateMailFolder(ctx, userID, folderName)
require.NoError(t, err)
return *folder.GetId()
@ -180,10 +186,10 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() {
name: "Test Mail: Two Attachments",
bytes: mockconnector.GetMockMessageWithTwoAttachments("Restore 2 Attachments"),
category: path.EmailCategory,
cleanupFunc: api.DeleteMailFolder,
cleanupFunc: suite.ac.DeleteMailFolder,
destination: func(t *testing.T, ctx context.Context) string {
folderName := "TestRestoreMailwithAttachments: " + common.FormatSimpleDateTime(now)
folder, err := api.CreateMailFolder(ctx, suite.gs, userID, folderName)
folder, err := suite.ac.CreateMailFolder(ctx, userID, folderName)
require.NoError(t, err)
return *folder.GetId()
@ -193,10 +199,10 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() {
name: "Test Mail: Reference(OneDrive) Attachment",
bytes: mockconnector.GetMessageWithOneDriveAttachment("Restore Reference(OneDrive) Attachment"),
category: path.EmailCategory,
cleanupFunc: api.DeleteMailFolder,
cleanupFunc: suite.ac.DeleteMailFolder,
destination: func(t *testing.T, ctx context.Context) string {
folderName := "TestRestoreMailwithReferenceAttachment: " + common.FormatSimpleDateTime(now)
folder, err := api.CreateMailFolder(ctx, suite.gs, userID, folderName)
folder, err := suite.ac.CreateMailFolder(ctx, userID, folderName)
require.NoError(t, err)
return *folder.GetId()
@ -207,10 +213,10 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() {
name: "Test Contact",
bytes: mockconnector.GetMockContactBytes("Test_Omega"),
category: path.ContactsCategory,
cleanupFunc: api.DeleteContactFolder,
cleanupFunc: suite.ac.DeleteContactFolder,
destination: func(t *testing.T, ctx context.Context) string {
folderName := "TestRestoreContactObject: " + common.FormatSimpleDateTime(now)
folder, err := api.CreateContactFolder(ctx, suite.gs, userID, folderName)
folder, err := suite.ac.CreateContactFolder(ctx, userID, folderName)
require.NoError(t, err)
return *folder.GetId()
@ -220,10 +226,10 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() {
name: "Test Events",
bytes: mockconnector.GetDefaultMockEventBytes("Restored Event Object"),
category: path.EventsCategory,
cleanupFunc: api.DeleteCalendar,
cleanupFunc: suite.ac.DeleteCalendar,
destination: func(t *testing.T, ctx context.Context) string {
calendarName := "TestRestoreEventObject: " + common.FormatSimpleDateTime(now)
calendar, err := api.CreateCalendar(ctx, suite.gs, userID, calendarName)
calendar, err := suite.ac.CreateCalendar(ctx, userID, calendarName)
require.NoError(t, err)
return *calendar.GetId()
@ -233,10 +239,10 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() {
name: "Test Event with Attachment",
bytes: mockconnector.GetMockEventWithAttachment("Restored Event Attachment"),
category: path.EventsCategory,
cleanupFunc: api.DeleteCalendar,
cleanupFunc: suite.ac.DeleteCalendar,
destination: func(t *testing.T, ctx context.Context) string {
calendarName := "TestRestoreEventObject_" + common.FormatSimpleDateTime(now)
calendar, err := api.CreateCalendar(ctx, suite.gs, userID, calendarName)
calendar, err := suite.ac.CreateCalendar(ctx, userID, calendarName)
require.NoError(t, err)
return *calendar.GetId()
@ -262,7 +268,7 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() {
assert.NoError(t, err, support.ConnectorStackErrorTrace(err))
assert.NotNil(t, info, "item info is populated")
cleanupError := test.cleanupFunc(ctx, service, userID, destination)
cleanupError := test.cleanupFunc(ctx, userID, destination)
assert.NoError(t, cleanupError)
})
}

View File

@ -6,6 +6,7 @@ import (
"github.com/pkg/errors"
"github.com/alcionai/corso/src/internal/connector/exchange/api"
"github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/path"
@ -38,32 +39,27 @@ func PopulateExchangeContainerResolver(
var (
res graph.ContainerResolver
cacheRoot string
service, err = createService(qp.Credentials)
)
if err != nil {
return nil, err
}
switch qp.Category {
case path.EmailCategory:
res = &mailFolderCache{
userID: qp.ResourceOwner,
gs: service,
ac: api.Client{Credentials: qp.Credentials},
}
cacheRoot = rootFolderAlias
case path.ContactsCategory:
res = &contactFolderCache{
userID: qp.ResourceOwner,
gs: service,
ac: api.Client{Credentials: qp.Credentials},
}
cacheRoot = DefaultContactFolder
case path.EventsCategory:
res = &eventCalendarCache{
userID: qp.ResourceOwner,
gs: service,
ac: api.Client{Credentials: qp.Credentials},
}
cacheRoot = DefaultCalendar

View File

@ -35,6 +35,7 @@ func filterContainersAndFillCollections(
) error {
var (
errs error
ac = api.Client{Credentials: qp.Credentials}
// folder ID -> delta url or folder path lookups
deltaURLs = map[string]string{}
currPaths = map[string]string{}
@ -43,7 +44,7 @@ func filterContainersAndFillCollections(
tombstones = makeTombstones(dps)
)
getJobs, err := getFetchIDFunc(qp.Category)
getJobs, err := getFetchIDFunc(ac, qp.Category)
if err != nil {
return support.WrapAndAppend(qp.ResourceOwner, err, errs)
}
@ -85,7 +86,7 @@ func filterContainersAndFillCollections(
}
}
added, removed, newDelta, err := getJobs(ctx, service, qp.ResourceOwner, cID, prevDelta)
added, removed, newDelta, err := getJobs(ctx, qp.ResourceOwner, cID, prevDelta)
if err != nil {
if graph.IsErrDeletedInFlight(err) == nil {
errs = support.WrapAndAppend(qp.ResourceOwner, err, errs)
@ -110,11 +111,11 @@ func filterContainersAndFillCollections(
currPath,
prevPath,
scope.Category().PathType(),
ac,
service,
statusUpdater,
ctrlOpts,
newDelta.Reset,
)
newDelta.Reset)
collections[cID] = &edc
edc.added = append(edc.added, added...)
@ -160,11 +161,11 @@ func filterContainersAndFillCollections(
nil, // marks the collection as deleted
prevPath,
scope.Category().PathType(),
ac,
service,
statusUpdater,
ctrlOpts,
false,
)
false)
collections[id] = &edc
}
@ -267,18 +268,17 @@ func IterativeCollectCalendarContainers(
// container supports fetching delta records.
type FetchIDFunc func(
ctx context.Context,
gs graph.Servicer,
user, containerID, oldDeltaToken string,
) ([]string, []string, api.DeltaUpdate, error)
func getFetchIDFunc(category path.CategoryType) (FetchIDFunc, error) {
func getFetchIDFunc(ac api.Client, category path.CategoryType) (FetchIDFunc, error) {
switch category {
case path.EmailCategory:
return api.FetchMessageIDsFromDirectory, nil
return ac.FetchMessageIDsFromDirectory, nil
case path.EventsCategory:
return api.FetchEventIDsFromCalendar, nil
return ac.FetchEventIDsFromCalendar, nil
case path.ContactsCategory:
return api.FetchContactIDsFromDirectory, nil
return ac.FetchContactIDsFromDirectory, nil
default:
return nil, fmt.Errorf("category %s not supported by getFetchIDFunc", category)
}

View File

@ -17,6 +17,7 @@ import (
"github.com/alcionai/corso/src/internal/data"
D "github.com/alcionai/corso/src/internal/diagnostics"
"github.com/alcionai/corso/src/internal/observe"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/logger"
@ -284,6 +285,7 @@ func SendMailToBackStore(
// @param dest: container destination to M365
func RestoreExchangeDataCollections(
ctx context.Context,
creds account.M365Config,
gs graph.Servicer,
dest control.RestoreDestination,
dcs []data.Collection,
@ -313,7 +315,7 @@ func RestoreExchangeDataCollections(
containerID, err := CreateContainerDestinaion(
ctx,
gs,
creds,
dc.FullPath(),
dest.ContainerName,
userCaches)
@ -431,12 +433,13 @@ func restoreCollection(
// @ returns the container ID of the new destination container.
func CreateContainerDestinaion(
ctx context.Context,
gs graph.Servicer,
creds account.M365Config,
directory path.Path,
destination string,
caches map[path.CategoryType]graph.ContainerResolver,
) (string, error) {
var (
ac = api.Client{Credentials: creds}
newCache = false
user = directory.ResourceOwner()
category = directory.Category()
@ -449,7 +452,7 @@ func CreateContainerDestinaion(
if directoryCache == nil {
mfc := &mailFolderCache{
userID: user,
gs: gs,
ac: ac,
}
caches[category] = mfc
@ -459,16 +462,17 @@ func CreateContainerDestinaion(
return establishMailRestoreLocation(
ctx,
ac,
newPathFolders,
directoryCache,
user,
gs,
newCache)
case path.ContactsCategory:
if directoryCache == nil {
cfc := &contactFolderCache{
userID: user,
gs: gs,
ac: ac,
}
caches[category] = cfc
newCache = true
@ -477,16 +481,17 @@ func CreateContainerDestinaion(
return establishContactsRestoreLocation(
ctx,
ac,
newPathFolders,
directoryCache,
user,
gs,
newCache)
case path.EventsCategory:
if directoryCache == nil {
ecc := &eventCalendarCache{
userID: user,
gs: gs,
ac: ac,
}
caches[category] = ecc
newCache = true
@ -495,10 +500,10 @@ func CreateContainerDestinaion(
return establishEventsRestoreLocation(
ctx,
ac,
newPathFolders,
directoryCache,
user,
gs,
newCache,
)
default:
@ -513,10 +518,10 @@ func CreateContainerDestinaion(
// @param isNewCache identifies if the cache is created and not populated
func establishMailRestoreLocation(
ctx context.Context,
ac api.Client,
folders []string,
mfc graph.ContainerResolver,
user string,
service graph.Servicer,
isNewCache bool,
) (string, error) {
// Process starts with the root folder in order to recreate
@ -533,12 +538,7 @@ func establishMailRestoreLocation(
continue
}
temp, err := api.CreateMailFolderWithParent(
ctx,
service,
user,
folder,
folderID)
temp, err := ac.CreateMailFolderWithParent(ctx, user, folder, folderID)
if err != nil {
// Should only error if cache malfunctions or incorrect parameters
return "", errors.Wrap(err, support.ConnectorStackErrorTrace(err))
@ -574,10 +574,10 @@ func establishMailRestoreLocation(
// @param isNewCache bool representation of whether Populate function needs to be run
func establishContactsRestoreLocation(
ctx context.Context,
ac api.Client,
folders []string,
cfc graph.ContainerResolver,
user string,
gs graph.Servicer,
isNewCache bool,
) (string, error) {
cached, ok := cfc.PathInCache(folders[0])
@ -585,7 +585,7 @@ func establishContactsRestoreLocation(
return cached, nil
}
temp, err := api.CreateContactFolder(ctx, gs, user, folders[0])
temp, err := ac.CreateContactFolder(ctx, user, folders[0])
if err != nil {
return "", errors.Wrap(err, support.ConnectorStackErrorTrace(err))
}
@ -607,10 +607,10 @@ func establishContactsRestoreLocation(
func establishEventsRestoreLocation(
ctx context.Context,
ac api.Client,
folders []string,
ecc graph.ContainerResolver, // eventCalendarCache
user string,
gs graph.Servicer,
isNewCache bool,
) (string, error) {
cached, ok := ecc.PathInCache(folders[0])
@ -618,7 +618,7 @@ func establishEventsRestoreLocation(
return cached, nil
}
temp, err := api.CreateCalendar(ctx, gs, user, folders[0])
temp, err := ac.CreateCalendar(ctx, user, folders[0])
if err != nil {
return "", errors.Wrap(err, support.ConnectorStackErrorTrace(err))
}

View File

@ -252,6 +252,7 @@ func (gc *GraphConnector) UnionSiteIDsAndWebURLs(ctx context.Context, ids, urls
// SideEffect: gc.status is updated at the completion of operation
func (gc *GraphConnector) RestoreDataCollections(
ctx context.Context,
acct account.Account,
selector selectors.Selector,
dest control.RestoreDestination,
dcs []data.Collection,
@ -265,9 +266,14 @@ func (gc *GraphConnector) RestoreDataCollections(
deets = &details.Builder{}
)
creds, err := acct.M365Config()
if err != nil {
return nil, errors.Wrap(err, "malformed azure credentials")
}
switch selector.Service {
case selectors.ServiceExchange:
status, err = exchange.RestoreExchangeDataCollections(ctx, gc.Service, dest, dcs, deets)
status, err = exchange.RestoreExchangeDataCollections(ctx, creds, gc.Service, dest, dcs, deets)
case selectors.ServiceOneDrive:
status, err = onedrive.RestoreCollections(ctx, gc.Service, dest, dcs, deets)
case selectors.ServiceSharePoint:

View File

@ -168,18 +168,20 @@ func (suite *DisconnectedGraphConnectorSuite) TestGraphConnector_ErrorChecking()
}
func (suite *DisconnectedGraphConnectorSuite) TestRestoreFailsBadService() {
t := suite.T()
ctx, flush := tester.NewContext()
defer flush()
gc := GraphConnector{wg: &sync.WaitGroup{}}
sel := selectors.Selector{
var (
t = suite.T()
acct = tester.NewM365Account(t)
dest = tester.DefaultTestRestoreDestination()
gc = GraphConnector{wg: &sync.WaitGroup{}}
sel = selectors.Selector{
Service: selectors.ServiceUnknown,
}
dest := tester.DefaultTestRestoreDestination()
)
deets, err := gc.RestoreDataCollections(ctx, sel, dest, nil)
deets, err := gc.RestoreDataCollections(ctx, acct, sel, dest, nil)
assert.Error(t, err)
assert.NotNil(t, deets)

View File

@ -17,6 +17,7 @@ import (
"github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/control"
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/selectors"
@ -135,6 +136,8 @@ type GraphConnectorIntegrationSuite struct {
suite.Suite
connector *GraphConnector
user string
acct account.Account
credentials account.M365Config
}
func TestGraphConnectorIntegrationSuite(t *testing.T) {
@ -155,6 +158,7 @@ func (suite *GraphConnectorIntegrationSuite) SetupSuite() {
suite.connector = loadConnector(ctx, suite.T(), Users)
suite.user = tester.M365UserID(suite.T())
suite.acct = tester.NewM365Account(suite.T())
tester.LogTimeOfTest(suite.T())
}
@ -265,7 +269,12 @@ func (suite *GraphConnectorIntegrationSuite) TestEmptyCollections() {
ctx, flush := tester.NewContext()
defer flush()
deets, err := suite.connector.RestoreDataCollections(ctx, test.sel, dest, test.col)
deets, err := suite.connector.RestoreDataCollections(
ctx,
suite.acct,
test.sel,
dest,
test.col)
require.NoError(t, err)
assert.NotNil(t, deets)
@ -308,6 +317,7 @@ func mustGetDefaultDriveID(
func runRestoreBackupTest(
t *testing.T,
acct account.Account,
test restoreBackupInfo,
tenant string,
users []string,
@ -349,7 +359,12 @@ func runRestoreBackupTest(
restoreGC := loadConnector(ctx, t, test.resource)
restoreSel := getSelectorWith(test.service)
deets, err := restoreGC.RestoreDataCollections(ctx, restoreSel, dest, collections)
deets, err := restoreGC.RestoreDataCollections(
ctx,
acct,
restoreSel,
dest,
collections)
require.NoError(t, err)
assert.NotNil(t, deets)
@ -724,7 +739,7 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() {
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
runRestoreBackupTest(t, test, suite.connector.tenant, []string{suite.user})
runRestoreBackupTest(t, suite.acct, test, suite.connector.tenant, []string{suite.user})
})
}
}
@ -833,7 +848,7 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames
)
restoreGC := loadConnector(ctx, t, test.resource)
deets, err := restoreGC.RestoreDataCollections(ctx, restoreSel, dest, collections)
deets, err := restoreGC.RestoreDataCollections(ctx, suite.acct, restoreSel, dest, collections)
require.NoError(t, err)
require.NotNil(t, deets)
@ -977,7 +992,7 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiuserRestoreAndBackup() {
for _, test := range table {
suite.T().Run(test.name, func(t *testing.T) {
runRestoreBackupTest(t, test, suite.connector.tenant, users)
runRestoreBackupTest(t, suite.acct, test, suite.connector.tenant, users)
})
}
}

View File

@ -294,6 +294,7 @@ func generateContainerOfItems(
ctx context.Context,
gc *connector.GraphConnector,
service path.ServiceType,
acct account.Account,
cat path.CategoryType,
sel selectors.Selector,
tenantID, userID, destFldr string,
@ -330,7 +331,7 @@ func generateContainerOfItems(
dest,
collections)
deets, err := gc.RestoreDataCollections(ctx, sel, dest, dataColls)
deets, err := gc.RestoreDataCollections(ctx, acct, sel, dest, dataColls)
require.NoError(t, err)
return deets
@ -709,6 +710,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_exchangeIncrementals() {
ctx,
gc,
path.ExchangeService,
acct,
category,
selectors.NewExchangeRestore(users).Selector,
m365.AzureTenantID, suite.user, destName,

View File

@ -188,7 +188,12 @@ func (op *RestoreOperation) Run(ctx context.Context) (restoreDetails *details.De
defer closer()
defer close(restoreComplete)
restoreDetails, err = gc.RestoreDataCollections(ctx, op.Selectors, op.Destination, dcs)
restoreDetails, err = gc.RestoreDataCollections(
ctx,
op.account,
op.Selectors,
op.Destination,
dcs)
if err != nil {
err = errors.Wrap(err, "restoring service data")
opStats.writeErr = err