adds tenant site lookup on new graph conn (#1540)
## Description Adds a lookup for all tenant site ids when a new graph connector is created. Also adds an enum to flag which resource set (users, sites, or all) that the connector should initialize. ## Type of change - [x] 🌻 Feature ## Issue(s) * #1506 ## Test Plan - [x] 💚 E2E
This commit is contained in:
parent
9fe9cd1ce6
commit
07a8d13d1e
@ -176,7 +176,7 @@ func getGCAndVerifyUser(ctx context.Context, userID string) (*connector.GraphCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
// build a graph connector
|
// build a graph connector
|
||||||
gc, err := connector.NewGraphConnector(ctx, acct)
|
gc, err := connector.NewGraphConnector(ctx, acct, connector.Users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", errors.Wrap(err, "connecting to graph api")
|
return nil, "", errors.Wrap(err, "connecting to graph api")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,7 +44,8 @@ var (
|
|||||||
// Supports:
|
// Supports:
|
||||||
// - exchange (contacts, email, and events)
|
// - exchange (contacts, email, and events)
|
||||||
// Input: go run ./getItem.go --user <user>
|
// Input: go run ./getItem.go --user <user>
|
||||||
// --m365ID <m365ID> --category <oneof: contacts, email, events>
|
//
|
||||||
|
// --m365ID <m365ID> --category <oneof: contacts, email, events>
|
||||||
func main() {
|
func main() {
|
||||||
ctx, _ := logger.SeedLevel(context.Background(), logger.Development)
|
ctx, _ := logger.SeedLevel(context.Background(), logger.Development)
|
||||||
ctx = SetRootCmd(ctx, getCmd)
|
ctx = SetRootCmd(ctx, getCmd)
|
||||||
@ -170,7 +171,7 @@ func getGC(ctx context.Context) (*connector.GraphConnector, error) {
|
|||||||
return nil, Only(ctx, errors.Wrap(err, "finding m365 account details"))
|
return nil, Only(ctx, errors.Wrap(err, "finding m365 account details"))
|
||||||
}
|
}
|
||||||
|
|
||||||
gc, err := connector.NewGraphConnector(ctx, acct)
|
gc, err := connector.NewGraphConnector(ctx, acct, connector.Users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Only(ctx, errors.Wrap(err, "connecting to graph API"))
|
return nil, Only(ctx, errors.Wrap(err, "connecting to graph API"))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -255,7 +255,7 @@ func getGC(ctx context.Context) (*connector.GraphConnector, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// build a graph connector
|
// build a graph connector
|
||||||
gc, err := connector.NewGraphConnector(ctx, acct)
|
gc, err := connector.NewGraphConnector(ctx, acct, connector.Users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, Only(ctx, errors.Wrap(err, "connecting to graph api"))
|
return nil, Only(ctx, errors.Wrap(err, "connecting to graph api"))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,7 +42,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) SetupSuite() {
|
|||||||
|
|
||||||
_, err := tester.GetRequiredEnvVars(tester.M365AcctCredEnvs...)
|
_, err := tester.GetRequiredEnvVars(tester.M365AcctCredEnvs...)
|
||||||
require.NoError(suite.T(), err)
|
require.NoError(suite.T(), err)
|
||||||
suite.connector = loadConnector(ctx, suite.T())
|
suite.connector = loadConnector(ctx, suite.T(), AllResources)
|
||||||
suite.user = tester.M365UserID(suite.T())
|
suite.user = tester.M365UserID(suite.T())
|
||||||
suite.site = tester.M365SiteID(suite.T())
|
suite.site = tester.M365SiteID(suite.T())
|
||||||
tester.LogTimeOfTest(suite.T())
|
tester.LogTimeOfTest(suite.T())
|
||||||
@ -58,7 +58,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestExchangeDataCollection
|
|||||||
ctx, flush := tester.NewContext()
|
ctx, flush := tester.NewContext()
|
||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
connector := loadConnector(ctx, suite.T())
|
connector := loadConnector(ctx, suite.T(), Users)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
getSelector func(t *testing.T) selectors.Selector
|
getSelector func(t *testing.T) selectors.Selector
|
||||||
@ -123,7 +123,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestInvalidUserForDataColl
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
invalidUser := "foo@example.com"
|
invalidUser := "foo@example.com"
|
||||||
connector := loadConnector(ctx, suite.T())
|
connector := loadConnector(ctx, suite.T(), Users)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
getSelector func(t *testing.T) selectors.Selector
|
getSelector func(t *testing.T) selectors.Selector
|
||||||
@ -162,7 +162,7 @@ func (suite *ConnectorDataCollectionIntegrationSuite) TestSharePointDataCollecti
|
|||||||
ctx, flush := tester.NewContext()
|
ctx, flush := tester.NewContext()
|
||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
connector := loadConnector(ctx, suite.T())
|
connector := loadConnector(ctx, suite.T(), Users)
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
getSelector func(t *testing.T) selectors.Selector
|
getSelector func(t *testing.T) selectors.Selector
|
||||||
@ -230,7 +230,7 @@ func (suite *ConnectorCreateExchangeCollectionIntegrationSuite) SetupSuite() {
|
|||||||
|
|
||||||
_, err := tester.GetRequiredEnvVars(tester.M365AcctCredEnvs...)
|
_, err := tester.GetRequiredEnvVars(tester.M365AcctCredEnvs...)
|
||||||
require.NoError(suite.T(), err)
|
require.NoError(suite.T(), err)
|
||||||
suite.connector = loadConnector(ctx, suite.T())
|
suite.connector = loadConnector(ctx, suite.T(), Users)
|
||||||
suite.user = tester.M365UserID(suite.T())
|
suite.user = tester.M365UserID(suite.T())
|
||||||
suite.site = tester.M365SiteID(suite.T())
|
suite.site = tester.M365SiteID(suite.T())
|
||||||
tester.LogTimeOfTest(suite.T())
|
tester.LogTimeOfTest(suite.T())
|
||||||
@ -263,7 +263,7 @@ func (suite *ConnectorCreateExchangeCollectionIntegrationSuite) TestMailFetch()
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
gc := loadConnector(ctx, t)
|
gc := loadConnector(ctx, t, Users)
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
suite.T().Run(test.name, func(t *testing.T) {
|
suite.T().Run(test.name, func(t *testing.T) {
|
||||||
@ -292,7 +292,7 @@ func (suite *ConnectorCreateExchangeCollectionIntegrationSuite) TestMailSerializ
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
t := suite.T()
|
t := suite.T()
|
||||||
connector := loadConnector(ctx, t)
|
connector := loadConnector(ctx, t, Users)
|
||||||
sel := selectors.NewExchangeBackup()
|
sel := selectors.NewExchangeBackup()
|
||||||
sel.Include(sel.MailFolders([]string{suite.user}, []string{exchange.DefaultMailFolder}, selectors.PrefixMatch()))
|
sel.Include(sel.MailFolders([]string{suite.user}, []string{exchange.DefaultMailFolder}, selectors.PrefixMatch()))
|
||||||
collection, err := connector.createExchangeCollections(ctx, sel.Scopes()[0])
|
collection, err := connector.createExchangeCollections(ctx, sel.Scopes()[0])
|
||||||
@ -326,7 +326,7 @@ func (suite *ConnectorCreateExchangeCollectionIntegrationSuite) TestContactSeria
|
|||||||
ctx, flush := tester.NewContext()
|
ctx, flush := tester.NewContext()
|
||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
connector := loadConnector(ctx, suite.T())
|
connector := loadConnector(ctx, suite.T(), Users)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -379,7 +379,7 @@ func (suite *ConnectorCreateExchangeCollectionIntegrationSuite) TestEventsSerial
|
|||||||
ctx, flush := tester.NewContext()
|
ctx, flush := tester.NewContext()
|
||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
connector := loadConnector(ctx, suite.T())
|
connector := loadConnector(ctx, suite.T(), Users)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name, expected string
|
name, expected string
|
||||||
@ -447,7 +447,7 @@ func (suite *ConnectorCreateExchangeCollectionIntegrationSuite) TestAccessOfInbo
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
t := suite.T()
|
t := suite.T()
|
||||||
connector := loadConnector(ctx, t)
|
connector := loadConnector(ctx, t, Users)
|
||||||
sel := selectors.NewExchangeBackup()
|
sel := selectors.NewExchangeBackup()
|
||||||
sel.Include(sel.MailFolders(selectors.Any(), []string{exchange.DefaultMailFolder}, selectors.PrefixMatch()))
|
sel.Include(sel.MailFolders(selectors.Any(), []string{exchange.DefaultMailFolder}, selectors.PrefixMatch()))
|
||||||
scopes := sel.DiscreteScopes(connector.GetUsers())
|
scopes := sel.DiscreteScopes(connector.GetUsers())
|
||||||
@ -488,7 +488,7 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) SetupSuite() {
|
|||||||
|
|
||||||
_, err := tester.GetRequiredEnvVars(tester.M365AcctCredEnvs...)
|
_, err := tester.GetRequiredEnvVars(tester.M365AcctCredEnvs...)
|
||||||
require.NoError(suite.T(), err)
|
require.NoError(suite.T(), err)
|
||||||
suite.connector = loadConnector(ctx, suite.T())
|
suite.connector = loadConnector(ctx, suite.T(), Sites)
|
||||||
suite.user = tester.M365UserID(suite.T())
|
suite.user = tester.M365UserID(suite.T())
|
||||||
tester.LogTimeOfTest(suite.T())
|
tester.LogTimeOfTest(suite.T())
|
||||||
}
|
}
|
||||||
@ -502,7 +502,7 @@ func (suite *ConnectorCreateSharePointCollectionIntegrationSuite) TestCreateShar
|
|||||||
userID = tester.M365UserID(t)
|
userID = tester.M365UserID(t)
|
||||||
)
|
)
|
||||||
|
|
||||||
gc := loadConnector(ctx, t)
|
gc := loadConnector(ctx, t, Sites)
|
||||||
scope := selectors.NewSharePointBackup().Folders(
|
scope := selectors.NewSharePointBackup().Folders(
|
||||||
[]string{userID},
|
[]string{userID},
|
||||||
[]string{"foo"},
|
[]string{"foo"},
|
||||||
|
|||||||
@ -39,9 +39,9 @@ func checkRequiredValues(c graph.Container) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================
|
// =========================================
|
||||||
// cachedContainer Implementations
|
// cachedContainer Implementations
|
||||||
//======================
|
// =========================================
|
||||||
|
|
||||||
var _ graph.CachedContainer = &cacheFolder{}
|
var _ graph.CachedContainer = &cacheFolder{}
|
||||||
|
|
||||||
@ -50,9 +50,9 @@ type cacheFolder struct {
|
|||||||
p *path.Builder
|
p *path.Builder
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================
|
// =========================================
|
||||||
// Required Functions to satisfy interfaces
|
// Required Functions to satisfy interfaces
|
||||||
//=====================================
|
// =========================================
|
||||||
|
|
||||||
func (cf cacheFolder) Path() *path.Builder {
|
func (cf cacheFolder) Path() *path.Builder {
|
||||||
return cf.p
|
return cf.p
|
||||||
@ -79,6 +79,7 @@ func (c CalendarDisplayable) GetDisplayName() *string {
|
|||||||
// GetParentFolderId returns the default calendar name address
|
// GetParentFolderId returns the default calendar name address
|
||||||
// EventCalendars have a flat hierarchy and Calendars are rooted
|
// EventCalendars have a flat hierarchy and Calendars are rooted
|
||||||
// at the default
|
// at the default
|
||||||
|
//
|
||||||
//nolint:revive
|
//nolint:revive
|
||||||
func (c CalendarDisplayable) GetParentFolderId() *string {
|
func (c CalendarDisplayable) GetParentFolderId() *string {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
absser "github.com/microsoft/kiota-abstractions-go/serialization"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
@ -252,8 +253,10 @@ func (suite *ExchangeServiceSuite) TestGraphQueryFunctions() {
|
|||||||
function: GetAllFolderNamesForUser,
|
function: GetAllFolderNamesForUser,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GraphQuery: Get All Users",
|
name: "GraphQuery: Get All Users",
|
||||||
function: GetAllUsersForTenant,
|
function: func(ctx context.Context, gs graph.Service, toss string) (absser.Parsable, error) {
|
||||||
|
return GetAllUsersForTenant(ctx, gs)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "GraphQuery: Get All ContactFolders",
|
name: "GraphQuery: Get All ContactFolders",
|
||||||
|
|||||||
@ -6,7 +6,8 @@ package exchange
|
|||||||
// Legacy Value Tags and constants are used to override certain values within
|
// Legacy Value Tags and constants are used to override certain values within
|
||||||
// M365 objects.
|
// M365 objects.
|
||||||
// Master Property Value Document:
|
// Master Property Value Document:
|
||||||
// https://interoperability.blob.core.windows.net/files/MS-OXPROPS/%5bMS-OXPROPS%5d.pdf
|
//
|
||||||
|
// https://interoperability.blob.core.windows.net/files/MS-OXPROPS/%5bMS-OXPROPS%5d.pdf
|
||||||
const (
|
const (
|
||||||
// MailRestorePropertyTag inhibits exchange.Mail.Message from being "resent" through the server.
|
// MailRestorePropertyTag inhibits exchange.Mail.Message from being "resent" through the server.
|
||||||
// DEFINED: Section 2.791 PidTagMessageFlags
|
// DEFINED: Section 2.791 PidTagMessageFlags
|
||||||
@ -27,9 +28,9 @@ const (
|
|||||||
// Section: 2.789 PidTagMessageDeliveryTime
|
// Section: 2.789 PidTagMessageDeliveryTime
|
||||||
MailReceiveDateTimeOverriveProperty = "SystemTime 0x0E06"
|
MailReceiveDateTimeOverriveProperty = "SystemTime 0x0E06"
|
||||||
|
|
||||||
//----------------------------------
|
// ----------------------------------
|
||||||
// Default Folder Names
|
// Default Folder Names
|
||||||
//------------------------
|
// ----------------------------------
|
||||||
// Mail Definitions: https://docs.microsoft.com/en-us/graph/api/resources/mailfolder?view=graph-rest-1.0
|
// Mail Definitions: https://docs.microsoft.com/en-us/graph/api/resources/mailfolder?view=graph-rest-1.0
|
||||||
|
|
||||||
// inbox and root
|
// inbox and root
|
||||||
@ -38,9 +39,9 @@ const (
|
|||||||
DefaultContactFolder = "Contacts"
|
DefaultContactFolder = "Contacts"
|
||||||
DefaultCalendar = "Calendar"
|
DefaultCalendar = "Calendar"
|
||||||
|
|
||||||
//---------------------
|
// ----------------------------------
|
||||||
// Paging
|
// Paging
|
||||||
//-----------------
|
// ----------------------------------
|
||||||
// nextDataLink definition https://docs.microsoft.com/en-us/graph/paging
|
// nextDataLink definition https://docs.microsoft.com/en-us/graph/paging
|
||||||
nextDataLink = "@odata.nextLink"
|
nextDataLink = "@odata.nextLink"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -21,11 +21,11 @@ import (
|
|||||||
"github.com/alcionai/corso/src/pkg/path"
|
"github.com/alcionai/corso/src/pkg/path"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
// Constant Section
|
// Constant Section
|
||||||
// Defines the allowable strings that can be passed into
|
// Defines the allowable strings that can be passed into
|
||||||
// selectors for M365 objects
|
// selectors for M365 objects
|
||||||
//------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
var (
|
var (
|
||||||
fieldsForCalendars = map[string]int{
|
fieldsForCalendars = map[string]int{
|
||||||
"changeKey": 1,
|
"changeKey": 1,
|
||||||
@ -118,12 +118,12 @@ func CategoryToOptionIdentifier(category path.CategoryType) optionIdentifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
// exchange.Query Option Section
|
// exchange.Query Option Section
|
||||||
// These functions can be used to filter a response on M365
|
// These functions can be used to filter a response on M365
|
||||||
// Graph queries and reduce / filter the amount of data returned
|
// Graph queries and reduce / filter the amount of data returned
|
||||||
// which reduces the overall latency of complex calls
|
// which reduces the overall latency of complex calls
|
||||||
//----------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
func optionsForFolderMessages(moreOps []string) (*msmfmessage.MessagesRequestBuilderGetRequestConfiguration, error) {
|
func optionsForFolderMessages(moreOps []string) (*msmfmessage.MessagesRequestBuilderGetRequestConfiguration, error) {
|
||||||
selecting, err := buildOptions(moreOps, messages)
|
selecting, err := buildOptions(moreOps, messages)
|
||||||
|
|||||||
@ -23,9 +23,10 @@ type exchangeService struct {
|
|||||||
credentials account.M365Config
|
credentials account.M365Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// /------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
// Functions to comply with graph.Service Interface
|
// Functions to comply with graph.Service Interface
|
||||||
// -------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
|
|
||||||
func (es *exchangeService) Client() *msgraphsdk.GraphServiceClient {
|
func (es *exchangeService) Client() *msgraphsdk.GraphServiceClient {
|
||||||
return &es.client
|
return &es.client
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,9 +74,8 @@ func GetAllContactFolderNamesForUser(ctx context.Context, gs graph.Service, user
|
|||||||
return gs.Client().UsersById(user).ContactFolders().Get(ctx, options)
|
return gs.Client().UsersById(user).ContactFolders().Get(ctx, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllUsersForTenant is a GraphQuery for retrieving all the UserCollectionResponse with
|
// GetAllUsersForTenant makes a GraphQuery request retrieving all the users in the tenant.
|
||||||
// that contains the UserID and email for each user. All other information is omitted
|
func GetAllUsersForTenant(ctx context.Context, gs graph.Service) (absser.Parsable, error) {
|
||||||
func GetAllUsersForTenant(ctx context.Context, gs graph.Service, user string) (absser.Parsable, error) {
|
|
||||||
selecting := []string{"userPrincipalName"}
|
selecting := []string{"userPrincipalName"}
|
||||||
|
|
||||||
options, err := optionsForUsers(selecting)
|
options, err := optionsForUsers(selecting)
|
||||||
|
|||||||
@ -37,9 +37,9 @@ func CheckRequiredValues(c Container) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================
|
// ======================================
|
||||||
// cachedContainer Implementations
|
// cachedContainer Implementations
|
||||||
//======================================
|
// ======================================
|
||||||
|
|
||||||
var _ CachedContainer = &CacheFolder{}
|
var _ CachedContainer = &CacheFolder{}
|
||||||
|
|
||||||
@ -58,9 +58,9 @@ func NewCacheFolder(c Container, pb *path.Builder) CacheFolder {
|
|||||||
return cf
|
return cf
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================================
|
// =========================================
|
||||||
// Required Functions to satisfy interfaces
|
// Required Functions to satisfy interfaces
|
||||||
//=========================================
|
// =========================================
|
||||||
|
|
||||||
func (cf CacheFolder) Path() *path.Builder {
|
func (cf CacheFolder) Path() *path.Builder {
|
||||||
return cf.p
|
return cf.p
|
||||||
@ -86,6 +86,7 @@ func (c CalendarDisplayable) GetDisplayName() *string {
|
|||||||
// GetParentFolderId returns the default calendar name address
|
// GetParentFolderId returns the default calendar name address
|
||||||
// EventCalendars have a flat hierarchy and Calendars are rooted
|
// EventCalendars have a flat hierarchy and Calendars are rooted
|
||||||
// at the default
|
// at the default
|
||||||
|
//
|
||||||
//nolint:revive
|
//nolint:revive
|
||||||
func (c CalendarDisplayable) GetParentFolderId() *string {
|
func (c CalendarDisplayable) GetParentFolderId() *string {
|
||||||
return &c.parentID
|
return &c.parentID
|
||||||
|
|||||||
@ -4,10 +4,11 @@ package connector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"runtime/trace"
|
"runtime/trace"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/microsoft/kiota-abstractions-go/serialization"
|
||||||
msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go"
|
msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go"
|
||||||
msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core"
|
msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core"
|
||||||
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
@ -16,6 +17,7 @@ import (
|
|||||||
"github.com/alcionai/corso/src/internal/connector/exchange"
|
"github.com/alcionai/corso/src/internal/connector/exchange"
|
||||||
"github.com/alcionai/corso/src/internal/connector/graph"
|
"github.com/alcionai/corso/src/internal/connector/graph"
|
||||||
"github.com/alcionai/corso/src/internal/connector/onedrive"
|
"github.com/alcionai/corso/src/internal/connector/onedrive"
|
||||||
|
"github.com/alcionai/corso/src/internal/connector/sharepoint"
|
||||||
"github.com/alcionai/corso/src/internal/connector/support"
|
"github.com/alcionai/corso/src/internal/connector/support"
|
||||||
"github.com/alcionai/corso/src/internal/data"
|
"github.com/alcionai/corso/src/internal/data"
|
||||||
D "github.com/alcionai/corso/src/internal/diagnostics"
|
D "github.com/alcionai/corso/src/internal/diagnostics"
|
||||||
@ -73,7 +75,16 @@ func (gs graphService) ErrPolicy() bool {
|
|||||||
return gs.failFast
|
return gs.failFast
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGraphConnector(ctx context.Context, acct account.Account) (*GraphConnector, error) {
|
type resource int
|
||||||
|
|
||||||
|
const (
|
||||||
|
UnknownResource resource = iota
|
||||||
|
AllResources
|
||||||
|
Users
|
||||||
|
Sites
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewGraphConnector(ctx context.Context, acct account.Account, r resource) (*GraphConnector, error) {
|
||||||
m365, err := acct.M365Config()
|
m365, err := acct.M365Config()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "retrieving m365 account configuration")
|
return nil, errors.Wrap(err, "retrieving m365 account configuration")
|
||||||
@ -93,15 +104,16 @@ func NewGraphConnector(ctx context.Context, acct account.Account) (*GraphConnect
|
|||||||
|
|
||||||
gc.graphService = *aService
|
gc.graphService = *aService
|
||||||
|
|
||||||
err = gc.setTenantUsers(ctx)
|
if r == AllResources || r == Users {
|
||||||
if err != nil {
|
if err = gc.setTenantUsers(ctx); err != nil {
|
||||||
return nil, errors.Wrap(err, "retrieving tenant user list")
|
return nil, errors.Wrap(err, "retrieving tenant user list")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: users or sites, one or the other, not both.
|
if r == AllResources || r == Sites {
|
||||||
err = gc.setTenantSites(ctx)
|
if err = gc.setTenantSites(ctx); err != nil {
|
||||||
if err != nil {
|
return nil, errors.Wrap(err, "retrieveing tenant site list")
|
||||||
return nil, errors.Wrap(err, "retrieveing tenant site list")
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &gc, nil
|
return &gc, nil
|
||||||
@ -133,59 +145,41 @@ func (gs *graphService) EnableFailFast() {
|
|||||||
|
|
||||||
// setTenantUsers queries the M365 to identify the users in the
|
// setTenantUsers queries the M365 to identify the users in the
|
||||||
// workspace. The users field is updated during this method
|
// workspace. The users field is updated during this method
|
||||||
// iff the return value is nil
|
// iff the returned error is nil
|
||||||
func (gc *GraphConnector) setTenantUsers(ctx context.Context) error {
|
func (gc *GraphConnector) setTenantUsers(ctx context.Context) error {
|
||||||
ctx, end := D.Span(ctx, "gc:setTenantUsers")
|
ctx, end := D.Span(ctx, "gc:setTenantUsers")
|
||||||
defer end()
|
defer end()
|
||||||
|
|
||||||
response, err := exchange.GetAllUsersForTenant(ctx, gc.graphService, "")
|
users, err := getResources(
|
||||||
if err != nil {
|
ctx,
|
||||||
return errors.Wrapf(
|
gc.graphService,
|
||||||
err,
|
gc.tenant,
|
||||||
"tenant %s M365 query: %s",
|
exchange.GetAllUsersForTenant,
|
||||||
gc.tenant,
|
|
||||||
support.ConnectorStackErrorTrace(err),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
userIterator, err := msgraphgocore.NewPageIterator(
|
|
||||||
response,
|
|
||||||
&gc.graphService.adapter,
|
|
||||||
models.CreateUserCollectionResponseFromDiscriminatorValue,
|
models.CreateUserCollectionResponseFromDiscriminatorValue,
|
||||||
|
identifyUser,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, support.ConnectorStackErrorTrace(err))
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
callbackFunc := func(userItem interface{}) bool {
|
gc.Users = users
|
||||||
user, ok := userItem.(models.Userable)
|
|
||||||
if !ok {
|
|
||||||
err = support.WrapAndAppend(gc.graphService.adapter.GetBaseUrl(), errors.New("received non-User on iteration"), err)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.GetUserPrincipalName() == nil {
|
return nil
|
||||||
err = support.WrapAndAppend(
|
}
|
||||||
gc.graphService.adapter.GetBaseUrl(),
|
|
||||||
fmt.Errorf("no email address for User: %s", *user.GetId()),
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
|
|
||||||
return true
|
// Transforms an interface{} into a key,value pair representing
|
||||||
}
|
// userPrincipalName:userID.
|
||||||
|
func identifyUser(item any) (string, string, error) {
|
||||||
// *user.GetId() is populated for every M365 entityable object by M365 backstore
|
m, ok := item.(models.Userable)
|
||||||
gc.Users[*user.GetUserPrincipalName()] = *user.GetId()
|
if !ok {
|
||||||
|
return "", "", errors.New("iteration retrieved non-User item")
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iterateError := userIterator.Iterate(ctx, callbackFunc)
|
if m.GetUserPrincipalName() == nil {
|
||||||
if iterateError != nil {
|
return "", "", errors.Errorf("no principal name for User: %s", *m.GetId())
|
||||||
err = support.WrapAndAppend(gc.graphService.adapter.GetBaseUrl(), iterateError, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return *m.GetUserPrincipalName(), *m.GetId(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUsers returns the email address of users within tenant.
|
// GetUsers returns the email address of users within tenant.
|
||||||
@ -199,68 +193,53 @@ func (gc *GraphConnector) GetUsersIds() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// setTenantSites queries the M365 to identify the sites in the
|
// setTenantSites queries the M365 to identify the sites in the
|
||||||
// workspace. The sitets field is updated during this method
|
// workspace. The sites field is updated during this method
|
||||||
// iff the return value is nil
|
// iff the returned error is nil.
|
||||||
func (gc *GraphConnector) setTenantSites(ctx context.Context) error {
|
func (gc *GraphConnector) setTenantSites(ctx context.Context) error {
|
||||||
// TODO
|
|
||||||
gc.Sites = map[string]string{}
|
gc.Sites = map[string]string{}
|
||||||
|
|
||||||
// ctx, end := D.Span(ctx, "gc:setTenantSites")
|
ctx, end := D.Span(ctx, "gc:setTenantSites")
|
||||||
// defer end()
|
defer end()
|
||||||
|
|
||||||
// response, err := exchange.GetAllUsersForTenant(ctx, gc.graphService, "")
|
sites, err := getResources(
|
||||||
// if err != nil {
|
ctx,
|
||||||
// return errors.Wrapf(
|
gc.graphService,
|
||||||
// err,
|
gc.tenant,
|
||||||
// "tenant %s M365 query: %s",
|
sharepoint.GetAllSitesForTenant,
|
||||||
// gc.tenant,
|
models.CreateSiteCollectionResponseFromDiscriminatorValue,
|
||||||
// support.ConnectorStackErrorTrace(err),
|
identifySite,
|
||||||
// )
|
)
|
||||||
// }
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// userIterator, err := msgraphgocore.NewPageIterator(
|
gc.Sites = sites
|
||||||
// response,
|
|
||||||
// &gc.graphService.adapter,
|
|
||||||
// models.CreateUserCollectionResponseFromDiscriminatorValue,
|
|
||||||
// )
|
|
||||||
// if err != nil {
|
|
||||||
// return errors.Wrap(err, support.ConnectorStackErrorTrace(err))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// callbackFunc := func(userItem interface{}) bool {
|
|
||||||
// user, ok := userItem.(models.Userable)
|
|
||||||
// if !ok {
|
|
||||||
// err = support.WrapAndAppend(gc.graphService.adapter.GetBaseUrl(),
|
|
||||||
// errors.New("received non-User on iteration"), err)
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if user.GetUserPrincipalName() == nil {
|
|
||||||
// err = support.WrapAndAppend(
|
|
||||||
// gc.graphService.adapter.GetBaseUrl(),
|
|
||||||
// fmt.Errorf("no email address for User: %s", *user.GetId()),
|
|
||||||
// err,
|
|
||||||
// )
|
|
||||||
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // *user.GetId() is populated for every M365 entityable object by M365 backstore
|
|
||||||
// gc.Users[*user.GetUserPrincipalName()] = *user.GetId()
|
|
||||||
|
|
||||||
// return true
|
|
||||||
// }
|
|
||||||
|
|
||||||
// iterateError := userIterator.Iterate(ctx, callbackFunc)
|
|
||||||
// if iterateError != nil {
|
|
||||||
// err = support.WrapAndAppend(gc.graphService.adapter.GetBaseUrl(), iterateError, err)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return err
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errKnownSkippableCase = errors.New("case is known and skippable")
|
||||||
|
|
||||||
|
// Transforms an interface{} into a key,value pair representing
|
||||||
|
// siteName:siteID.
|
||||||
|
func identifySite(item any) (string, string, error) {
|
||||||
|
m, ok := item.(models.Siteable)
|
||||||
|
if !ok {
|
||||||
|
return "", "", errors.New("iteration retrieved non-Site item")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.GetName() == nil {
|
||||||
|
// the built-in site at "htps://{tenant-domain}/search" never has a name.
|
||||||
|
if m.GetWebUrl() != nil && strings.HasSuffix(*m.GetWebUrl(), "/search") {
|
||||||
|
return "", "", errKnownSkippableCase
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", "", errors.Errorf("no name for Site: %s", *m.GetId())
|
||||||
|
}
|
||||||
|
|
||||||
|
return *m.GetName(), *m.GetId(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetSites returns the siteIDs of sharepoint sites within tenant.
|
// GetSites returns the siteIDs of sharepoint sites within tenant.
|
||||||
func (gc *GraphConnector) GetSites() []string {
|
func (gc *GraphConnector) GetSites() []string {
|
||||||
return buildFromMap(true, gc.Sites)
|
return buildFromMap(true, gc.Sites)
|
||||||
@ -365,6 +344,57 @@ func (gc *GraphConnector) incrementAwaitingMessages() {
|
|||||||
// Helper Funcs
|
// Helper Funcs
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func getResources(
|
||||||
|
ctx context.Context,
|
||||||
|
gs graph.Service,
|
||||||
|
tenantID string,
|
||||||
|
query func(context.Context, graph.Service) (serialization.Parsable, error),
|
||||||
|
parser func(parseNode serialization.ParseNode) (serialization.Parsable, error),
|
||||||
|
identify func(any) (string, string, error),
|
||||||
|
) (map[string]string, error) {
|
||||||
|
resources := map[string]string{}
|
||||||
|
|
||||||
|
response, err := query(ctx, gs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(
|
||||||
|
err,
|
||||||
|
"retrieving resources for tenant %s: %s",
|
||||||
|
tenantID,
|
||||||
|
support.ConnectorStackErrorTrace(err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
iter, err := msgraphgocore.NewPageIterator(response, gs.Adapter(), parser)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, support.ConnectorStackErrorTrace(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
var iterErrs error
|
||||||
|
|
||||||
|
callbackFunc := func(item any) bool {
|
||||||
|
k, v, err := identify(item)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, errKnownSkippableCase) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
iterErrs = support.WrapAndAppend(gs.Adapter().GetBaseUrl(), err, iterErrs)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
resources[k] = v
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := iter.Iterate(ctx, callbackFunc); err != nil {
|
||||||
|
return nil, errors.Wrap(err, support.ConnectorStackErrorTrace(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return resources, iterErrs
|
||||||
|
}
|
||||||
|
|
||||||
// IsRecoverableError returns true iff error is a RecoverableGCEerror
|
// IsRecoverableError returns true iff error is a RecoverableGCEerror
|
||||||
func IsRecoverableError(e error) bool {
|
func IsRecoverableError(e error) bool {
|
||||||
var recoverable support.RecoverableGCError
|
var recoverable support.RecoverableGCError
|
||||||
|
|||||||
@ -65,7 +65,7 @@ func (suite *DisconnectedGraphConnectorSuite) TestBadConnection() {
|
|||||||
|
|
||||||
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) {
|
||||||
gc, err := NewGraphConnector(ctx, test.acct(t))
|
gc, err := NewGraphConnector(ctx, test.acct(t), Users)
|
||||||
assert.Nil(t, gc, test.name+" failed")
|
assert.Nil(t, gc, test.name+" failed")
|
||||||
assert.NotNil(t, err, test.name+"failed")
|
assert.NotNil(t, err, test.name+"failed")
|
||||||
})
|
})
|
||||||
|
|||||||
@ -162,6 +162,7 @@ type restoreBackupInfo struct {
|
|||||||
name string
|
name string
|
||||||
service path.ServiceType
|
service path.ServiceType
|
||||||
collections []colInfo
|
collections []colInfo
|
||||||
|
resource resource
|
||||||
}
|
}
|
||||||
|
|
||||||
func attachmentEqual(
|
func attachmentEqual(
|
||||||
@ -858,15 +859,16 @@ func getSelectorWith(service path.ServiceType) selectors.Selector {
|
|||||||
case path.OneDriveService:
|
case path.OneDriveService:
|
||||||
s = selectors.ServiceOneDrive
|
s = selectors.ServiceOneDrive
|
||||||
}
|
}
|
||||||
|
// TODO: ^ sharepoint
|
||||||
|
|
||||||
return selectors.Selector{
|
return selectors.Selector{
|
||||||
Service: s,
|
Service: s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadConnector(ctx context.Context, t *testing.T) *GraphConnector {
|
func loadConnector(ctx context.Context, t *testing.T, r resource) *GraphConnector {
|
||||||
a := tester.NewM365Account(t)
|
a := tester.NewM365Account(t)
|
||||||
connector, err := NewGraphConnector(ctx, a)
|
connector, err := NewGraphConnector(ctx, a, r)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
return connector
|
return connector
|
||||||
|
|||||||
@ -39,7 +39,7 @@ func (suite *GraphConnectorIntegrationSuite) SetupSuite() {
|
|||||||
|
|
||||||
_, err := tester.GetRequiredEnvVars(tester.M365AcctCredEnvs...)
|
_, err := tester.GetRequiredEnvVars(tester.M365AcctCredEnvs...)
|
||||||
require.NoError(suite.T(), err)
|
require.NoError(suite.T(), err)
|
||||||
suite.connector = loadConnector(ctx, suite.T())
|
suite.connector = loadConnector(ctx, suite.T(), Users)
|
||||||
suite.user = tester.M365UserID(suite.T())
|
suite.user = tester.M365UserID(suite.T())
|
||||||
tester.LogTimeOfTest(suite.T())
|
tester.LogTimeOfTest(suite.T())
|
||||||
}
|
}
|
||||||
@ -63,8 +63,8 @@ func (suite *GraphConnectorIntegrationSuite) TestSetTenantUsers() {
|
|||||||
|
|
||||||
suite.Equal(len(newConnector.Users), 0)
|
suite.Equal(len(newConnector.Users), 0)
|
||||||
err = newConnector.setTenantUsers(ctx)
|
err = newConnector.setTenantUsers(ctx)
|
||||||
assert.NoError(suite.T(), err)
|
suite.NoError(err)
|
||||||
suite.Greater(len(newConnector.Users), 0)
|
suite.Less(0, len(newConnector.Users))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestSetTenantUsers verifies GraphConnector's ability to query
|
// TestSetTenantUsers verifies GraphConnector's ability to query
|
||||||
@ -86,10 +86,8 @@ func (suite *GraphConnectorIntegrationSuite) TestSetTenantSites() {
|
|||||||
|
|
||||||
suite.Equal(0, len(newConnector.Sites))
|
suite.Equal(0, len(newConnector.Sites))
|
||||||
err = newConnector.setTenantSites(ctx)
|
err = newConnector.setTenantSites(ctx)
|
||||||
assert.NoError(suite.T(), err)
|
suite.NoError(err)
|
||||||
// TODO: should be non-zero once implemented.
|
suite.Less(0, len(newConnector.Sites))
|
||||||
// suite.Greater(len(newConnector.Users), 0)
|
|
||||||
suite.Equal(0, len(newConnector.Sites))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *GraphConnectorIntegrationSuite) TestEmptyCollections() {
|
func (suite *GraphConnectorIntegrationSuite) TestEmptyCollections() {
|
||||||
@ -194,7 +192,7 @@ func runRestoreBackupTest(
|
|||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
restoreGC := loadConnector(ctx, t)
|
restoreGC := loadConnector(ctx, t, test.resource)
|
||||||
restoreSel := getSelectorWith(test.service)
|
restoreSel := getSelectorWith(test.service)
|
||||||
deets, err := restoreGC.RestoreDataCollections(ctx, restoreSel, dest, collections)
|
deets, err := restoreGC.RestoreDataCollections(ctx, restoreSel, dest, collections)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -228,7 +226,7 @@ func runRestoreBackupTest(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
backupGC := loadConnector(ctx, t)
|
backupGC := loadConnector(ctx, t, test.resource)
|
||||||
backupSel := backupSelectorForExpected(t, test.service, expectedDests)
|
backupSel := backupSelectorForExpected(t, test.service, expectedDests)
|
||||||
t.Logf("Selective backup of %s\n", backupSel)
|
t.Logf("Selective backup of %s\n", backupSel)
|
||||||
|
|
||||||
@ -253,8 +251,9 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() {
|
|||||||
|
|
||||||
table := []restoreBackupInfo{
|
table := []restoreBackupInfo{
|
||||||
{
|
{
|
||||||
name: "EmailsWithAttachments",
|
name: "EmailsWithAttachments",
|
||||||
service: path.ExchangeService,
|
service: path.ExchangeService,
|
||||||
|
resource: Users,
|
||||||
collections: []colInfo{
|
collections: []colInfo{
|
||||||
{
|
{
|
||||||
pathElements: []string{"Inbox"},
|
pathElements: []string{"Inbox"},
|
||||||
@ -279,8 +278,9 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MultipleEmailsMultipleFolders",
|
name: "MultipleEmailsMultipleFolders",
|
||||||
service: path.ExchangeService,
|
service: path.ExchangeService,
|
||||||
|
resource: Users,
|
||||||
collections: []colInfo{
|
collections: []colInfo{
|
||||||
{
|
{
|
||||||
pathElements: []string{"Inbox"},
|
pathElements: []string{"Inbox"},
|
||||||
@ -324,8 +324,9 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MultipleContactsSingleFolder",
|
name: "MultipleContactsSingleFolder",
|
||||||
service: path.ExchangeService,
|
service: path.ExchangeService,
|
||||||
|
resource: Users,
|
||||||
collections: []colInfo{
|
collections: []colInfo{
|
||||||
{
|
{
|
||||||
pathElements: []string{"Contacts"},
|
pathElements: []string{"Contacts"},
|
||||||
@ -351,8 +352,9 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MultipleContactsMutlipleFolders",
|
name: "MultipleContactsMutlipleFolders",
|
||||||
service: path.ExchangeService,
|
service: path.ExchangeService,
|
||||||
|
resource: Users,
|
||||||
collections: []colInfo{
|
collections: []colInfo{
|
||||||
{
|
{
|
||||||
pathElements: []string{"Work"},
|
pathElements: []string{"Work"},
|
||||||
@ -475,8 +477,9 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() {
|
|||||||
func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames() {
|
func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames() {
|
||||||
table := []restoreBackupInfo{
|
table := []restoreBackupInfo{
|
||||||
{
|
{
|
||||||
name: "Contacts",
|
name: "Contacts",
|
||||||
service: path.ExchangeService,
|
service: path.ExchangeService,
|
||||||
|
resource: Users,
|
||||||
collections: []colInfo{
|
collections: []colInfo{
|
||||||
{
|
{
|
||||||
pathElements: []string{"Work"},
|
pathElements: []string{"Work"},
|
||||||
@ -574,7 +577,7 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames
|
|||||||
dest.ContainerName,
|
dest.ContainerName,
|
||||||
)
|
)
|
||||||
|
|
||||||
restoreGC := loadConnector(ctx, t)
|
restoreGC := loadConnector(ctx, t, test.resource)
|
||||||
deets, err := restoreGC.RestoreDataCollections(ctx, restoreSel, dest, collections)
|
deets, err := restoreGC.RestoreDataCollections(ctx, restoreSel, dest, collections)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, deets)
|
require.NotNil(t, deets)
|
||||||
@ -592,7 +595,7 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames
|
|||||||
|
|
||||||
// Run a backup and compare its output with what we put in.
|
// Run a backup and compare its output with what we put in.
|
||||||
|
|
||||||
backupGC := loadConnector(ctx, t)
|
backupGC := loadConnector(ctx, t, test.resource)
|
||||||
backupSel := backupSelectorForExpected(t, test.service, expectedDests)
|
backupSel := backupSelectorForExpected(t, test.service, expectedDests)
|
||||||
t.Log("Selective backup of", backupSel)
|
t.Log("Selective backup of", backupSel)
|
||||||
|
|
||||||
@ -622,8 +625,9 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiuserRestoreAndBackup() {
|
|||||||
}
|
}
|
||||||
table := []restoreBackupInfo{
|
table := []restoreBackupInfo{
|
||||||
{
|
{
|
||||||
name: "Email",
|
name: "Email",
|
||||||
service: path.ExchangeService,
|
service: path.ExchangeService,
|
||||||
|
resource: Users,
|
||||||
collections: []colInfo{
|
collections: []colInfo{
|
||||||
{
|
{
|
||||||
pathElements: []string{"Inbox"},
|
pathElements: []string{"Inbox"},
|
||||||
@ -658,8 +662,9 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiuserRestoreAndBackup() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Contacts",
|
name: "Contacts",
|
||||||
service: path.ExchangeService,
|
service: path.ExchangeService,
|
||||||
|
resource: Users,
|
||||||
collections: []colInfo{
|
collections: []colInfo{
|
||||||
{
|
{
|
||||||
pathElements: []string{"Work"},
|
pathElements: []string{"Work"},
|
||||||
|
|||||||
21
src/internal/connector/sharepoint/queries.go
Normal file
21
src/internal/connector/sharepoint/queries.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package sharepoint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
absser "github.com/microsoft/kiota-abstractions-go/serialization"
|
||||||
|
mssite "github.com/microsoftgraph/msgraph-sdk-go/sites"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/connector/graph"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetAllSitesForTenant makes a GraphQuery request retrieving all sites in the tenant.
|
||||||
|
func GetAllSitesForTenant(ctx context.Context, gs graph.Service) (absser.Parsable, error) {
|
||||||
|
options := &mssite.SitesRequestBuilderGetRequestConfiguration{
|
||||||
|
QueryParameters: &mssite.SitesRequestBuilderGetQueryParameters{
|
||||||
|
Select: []string{"id", "name", "weburl"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return gs.Client().Sites().Get(ctx, options)
|
||||||
|
}
|
||||||
@ -406,9 +406,9 @@ func SetAdditionalDataToEventMessage(
|
|||||||
|
|
||||||
// ToEventSimplified transforms an event to simplifed restore format
|
// ToEventSimplified transforms an event to simplifed restore format
|
||||||
// To overcome some of the MS Graph API challenges, the event object is modified in the following ways:
|
// To overcome some of the MS Graph API challenges, the event object is modified in the following ways:
|
||||||
// * Instead of adding attendees and generating spurious notifications,
|
// - Instead of adding attendees and generating spurious notifications,
|
||||||
// add a summary of attendees at the beginning to the event before the original body content
|
// add a summary of attendees at the beginning to the event before the original body content
|
||||||
// * event.attendees is set to an empty list
|
// - event.attendees is set to an empty list
|
||||||
func ToEventSimplified(orig models.Eventable) models.Eventable {
|
func ToEventSimplified(orig models.Eventable) models.Eventable {
|
||||||
attendees := FormatAttendees(orig, *orig.GetBody().GetContentType() == models.HTML_BODYTYPE)
|
attendees := FormatAttendees(orig, *orig.GetBody().GetContentType() == models.HTML_BODYTYPE)
|
||||||
orig.SetAttendees([]models.Attendeeable{})
|
orig.SetAttendees([]models.Attendeeable{})
|
||||||
|
|||||||
@ -128,7 +128,12 @@ func (op *BackupOperation) Run(ctx context.Context) (err error) {
|
|||||||
defer close(complete)
|
defer close(complete)
|
||||||
|
|
||||||
// retrieve data from the producer
|
// retrieve data from the producer
|
||||||
gc, err := connector.NewGraphConnector(ctx, op.account)
|
resource := connector.Users
|
||||||
|
if op.Selectors.Service == selectors.ServiceSharePoint {
|
||||||
|
resource = connector.Sites
|
||||||
|
}
|
||||||
|
|
||||||
|
gc, err := connector.NewGraphConnector(ctx, op.account, resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "connecting to graph api")
|
err = errors.Wrap(err, "connecting to graph api")
|
||||||
opStats.readErr = err
|
opStats.readErr = err
|
||||||
|
|||||||
@ -166,7 +166,12 @@ func (op *RestoreOperation) Run(ctx context.Context) (restoreDetails *details.De
|
|||||||
defer close(gcComplete)
|
defer close(gcComplete)
|
||||||
|
|
||||||
// restore those collections using graph
|
// restore those collections using graph
|
||||||
gc, err := connector.NewGraphConnector(ctx, op.account)
|
resource := connector.Users
|
||||||
|
if op.Selectors.Service == selectors.ServiceSharePoint {
|
||||||
|
resource = connector.Sites
|
||||||
|
}
|
||||||
|
|
||||||
|
gc, err := connector.NewGraphConnector(ctx, op.account, resource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "connecting to microsoft servers")
|
err = errors.Wrap(err, "connecting to microsoft servers")
|
||||||
opStats.writeErr = err
|
opStats.writeErr = err
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import (
|
|||||||
// Users returns a list of users in the specified M365 tenant
|
// Users returns a list of users in the specified M365 tenant
|
||||||
// TODO: Implement paging support
|
// TODO: Implement paging support
|
||||||
func Users(ctx context.Context, m365Account account.Account) ([]string, error) {
|
func Users(ctx context.Context, m365Account account.Account) ([]string, error) {
|
||||||
gc, err := connector.NewGraphConnector(ctx, m365Account)
|
gc, err := connector.NewGraphConnector(ctx, m365Account, connector.Users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "could not initialize M365 graph connection")
|
return nil, errors.Wrap(err, "could not initialize M365 graph connection")
|
||||||
}
|
}
|
||||||
@ -23,7 +23,7 @@ func Users(ctx context.Context, m365Account account.Account) ([]string, error) {
|
|||||||
// UserIDs returns a list of user IDs for the specified M365 tenant
|
// UserIDs returns a list of user IDs for the specified M365 tenant
|
||||||
// TODO: Implement paging support
|
// TODO: Implement paging support
|
||||||
func UserIDs(ctx context.Context, m365Account account.Account) ([]string, error) {
|
func UserIDs(ctx context.Context, m365Account account.Account) ([]string, error) {
|
||||||
gc, err := connector.NewGraphConnector(ctx, m365Account)
|
gc, err := connector.NewGraphConnector(ctx, m365Account, connector.Users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "could not initialize M365 graph connection")
|
return nil, errors.Wrap(err, "could not initialize M365 graph connection")
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ func UserIDs(ctx context.Context, m365Account account.Account) ([]string, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetEmailAndUserID(ctx context.Context, m365Account account.Account) (map[string]string, error) {
|
func GetEmailAndUserID(ctx context.Context, m365Account account.Account) (map[string]string, error) {
|
||||||
gc, err := connector.NewGraphConnector(ctx, m365Account)
|
gc, err := connector.NewGraphConnector(ctx, m365Account, connector.Users)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "could not initialize M365 graph connection")
|
return nil, errors.Wrap(err, "could not initialize M365 graph connection")
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user