From c88b5764a96841622c5342fb8fb68c853f698ae4 Mon Sep 17 00:00:00 2001 From: Keepers Date: Thu, 5 Oct 2023 10:38:17 -0600 Subject: [PATCH] hand resource down to drive controller (#4436) hands the backup resource into the drive collection for the handler to use to record as the siteID --- #### Does this PR need a docs update or release note? - [x] :no_entry: No #### Type of change - [x] :bug: Bugfix #### Issue(s) * #3988 #### Test Plan - [x] :muscle: Manual - [x] :zap: Unit test - [x] :green_heart: E2E --- src/cmd/factory/impl/common.go | 6 +- src/internal/common/idname/idname.go | 34 ++- src/internal/m365/backup_test.go | 24 +- .../m365/collection/drive/collection.go | 39 ++-- .../m365/collection/drive/collection_test.go | 5 + .../m365/collection/drive/collections.go | 25 +- .../m365/collection/drive/collections_test.go | 8 +- .../m365/collection/drive/handler_utils.go | 25 +- .../m365/collection/drive/handlers.go | 2 + .../collection/drive/item_collector_test.go | 3 +- .../m365/collection/drive/item_handler.go | 7 +- .../m365/collection/drive/library_handler.go | 42 +--- src/internal/m365/collection/drive/restore.go | 23 +- src/internal/m365/collection/site/backup.go | 2 +- src/internal/m365/controller.go | 54 ++--- src/internal/m365/controller_test.go | 214 ++++++++++-------- src/internal/m365/mock/connector.go | 5 +- src/internal/m365/service/groups/backup.go | 2 +- src/internal/m365/service/onedrive/backup.go | 2 +- .../m365/service/onedrive/mock/handlers.go | 26 ++- .../m365/service/sharepoint/backup_test.go | 3 +- src/internal/operations/help_test.go | 4 +- src/internal/operations/inject/inject.go | 5 +- src/internal/operations/restore.go | 4 +- src/internal/operations/test/helper_test.go | 4 +- src/pkg/repository/backups.go | 4 +- 26 files changed, 305 insertions(+), 267 deletions(-) diff --git a/src/cmd/factory/impl/common.go b/src/cmd/factory/impl/common.go index 466595587..876b1dc2e 100644 --- a/src/cmd/factory/impl/common.go +++ b/src/cmd/factory/impl/common.go @@ -120,7 +120,7 @@ func generateAndRestoreItems( func getControllerAndVerifyResourceOwner( ctx context.Context, - resourceOwner string, + protectedResource string, pst path.ServiceType, ) ( *m365.Controller, @@ -150,12 +150,12 @@ func getControllerAndVerifyResourceOwner( return nil, account.Account{}, nil, clues.Wrap(err, "connecting to graph api") } - id, _, err := ctrl.PopulateProtectedResourceIDAndName(ctx, resourceOwner, nil) + pr, err := ctrl.PopulateProtectedResourceIDAndName(ctx, protectedResource, nil) if err != nil { return nil, account.Account{}, nil, clues.Wrap(err, "verifying user") } - return ctrl, acct, ctrl.IDNameLookup.ProviderForID(id), nil + return ctrl, acct, pr, nil } type item struct { diff --git a/src/internal/common/idname/idname.go b/src/internal/common/idname/idname.go index e2a48fca3..06a011fa0 100644 --- a/src/internal/common/idname/idname.go +++ b/src/internal/common/idname/idname.go @@ -1,8 +1,11 @@ package idname import ( + "context" + "fmt" "strings" + "github.com/alcionai/clues" "golang.org/x/exp/maps" ) @@ -21,7 +24,18 @@ type Provider interface { Name() string } -var _ Provider = &is{} +type GetResourceIDAndNamer interface { + GetResourceIDAndNameFrom( + ctx context.Context, + owner string, + cacher Cacher, + ) (Provider, error) +} + +var ( + _ Provider = &is{} + _ clues.Concealer = &is{} +) type is struct { id string @@ -35,6 +49,24 @@ func NewProvider(id, name string) *is { func (is is) ID() string { return is.id } func (is is) Name() string { return is.name } +const isStringTmpl = "{id:%s, name:%s}" + +func (is is) PlainString() string { + return fmt.Sprintf(isStringTmpl, clues.Hide(is.id), clues.Hide(is.name)) +} + +func (is is) Conceal() string { + return fmt.Sprintf(isStringTmpl, clues.Hide(is.id), clues.Hide(is.name)) +} + +func (is is) String() string { + return is.Conceal() +} + +func (is is) Format(fs fmt.State, _ rune) { + fmt.Fprint(fs, is.Conceal()) +} + type Cacher interface { IDOf(name string) (string, bool) NameOf(id string) (string, bool) diff --git a/src/internal/m365/backup_test.go b/src/internal/m365/backup_test.go index f7e51f89d..b5efb4d4c 100644 --- a/src/internal/m365/backup_test.go +++ b/src/internal/m365/backup_test.go @@ -380,18 +380,18 @@ func (suite *SPCollectionIntgSuite) TestCreateSharePointCollection_Libraries() { siteIDs = []string{siteID} ) - id, name, err := ctrl.PopulateProtectedResourceIDAndName(ctx, siteID, nil) + site, err := ctrl.PopulateProtectedResourceIDAndName(ctx, siteID, nil) require.NoError(t, err, clues.ToCore(err)) sel := selectors.NewSharePointBackup(siteIDs) sel.Include(sel.LibraryFolders([]string{"foo"}, selectors.PrefixMatch())) - sel.SetDiscreteOwnerIDName(id, name) + sel.SetDiscreteOwnerIDName(site.ID(), site.Name()) bpc := inject.BackupProducerConfig{ LastBackupVersion: version.NoBackup, Options: control.DefaultOptions(), - ProtectedResource: inMock.NewProvider(id, name), + ProtectedResource: site, Selector: sel.Selector, } @@ -430,18 +430,18 @@ func (suite *SPCollectionIntgSuite) TestCreateSharePointCollection_Lists() { siteIDs = []string{siteID} ) - id, name, err := ctrl.PopulateProtectedResourceIDAndName(ctx, siteID, nil) + site, err := ctrl.PopulateProtectedResourceIDAndName(ctx, siteID, nil) require.NoError(t, err, clues.ToCore(err)) sel := selectors.NewSharePointBackup(siteIDs) sel.Include(sel.Lists(selectors.Any())) - sel.SetDiscreteOwnerIDName(id, name) + sel.SetDiscreteOwnerIDName(site.ID(), site.Name()) bpc := inject.BackupProducerConfig{ LastBackupVersion: version.NoBackup, Options: control.DefaultOptions(), - ProtectedResource: inMock.NewProvider(id, name), + ProtectedResource: site, Selector: sel.Selector, } @@ -516,18 +516,18 @@ func (suite *GroupsCollectionIntgSuite) TestCreateGroupsCollection_SharePoint() groupIDs = []string{groupID} ) - id, name, err := ctrl.PopulateProtectedResourceIDAndName(ctx, groupID, nil) + group, err := ctrl.PopulateProtectedResourceIDAndName(ctx, groupID, nil) require.NoError(t, err, clues.ToCore(err)) sel := selectors.NewGroupsBackup(groupIDs) sel.Include(sel.LibraryFolders([]string{"test"}, selectors.PrefixMatch())) - sel.SetDiscreteOwnerIDName(id, name) + sel.SetDiscreteOwnerIDName(group.ID(), group.Name()) bpc := inject.BackupProducerConfig{ LastBackupVersion: version.NoBackup, Options: control.DefaultOptions(), - ProtectedResource: inMock.NewProvider(id, name), + ProtectedResource: group, Selector: sel.Selector, } @@ -590,13 +590,13 @@ func (suite *GroupsCollectionIntgSuite) TestCreateGroupsCollection_SharePoint_In groupIDs = []string{groupID} ) - id, name, err := ctrl.PopulateProtectedResourceIDAndName(ctx, groupID, nil) + group, err := ctrl.PopulateProtectedResourceIDAndName(ctx, groupID, nil) require.NoError(t, err, clues.ToCore(err)) sel := selectors.NewGroupsBackup(groupIDs) sel.Include(sel.LibraryFolders([]string{"test"}, selectors.PrefixMatch())) - sel.SetDiscreteOwnerIDName(id, name) + sel.SetDiscreteOwnerIDName(group.ID(), group.Name()) site, err := suite.connector.AC.Groups().GetRootSite(ctx, groupID) require.NoError(t, err, clues.ToCore(err)) @@ -626,7 +626,7 @@ func (suite *GroupsCollectionIntgSuite) TestCreateGroupsCollection_SharePoint_In bpc := inject.BackupProducerConfig{ LastBackupVersion: version.NoBackup, Options: control.DefaultOptions(), - ProtectedResource: inMock.NewProvider(id, name), + ProtectedResource: group, Selector: sel.Selector, MetadataCollections: mmc, } diff --git a/src/internal/m365/collection/drive/collection.go b/src/internal/m365/collection/drive/collection.go index b29cb98be..b963cf6a7 100644 --- a/src/internal/m365/collection/drive/collection.go +++ b/src/internal/m365/collection/drive/collection.go @@ -13,6 +13,7 @@ import ( "github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/spatialcurrent/go-lazy/pkg/lazy" + "github.com/alcionai/corso/src/internal/common/idname" "github.com/alcionai/corso/src/internal/common/ptr" "github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/internal/m365/collection/drive/metadata" @@ -39,6 +40,9 @@ var _ data.BackupCollection = &Collection{} type Collection struct { handler BackupHandler + // the protected resource represented in this collection. + protectedResource idname.Provider + // data is used to share data streams with the collection consumer data chan data.Item // folderPath indicates what level in the hierarchy this collection @@ -98,6 +102,7 @@ func pathToLocation(p path.Path) (*path.Builder, error) { // NewCollection creates a Collection func NewCollection( handler BackupHandler, + resource idname.Provider, currPath path.Path, prevPath path.Path, driveID string, @@ -123,6 +128,7 @@ func NewCollection( c := newColl( handler, + resource, currPath, prevPath, driveID, @@ -140,6 +146,7 @@ func NewCollection( func newColl( handler BackupHandler, + resource idname.Provider, currPath path.Path, prevPath path.Path, driveID string, @@ -150,18 +157,19 @@ func newColl( urlCache getItemPropertyer, ) *Collection { c := &Collection{ - handler: handler, - folderPath: currPath, - prevPath: prevPath, - driveItems: map[string]models.DriveItemable{}, - driveID: driveID, - data: make(chan data.Item, graph.Parallelism(path.OneDriveMetadataService).CollectionBufferSize()), - statusUpdater: statusUpdater, - ctrl: ctrlOpts, - state: data.StateOf(prevPath, currPath), - scope: colScope, - doNotMergeItems: doNotMergeItems, - urlCache: urlCache, + handler: handler, + protectedResource: resource, + folderPath: currPath, + prevPath: prevPath, + driveItems: map[string]models.DriveItemable{}, + driveID: driveID, + data: make(chan data.Item, graph.Parallelism(path.OneDriveMetadataService).CollectionBufferSize()), + statusUpdater: statusUpdater, + ctrl: ctrlOpts, + state: data.StateOf(prevPath, currPath), + scope: colScope, + doNotMergeItems: doNotMergeItems, + urlCache: urlCache, } return c @@ -551,7 +559,12 @@ func (oc *Collection) streamDriveItem( return } - itemInfo = oc.handler.AugmentItemInfo(itemInfo, item, itemSize, parentPath) + itemInfo = oc.handler.AugmentItemInfo( + itemInfo, + oc.protectedResource, + item, + itemSize, + parentPath) ctx = clues.Add(ctx, "item_info", itemInfo) diff --git a/src/internal/m365/collection/drive/collection_test.go b/src/internal/m365/collection/drive/collection_test.go index 9ced071f9..daeb8cfb3 100644 --- a/src/internal/m365/collection/drive/collection_test.go +++ b/src/internal/m365/collection/drive/collection_test.go @@ -207,6 +207,7 @@ func (suite *CollectionUnitSuite) TestCollection() { coll, err := NewCollection( mbh, + mbh.ProtectedResource, folderPath, nil, "drive-id", @@ -328,6 +329,7 @@ func (suite *CollectionUnitSuite) TestCollectionReadError() { coll, err := NewCollection( mbh, + mbh.ProtectedResource, folderPath, nil, "fakeDriveID", @@ -405,6 +407,7 @@ func (suite *CollectionUnitSuite) TestCollectionReadUnauthorizedErrorRetry() { coll, err := NewCollection( mbh, + mbh.ProtectedResource, folderPath, nil, "fakeDriveID", @@ -460,6 +463,7 @@ func (suite *CollectionUnitSuite) TestCollectionPermissionBackupLatestModTime() coll, err := NewCollection( mbh, + mbh.ProtectedResource, folderPath, nil, "drive-id", @@ -971,6 +975,7 @@ func (suite *CollectionUnitSuite) TestItemExtensions() { coll, err := NewCollection( mbh, + mbh.ProtectedResource, folderPath, nil, driveID, diff --git a/src/internal/m365/collection/drive/collections.go b/src/internal/m365/collection/drive/collections.go index 7d94156ea..17aee6217 100644 --- a/src/internal/m365/collection/drive/collections.go +++ b/src/internal/m365/collection/drive/collections.go @@ -11,6 +11,7 @@ import ( "github.com/microsoftgraph/msgraph-sdk-go/models" "golang.org/x/exp/maps" + "github.com/alcionai/corso/src/internal/common/idname" "github.com/alcionai/corso/src/internal/common/prefixmatcher" "github.com/alcionai/corso/src/internal/common/ptr" "github.com/alcionai/corso/src/internal/data" @@ -48,8 +49,8 @@ const restrictedDirectory = "Site Pages" type Collections struct { handler BackupHandler - tenantID string - resourceOwner string + tenantID string + protectedResource idname.Provider statusUpdater support.StatusUpdater @@ -69,17 +70,17 @@ type Collections struct { func NewCollections( bh BackupHandler, tenantID string, - resourceOwner string, + protectedResource idname.Provider, statusUpdater support.StatusUpdater, ctrlOpts control.Options, ) *Collections { return &Collections{ - handler: bh, - tenantID: tenantID, - resourceOwner: resourceOwner, - CollectionMap: map[string]map[string]*Collection{}, - statusUpdater: statusUpdater, - ctrl: ctrlOpts, + handler: bh, + tenantID: tenantID, + protectedResource: protectedResource, + CollectionMap: map[string]map[string]*Collection{}, + statusUpdater: statusUpdater, + ctrl: ctrlOpts, } } @@ -246,7 +247,7 @@ func (c *Collections) Get( defer close(progressBar) // Enumerate drives for the specified resourceOwner - pager := c.handler.NewDrivePager(c.resourceOwner, nil) + pager := c.handler.NewDrivePager(c.protectedResource.ID(), nil) drives, err := api.GetAllDrives(ctx, pager) if err != nil { @@ -384,6 +385,7 @@ func (c *Collections) Get( col, err := NewCollection( c.handler, + c.protectedResource, nil, // delete the folder prevPath, driveID, @@ -420,6 +422,7 @@ func (c *Collections) Get( coll, err := NewCollection( c.handler, + c.protectedResource, nil, // delete the drive prevDrivePath, driveID, @@ -605,6 +608,7 @@ func (c *Collections) handleDelete( col, err := NewCollection( c.handler, + c.protectedResource, nil, // deletes the collection prevPath, driveID, @@ -789,6 +793,7 @@ func (c *Collections) UpdateCollections( col, err := NewCollection( c.handler, + c.protectedResource, collectionPath, prevPath, driveID, diff --git a/src/internal/m365/collection/drive/collections_test.go b/src/internal/m365/collection/drive/collections_test.go index 1e25d16c0..2943447fe 100644 --- a/src/internal/m365/collection/drive/collections_test.go +++ b/src/internal/m365/collection/drive/collections_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/suite" "golang.org/x/exp/maps" + "github.com/alcionai/corso/src/internal/common/idname" "github.com/alcionai/corso/src/internal/common/prefixmatcher" pmMock "github.com/alcionai/corso/src/internal/common/prefixmatcher/mock" "github.com/alcionai/corso/src/internal/data" @@ -747,7 +748,7 @@ func (suite *OneDriveCollectionsUnitSuite) TestUpdateCollections() { c := NewCollections( &itemBackupHandler{api.Drives{}, user, tt.scope}, tenant, - user, + idname.NewProvider(user, user), nil, control.Options{ToggleFeatures: control.Toggles{}}) @@ -2274,7 +2275,7 @@ func (suite *OneDriveCollectionsUnitSuite) TestGet() { c := NewCollections( mbh, tenant, - user, + idname.NewProvider(user, user), func(*support.ControllerOperationStatus) {}, control.Options{ToggleFeatures: control.Toggles{}}) @@ -2648,7 +2649,7 @@ func (suite *OneDriveCollectionsUnitSuite) TestAddURLCacheToDriveCollections() { c := NewCollections( mbh, "test-tenant", - "test-user", + idname.NewProvider("test-user", "test-user"), nil, control.Options{ToggleFeatures: control.Toggles{}}) @@ -2660,6 +2661,7 @@ func (suite *OneDriveCollectionsUnitSuite) TestAddURLCacheToDriveCollections() { for i := 0; i < collCount; i++ { coll, err := NewCollection( &itemBackupHandler{api.Drives{}, "test-user", anyFolder}, + idname.NewProvider("", ""), nil, nil, driveID, diff --git a/src/internal/m365/collection/drive/handler_utils.go b/src/internal/m365/collection/drive/handler_utils.go index 9d0f973ad..d637d1a8a 100644 --- a/src/internal/m365/collection/drive/handler_utils.go +++ b/src/internal/m365/collection/drive/handler_utils.go @@ -5,6 +5,7 @@ import ( "github.com/microsoftgraph/msgraph-sdk-go/models" + "github.com/alcionai/corso/src/internal/common/idname" "github.com/alcionai/corso/src/internal/common/ptr" "github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/path" @@ -12,12 +13,13 @@ import ( func augmentItemInfo( dii details.ItemInfo, + resource idname.Provider, service path.ServiceType, item models.DriveItemable, size int64, parentPath *path.Builder, ) details.ItemInfo { - var driveName, siteID, driveID, weburl, creatorEmail string + var driveName, driveID, creatorEmail string // TODO: we rely on this info for details/restore lookups, // so if it's nil we have an issue, and will need an alternative @@ -38,19 +40,6 @@ func augmentItemInfo( } } - if service == path.SharePointService || - service == path.GroupsService { - gsi := item.GetSharepointIds() - if gsi != nil { - siteID = ptr.Val(gsi.GetSiteId()) - weburl = ptr.Val(gsi.GetSiteUrl()) - - if len(weburl) == 0 { - weburl = constructWebURL(item.GetAdditionalData()) - } - } - } - if item.GetParentReference() != nil { driveID = ptr.Val(item.GetParentReference().GetDriveId()) driveName = strings.TrimSpace(ptr.Val(item.GetParentReference().GetName())) @@ -84,9 +73,9 @@ func augmentItemInfo( Modified: ptr.Val(item.GetLastModifiedDateTime()), Owner: creatorEmail, ParentPath: pps, - SiteID: siteID, + SiteID: resource.ID(), Size: size, - WebURL: weburl, + WebURL: resource.Name(), } case path.GroupsService: @@ -99,9 +88,9 @@ func augmentItemInfo( Modified: ptr.Val(item.GetLastModifiedDateTime()), Owner: creatorEmail, ParentPath: pps, - SiteID: siteID, + SiteID: resource.ID(), Size: size, - WebURL: weburl, + WebURL: resource.Name(), } } diff --git a/src/internal/m365/collection/drive/handlers.go b/src/internal/m365/collection/drive/handlers.go index 7b0064546..eaa27aebb 100644 --- a/src/internal/m365/collection/drive/handlers.go +++ b/src/internal/m365/collection/drive/handlers.go @@ -6,6 +6,7 @@ import ( "github.com/microsoftgraph/msgraph-sdk-go/drives" "github.com/microsoftgraph/msgraph-sdk-go/models" + "github.com/alcionai/corso/src/internal/common/idname" "github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/control" "github.com/alcionai/corso/src/pkg/path" @@ -20,6 +21,7 @@ type ItemInfoAugmenter interface { // and kiota drops any SetSize update. AugmentItemInfo( dii details.ItemInfo, + resource idname.Provider, item models.DriveItemable, size int64, parentPath *path.Builder, diff --git a/src/internal/m365/collection/drive/item_collector_test.go b/src/internal/m365/collection/drive/item_collector_test.go index 0cc4d2a67..b6f32a5bc 100644 --- a/src/internal/m365/collection/drive/item_collector_test.go +++ b/src/internal/m365/collection/drive/item_collector_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "github.com/alcionai/corso/src/internal/common/idname" "github.com/alcionai/corso/src/internal/common/prefixmatcher" "github.com/alcionai/corso/src/internal/m365/graph" "github.com/alcionai/corso/src/internal/tester" @@ -267,7 +268,7 @@ func (suite *OneDriveIntgSuite) TestOneDriveNewCollections() { colls := NewCollections( &itemBackupHandler{suite.ac.Drives(), test.user, scope}, creds.AzureTenantID, - test.user, + idname.NewProvider(test.user, test.user), service.updateStatus, control.Options{ ToggleFeatures: control.Toggles{}, diff --git a/src/internal/m365/collection/drive/item_handler.go b/src/internal/m365/collection/drive/item_handler.go index 4a62f35e3..0e72ec55f 100644 --- a/src/internal/m365/collection/drive/item_handler.go +++ b/src/internal/m365/collection/drive/item_handler.go @@ -8,6 +8,7 @@ import ( "github.com/microsoftgraph/msgraph-sdk-go/drives" "github.com/microsoftgraph/msgraph-sdk-go/models" + "github.com/alcionai/corso/src/internal/common/idname" odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts" "github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/control" @@ -96,11 +97,12 @@ func (h itemBackupHandler) NewItemPager( func (h itemBackupHandler) AugmentItemInfo( dii details.ItemInfo, + resource idname.Provider, item models.DriveItemable, size int64, parentPath *path.Builder, ) details.ItemInfo { - return augmentItemInfo(dii, path.OneDriveService, item, size, parentPath) + return augmentItemInfo(dii, resource, path.OneDriveService, item, size, parentPath) } func (h itemBackupHandler) FormatDisplayPath( @@ -173,11 +175,12 @@ func (h itemRestoreHandler) NewDrivePager( // and kiota drops any SetSize update. func (h itemRestoreHandler) AugmentItemInfo( dii details.ItemInfo, + resource idname.Provider, item models.DriveItemable, size int64, parentPath *path.Builder, ) details.ItemInfo { - return augmentItemInfo(dii, path.OneDriveService, item, size, parentPath) + return augmentItemInfo(dii, resource, path.OneDriveService, item, size, parentPath) } func (h itemRestoreHandler) DeleteItem( diff --git a/src/internal/m365/collection/drive/library_handler.go b/src/internal/m365/collection/drive/library_handler.go index 74ec182d9..51a9e5bed 100644 --- a/src/internal/m365/collection/drive/library_handler.go +++ b/src/internal/m365/collection/drive/library_handler.go @@ -3,13 +3,12 @@ package drive import ( "context" "net/http" - "strings" "github.com/alcionai/clues" "github.com/microsoftgraph/msgraph-sdk-go/drives" "github.com/microsoftgraph/msgraph-sdk-go/models" - "github.com/alcionai/corso/src/internal/common/ptr" + "github.com/alcionai/corso/src/internal/common/idname" odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts" "github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/control" @@ -101,44 +100,12 @@ func (h libraryBackupHandler) NewItemPager( func (h libraryBackupHandler) AugmentItemInfo( dii details.ItemInfo, + resource idname.Provider, item models.DriveItemable, size int64, parentPath *path.Builder, ) details.ItemInfo { - return augmentItemInfo(dii, h.service, item, size, parentPath) -} - -// constructWebURL is a helper function for recreating the webURL -// for the originating SharePoint site. Uses the additionalData map -// from a models.DriveItemable that possesses a downloadURL within the map. -// Returns "" if the map is nil or key is not present. -func constructWebURL(adtl map[string]any) string { - var ( - desiredKey = "@microsoft.graph.downloadUrl" - sep = `/_layouts` - url string - ) - - if adtl == nil { - return url - } - - r := adtl[desiredKey] - point, ok := r.(*string) - - if !ok { - return url - } - - value := ptr.Val(point) - if len(value) == 0 { - return url - } - - temp := strings.Split(value, sep) - url = temp[0] - - return url + return augmentItemInfo(dii, resource, h.service, item, size, parentPath) } func (h libraryBackupHandler) FormatDisplayPath( @@ -208,11 +175,12 @@ func (h libraryRestoreHandler) NewDrivePager( func (h libraryRestoreHandler) AugmentItemInfo( dii details.ItemInfo, + resource idname.Provider, item models.DriveItemable, size int64, parentPath *path.Builder, ) details.ItemInfo { - return augmentItemInfo(dii, h.service, item, size, parentPath) + return augmentItemInfo(dii, resource, h.service, item, size, parentPath) } func (h libraryRestoreHandler) DeleteItem( diff --git a/src/internal/m365/collection/drive/restore.go b/src/internal/m365/collection/drive/restore.go index 7a9017744..106896faa 100644 --- a/src/internal/m365/collection/drive/restore.go +++ b/src/internal/m365/collection/drive/restore.go @@ -271,7 +271,7 @@ func restoreItem( itemInfo, err := restoreV0File( ctx, rh, - rcc.RestoreConfig, + rcc, drivePath, fibn, restoreFolderID, @@ -377,7 +377,7 @@ func restoreItem( func restoreV0File( ctx context.Context, rh RestoreHandler, - restoreCfg control.RestoreConfig, + rcc inject.RestoreConsumerConfig, drivePath *path.DrivePath, fibn data.FetchItemByNamer, restoreFolderID string, @@ -388,7 +388,7 @@ func restoreV0File( ) (details.ItemInfo, error) { _, itemInfo, err := restoreFile( ctx, - restoreCfg, + rcc, rh, fibn, itemData.ID(), @@ -423,7 +423,7 @@ func restoreV1File( itemID, itemInfo, err := restoreFile( ctx, - rcc.RestoreConfig, + rcc, rh, fibn, trimmedName, @@ -509,7 +509,7 @@ func restoreV6File( itemID, itemInfo, err := restoreFile( ctx, - rcc.RestoreConfig, + rcc, rh, fibn, meta.FileName, @@ -711,7 +711,7 @@ type itemRestorer interface { // restoreFile will create a new item in the specified `parentFolderID` and upload the data.Item func restoreFile( ctx context.Context, - restoreCfg control.RestoreConfig, + rcc inject.RestoreConsumerConfig, ir itemRestorer, fibn data.FetchItemByNamer, name string, @@ -743,7 +743,7 @@ func restoreFile( log := logger.Ctx(ctx).With("collision_key", clues.Hide(collisionKey)) log.Debug("item collision") - if restoreCfg.OnCollision == control.Skip { + if rcc.RestoreConfig.OnCollision == control.Skip { ctr.Inc(count.CollisionSkip) log.Debug("skipping item with collision") @@ -751,7 +751,7 @@ func restoreFile( } collision = dci - shouldDeleteOriginal = restoreCfg.OnCollision == control.Replace && !dci.IsFolder + shouldDeleteOriginal = rcc.RestoreConfig.OnCollision == control.Replace && !dci.IsFolder } // drive items do not support PUT requests on the drive item data, so @@ -850,7 +850,12 @@ func restoreFile( defer closeProgressBar() - dii := ir.AugmentItemInfo(details.ItemInfo{}, newItem, written, nil) + dii := ir.AugmentItemInfo( + details.ItemInfo{}, + rcc.ProtectedResource, + newItem, + written, + nil) if shouldDeleteOriginal { ctr.Inc(count.CollisionReplace) diff --git a/src/internal/m365/collection/site/backup.go b/src/internal/m365/collection/site/backup.go index 0ce62c14e..a168e6dba 100644 --- a/src/internal/m365/collection/site/backup.go +++ b/src/internal/m365/collection/site/backup.go @@ -38,7 +38,7 @@ func CollectLibraries( colls = drive.NewCollections( bh, tenantID, - bpc.ProtectedResource.ID(), + bpc.ProtectedResource, su, bpc.Options) ) diff --git a/src/internal/m365/controller.go b/src/internal/m365/controller.go index 3e0b3af93..6be0669dd 100644 --- a/src/internal/m365/controller.go +++ b/src/internal/m365/controller.go @@ -36,7 +36,7 @@ type Controller struct { tenant string credentials account.M365Config - ownerLookup getOwnerIDAndNamer + ownerLookup idname.GetResourceIDAndNamer // maps of resource owner ids to names, and names to ids. // not guaranteed to be populated, only here as a post-population // reference for processes that choose to populate the values. @@ -229,38 +229,24 @@ type getIDAndNamer interface { ) } -var _ getOwnerIDAndNamer = &resourceClient{} +var _ idname.GetResourceIDAndNamer = &resourceClient{} -type getOwnerIDAndNamer interface { - getOwnerIDAndNameFrom( - ctx context.Context, - discovery api.Client, - owner string, - ins idname.Cacher, - ) ( - ownerID string, - ownerName string, - err error, - ) -} - -// getOwnerIDAndNameFrom looks up the owner's canonical id and display name. -// If the owner is present in the idNameSwapper, then that interface's id and +// GetResourceIDAndNameFrom looks up the resource's canonical id and display name. +// If the resource is present in the idNameSwapper, then that interface's id and // name values are returned. As a fallback, the resource calls the discovery -// api to fetch the user or site using the owner value. This fallback assumes -// that the owner is a well formed ID or display name of appropriate design +// api to fetch the user or site using the resource value. This fallback assumes +// that the resource is a well formed ID or display name of appropriate design // (PrincipalName for users, WebURL for sites). -func (r resourceClient) getOwnerIDAndNameFrom( +func (r resourceClient) GetResourceIDAndNameFrom( ctx context.Context, - discovery api.Client, owner string, ins idname.Cacher, -) (string, string, error) { +) (idname.Provider, error) { if ins != nil { if n, ok := ins.NameOf(owner); ok { - return owner, n, nil + return idname.NewProvider(owner, n), nil } else if i, ok := ins.IDOf(owner); ok { - return i, owner, nil + return idname.NewProvider(i, owner), nil } } @@ -274,17 +260,17 @@ func (r resourceClient) getOwnerIDAndNameFrom( id, name, err = r.getter.GetIDAndName(ctx, owner, api.CallConfig{}) if err != nil { if graph.IsErrUserNotFound(err) { - return "", "", clues.Stack(graph.ErrResourceOwnerNotFound, err) + return nil, clues.Stack(graph.ErrResourceOwnerNotFound, err) } - return "", "", err + return nil, err } if len(id) == 0 || len(name) == 0 { - return "", "", clues.Stack(graph.ErrResourceOwnerNotFound) + return nil, clues.Stack(graph.ErrResourceOwnerNotFound) } - return id, name, nil + return idname.NewProvider(id, name), nil } // PopulateProtectedResourceIDAndName takes the provided owner identifier and produces @@ -297,15 +283,15 @@ func (r resourceClient) getOwnerIDAndNameFrom( // data gets stored inside the controller instance for later re-use. func (ctrl *Controller) PopulateProtectedResourceIDAndName( ctx context.Context, - owner string, // input value, can be either id or name + resourceID string, // input value, can be either id or name ins idname.Cacher, -) (string, string, error) { - id, name, err := ctrl.ownerLookup.getOwnerIDAndNameFrom(ctx, ctrl.AC, owner, ins) +) (idname.Provider, error) { + pr, err := ctrl.ownerLookup.GetResourceIDAndNameFrom(ctx, resourceID, ins) if err != nil { - return "", "", clues.Wrap(err, "identifying resource owner") + return nil, clues.Wrap(err, "identifying resource owner") } - ctrl.IDNameLookup = idname.NewCache(map[string]string{id: name}) + ctrl.IDNameLookup = idname.NewCache(map[string]string{pr.ID(): pr.Name()}) - return id, name, nil + return pr, nil } diff --git a/src/internal/m365/controller_test.go b/src/internal/m365/controller_test.go index d95a56c9f..7f9e52ea5 100644 --- a/src/internal/m365/controller_test.go +++ b/src/internal/m365/controller_test.go @@ -65,114 +65,126 @@ func (suite *ControllerUnitSuite) TestPopulateOwnerIDAndNamesFrom() { ) table := []struct { - name string - owner string - ins inMock.Cache - rc *resourceClient - expectID string - expectName string - expectErr require.ErrorAssertionFunc + name string + protectedResource string + ins inMock.Cache + rc *resourceClient + expectID string + expectName string + expectErr require.ErrorAssertionFunc + expectNil require.ValueAssertionFunc }{ { - name: "nil ins", - owner: id, - rc: lookup, - expectID: id, - expectName: name, - expectErr: require.NoError, + name: "nil ins", + protectedResource: id, + rc: lookup, + expectID: id, + expectName: name, + expectErr: require.NoError, + expectNil: require.NotNil, }, { - name: "nil ins no lookup", - owner: id, - rc: noLookup, - expectID: "", - expectName: "", - expectErr: require.Error, + name: "nil ins no lookup", + protectedResource: id, + rc: noLookup, + expectID: "", + expectName: "", + expectErr: require.Error, + expectNil: require.Nil, }, { - name: "only id map with owner id", - owner: id, - ins: inMock.NewCache(itn, nil), - rc: noLookup, - expectID: id, - expectName: name, - expectErr: require.NoError, + name: "only id map with owner id", + protectedResource: id, + ins: inMock.NewCache(itn, nil), + rc: noLookup, + expectID: id, + expectName: name, + expectErr: require.NoError, + expectNil: require.NotNil, }, { - name: "only name map with owner id", - owner: id, - ins: inMock.NewCache(nil, nti), - rc: noLookup, - expectID: "", - expectName: "", - expectErr: require.Error, + name: "only name map with owner id", + protectedResource: id, + ins: inMock.NewCache(nil, nti), + rc: noLookup, + expectID: "", + expectName: "", + expectErr: require.Error, + expectNil: require.Nil, }, { - name: "only name map with owner id and lookup", - owner: id, - ins: inMock.NewCache(nil, nti), - rc: lookup, - expectID: id, - expectName: name, - expectErr: require.NoError, + name: "only name map with owner id and lookup", + protectedResource: id, + ins: inMock.NewCache(nil, nti), + rc: lookup, + expectID: id, + expectName: name, + expectErr: require.NoError, + expectNil: require.NotNil, }, { - name: "only id map with owner name", - owner: name, - ins: inMock.NewCache(itn, nil), - rc: lookup, - expectID: id, - expectName: name, - expectErr: require.NoError, + name: "only id map with owner name", + protectedResource: name, + ins: inMock.NewCache(itn, nil), + rc: lookup, + expectID: id, + expectName: name, + expectErr: require.NoError, + expectNil: require.NotNil, }, { - name: "only name map with owner name", - owner: name, - ins: inMock.NewCache(nil, nti), - rc: noLookup, - expectID: id, - expectName: name, - expectErr: require.NoError, + name: "only name map with owner name", + protectedResource: name, + ins: inMock.NewCache(nil, nti), + rc: noLookup, + expectID: id, + expectName: name, + expectErr: require.NoError, + expectNil: require.NotNil, }, { - name: "only id map with owner name", - owner: name, - ins: inMock.NewCache(itn, nil), - rc: noLookup, - expectID: "", - expectName: "", - expectErr: require.Error, + name: "only id map with owner name", + protectedResource: name, + ins: inMock.NewCache(itn, nil), + rc: noLookup, + expectID: "", + expectName: "", + expectErr: require.Error, + expectNil: require.Nil, }, { - name: "only id map with owner name and lookup", - owner: name, - ins: inMock.NewCache(itn, nil), - rc: lookup, - expectID: id, - expectName: name, - expectErr: require.NoError, + name: "only id map with owner name and lookup", + protectedResource: name, + ins: inMock.NewCache(itn, nil), + rc: lookup, + expectID: id, + expectName: name, + expectErr: require.NoError, + expectNil: require.NotNil, }, { - name: "both maps with owner id", - owner: id, - ins: inMock.NewCache(itn, nti), - rc: noLookup, - expectID: id, - expectName: name, - expectErr: require.NoError, + name: "both maps with owner id", + protectedResource: id, + ins: inMock.NewCache(itn, nti), + rc: noLookup, + expectID: id, + expectName: name, + expectErr: require.NoError, + expectNil: require.NotNil, }, { - name: "both maps with owner name", - owner: name, - ins: inMock.NewCache(itn, nti), - rc: noLookup, - expectID: id, - expectName: name, - expectErr: require.NoError, + name: "both maps with owner name", + protectedResource: name, + ins: inMock.NewCache(itn, nti), + rc: noLookup, + expectID: id, + expectName: name, + expectErr: require.NoError, + expectNil: require.NotNil, }, { - name: "non-matching maps with owner id", - owner: id, + name: "non-matching maps with owner id", + protectedResource: id, ins: inMock.NewCache( map[string]string{"foo": "bar"}, map[string]string{"fnords": "smarf"}), @@ -180,10 +192,11 @@ func (suite *ControllerUnitSuite) TestPopulateOwnerIDAndNamesFrom() { expectID: "", expectName: "", expectErr: require.Error, + expectNil: require.Nil, }, { - name: "non-matching with owner name", - owner: name, + name: "non-matching with owner name", + protectedResource: name, ins: inMock.NewCache( map[string]string{"foo": "bar"}, map[string]string{"fnords": "smarf"}), @@ -191,10 +204,11 @@ func (suite *ControllerUnitSuite) TestPopulateOwnerIDAndNamesFrom() { expectID: "", expectName: "", expectErr: require.Error, + expectNil: require.Nil, }, { - name: "non-matching maps with owner id and lookup", - owner: id, + name: "non-matching maps with owner id and lookup", + protectedResource: id, ins: inMock.NewCache( map[string]string{"foo": "bar"}, map[string]string{"fnords": "smarf"}), @@ -202,10 +216,11 @@ func (suite *ControllerUnitSuite) TestPopulateOwnerIDAndNamesFrom() { expectID: id, expectName: name, expectErr: require.NoError, + expectNil: require.NotNil, }, { - name: "non-matching with owner name and lookup", - owner: name, + name: "non-matching with owner name and lookup", + protectedResource: name, ins: inMock.NewCache( map[string]string{"foo": "bar"}, map[string]string{"fnords": "smarf"}), @@ -213,6 +228,7 @@ func (suite *ControllerUnitSuite) TestPopulateOwnerIDAndNamesFrom() { expectID: id, expectName: name, expectErr: require.NoError, + expectNil: require.NotNil, }, } for _, test := range table { @@ -224,10 +240,16 @@ func (suite *ControllerUnitSuite) TestPopulateOwnerIDAndNamesFrom() { ctrl := &Controller{ownerLookup: test.rc} - rID, rName, err := ctrl.PopulateProtectedResourceIDAndName(ctx, test.owner, test.ins) + resource, err := ctrl.PopulateProtectedResourceIDAndName(ctx, test.protectedResource, test.ins) test.expectErr(t, err, clues.ToCore(err)) - assert.Equal(t, test.expectID, rID, "id") - assert.Equal(t, test.expectName, rName, "name") + test.expectNil(t, resource) + + if err != nil { + return + } + + assert.Equal(t, test.expectID, resource.ID(), "id") + assert.Equal(t, test.expectName, resource.Name(), "name") }) } } @@ -1362,15 +1384,15 @@ func (suite *ControllerIntegrationSuite) TestBackup_CreatesPrefixCollections() { start = time.Now() ) - id, name, err := backupCtrl.PopulateProtectedResourceIDAndName(ctx, backupSel.DiscreteOwner, nil) + resource, err := backupCtrl.PopulateProtectedResourceIDAndName(ctx, backupSel.DiscreteOwner, nil) require.NoError(t, err, clues.ToCore(err)) - backupSel.SetDiscreteOwnerIDName(id, name) + backupSel.SetDiscreteOwnerIDName(resource.ID(), resource.Name()) bpc := inject.BackupProducerConfig{ LastBackupVersion: version.NoBackup, Options: control.DefaultOptions(), - ProtectedResource: inMock.NewProvider(id, name), + ProtectedResource: resource, Selector: backupSel, } diff --git a/src/internal/m365/mock/connector.go b/src/internal/m365/mock/connector.go index 20d17eed1..ed04f1d3e 100644 --- a/src/internal/m365/mock/connector.go +++ b/src/internal/m365/mock/connector.go @@ -99,8 +99,7 @@ func (ctrl Controller) PopulateProtectedResourceIDAndName( ctx context.Context, protectedResource string, // input value, can be either id or name ins idname.Cacher, -) (string, string, error) { - return ctrl.ProtectedResourceID, - ctrl.ProtectedResourceName, +) (idname.Provider, error) { + return idname.NewProvider(ctrl.ProtectedResourceID, ctrl.ProtectedResourceName), ctrl.ProtectedResourceErr } diff --git a/src/internal/m365/service/groups/backup.go b/src/internal/m365/service/groups/backup.go index 25210ade3..0bb9a9b44 100644 --- a/src/internal/m365/service/groups/backup.go +++ b/src/internal/m365/service/groups/backup.go @@ -93,7 +93,7 @@ func ProduceBackupCollections( } for _, s := range sites { - pr := idname.NewProvider(ptr.Val(s.GetId()), ptr.Val(s.GetName())) + pr := idname.NewProvider(ptr.Val(s.GetId()), ptr.Val(s.GetWebUrl())) sbpc := inject.BackupProducerConfig{ LastBackupVersion: bpc.LastBackupVersion, Options: bpc.Options, diff --git a/src/internal/m365/service/onedrive/backup.go b/src/internal/m365/service/onedrive/backup.go index b94ce918d..8d159169c 100644 --- a/src/internal/m365/service/onedrive/backup.go +++ b/src/internal/m365/service/onedrive/backup.go @@ -51,7 +51,7 @@ func ProduceBackupCollections( nc := drive.NewCollections( drive.NewItemBackupHandler(ac.Drives(), bpc.ProtectedResource.ID(), scope), tenant, - bpc.ProtectedResource.ID(), + bpc.ProtectedResource, su, bpc.Options) diff --git a/src/internal/m365/service/onedrive/mock/handlers.go b/src/internal/m365/service/onedrive/mock/handlers.go index f0e0286d5..5d1b603b2 100644 --- a/src/internal/m365/service/onedrive/mock/handlers.go +++ b/src/internal/m365/service/onedrive/mock/handlers.go @@ -8,6 +8,7 @@ import ( "github.com/microsoftgraph/msgraph-sdk-go/drives" "github.com/microsoftgraph/msgraph-sdk-go/models" + "github.com/alcionai/corso/src/internal/common/idname" odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts" "github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/control" @@ -34,9 +35,9 @@ type BackupHandler struct { CanonPathFn canonPather CanonPathErr error - ResourceOwner string - Service path.ServiceType - Category path.CategoryType + ProtectedResource idname.Provider + Service path.ServiceType + Category path.CategoryType DrivePagerV api.Pager[models.Driveable] // driveID -> itemPager @@ -60,7 +61,7 @@ func DefaultOneDriveBH(resourceOwner string) *BackupHandler { PathPrefixFn: defaultOneDrivePathPrefixer, MetadataPathPrefixFn: defaultOneDriveMetadataPathPrefixer, CanonPathFn: defaultOneDriveCanonPather, - ResourceOwner: resourceOwner, + ProtectedResource: idname.NewProvider(resourceOwner, resourceOwner), Service: path.OneDriveService, Category: path.FilesCategory, LocationIDFn: defaultOneDriveLocationIDer, @@ -80,7 +81,7 @@ func DefaultSharePointBH(resourceOwner string) *BackupHandler { PathPrefixFn: defaultSharePointPathPrefixer, MetadataPathPrefixFn: defaultSharePointMetadataPathPrefixer, CanonPathFn: defaultSharePointCanonPather, - ResourceOwner: resourceOwner, + ProtectedResource: idname.NewProvider(resourceOwner, resourceOwner), Service: path.SharePointService, Category: path.LibrariesCategory, LocationIDFn: defaultSharePointLocationIDer, @@ -90,7 +91,7 @@ func DefaultSharePointBH(resourceOwner string) *BackupHandler { } func (h BackupHandler) PathPrefix(tID, driveID string) (path.Path, error) { - pp, err := h.PathPrefixFn(tID, h.ResourceOwner, driveID) + pp, err := h.PathPrefixFn(tID, h.ProtectedResource.ID(), driveID) if err != nil { return nil, err } @@ -99,7 +100,7 @@ func (h BackupHandler) PathPrefix(tID, driveID string) (path.Path, error) { } func (h BackupHandler) MetadataPathPrefix(tID string) (path.Path, error) { - pp, err := h.MetadataPathPrefixFn(tID, h.ResourceOwner) + pp, err := h.MetadataPathPrefixFn(tID, h.ProtectedResource.ID()) if err != nil { return nil, err } @@ -108,7 +109,7 @@ func (h BackupHandler) MetadataPathPrefix(tID string) (path.Path, error) { } func (h BackupHandler) CanonicalPath(pb *path.Builder, tID string) (path.Path, error) { - cp, err := h.CanonPathFn(pb, tID, h.ResourceOwner) + cp, err := h.CanonPathFn(pb, tID, h.ProtectedResource.ID()) if err != nil { return nil, err } @@ -136,7 +137,13 @@ func (h BackupHandler) NewLocationIDer(driveID string, elems ...string) details. return h.LocationIDFn(driveID, elems...) } -func (h BackupHandler) AugmentItemInfo(details.ItemInfo, models.DriveItemable, int64, *path.Builder) details.ItemInfo { +func (h BackupHandler) AugmentItemInfo( + details.ItemInfo, + idname.Provider, + models.DriveItemable, + int64, + *path.Builder, +) details.ItemInfo { return h.ItemInfo } @@ -308,6 +315,7 @@ func (h RestoreHandler) NewDrivePager(string, []string) api.Pager[models.Driveab func (h *RestoreHandler) AugmentItemInfo( details.ItemInfo, + idname.Provider, models.DriveItemable, int64, *path.Builder, diff --git a/src/internal/m365/service/sharepoint/backup_test.go b/src/internal/m365/service/sharepoint/backup_test.go index bcd37dd6b..cfed30567 100644 --- a/src/internal/m365/service/sharepoint/backup_test.go +++ b/src/internal/m365/service/sharepoint/backup_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "github.com/alcionai/corso/src/internal/common/idname" "github.com/alcionai/corso/src/internal/m365/collection/drive" odConsts "github.com/alcionai/corso/src/internal/m365/service/onedrive/consts" "github.com/alcionai/corso/src/internal/tester" @@ -103,7 +104,7 @@ func (suite *LibrariesBackupUnitSuite) TestUpdateCollections() { c := drive.NewCollections( drive.NewLibraryBackupHandler(api.Drives{}, siteID, test.scope, path.SharePointService), tenantID, - siteID, + idname.NewProvider(siteID, siteID), nil, control.DefaultOptions()) diff --git a/src/internal/operations/help_test.go b/src/internal/operations/help_test.go index 8bf863b64..11706bf01 100644 --- a/src/internal/operations/help_test.go +++ b/src/internal/operations/help_test.go @@ -34,7 +34,7 @@ func ControllerWithSelector( t.FailNow() } - id, name, err := ctrl.PopulateProtectedResourceIDAndName(ctx, sel.DiscreteOwner, ins) + resource, err := ctrl.PopulateProtectedResourceIDAndName(ctx, sel.DiscreteOwner, ins) if !assert.NoError(t, err, clues.ToCore(err)) { if onFail != nil { onFail() @@ -43,7 +43,7 @@ func ControllerWithSelector( t.FailNow() } - sel = sel.SetDiscreteOwnerIDName(id, name) + sel = sel.SetDiscreteOwnerIDName(resource.ID(), resource.Name()) return ctrl, sel } diff --git a/src/internal/operations/inject/inject.go b/src/internal/operations/inject/inject.go index e7b4ba228..92d74d334 100644 --- a/src/internal/operations/inject/inject.go +++ b/src/internal/operations/inject/inject.go @@ -109,10 +109,7 @@ type ( ctx context.Context, owner string, // input value, can be either id or name ins idname.Cacher, - ) ( - id, name string, - err error, - ) + ) (idname.Provider, error) } RepoMaintenancer interface { diff --git a/src/internal/operations/restore.go b/src/internal/operations/restore.go index dc05836e3..dcb387c03 100644 --- a/src/internal/operations/restore.go +++ b/src/internal/operations/restore.go @@ -362,12 +362,12 @@ func chooseRestoreResource( return orig, nil } - id, name, err := pprian.PopulateProtectedResourceIDAndName( + resource, err := pprian.PopulateProtectedResourceIDAndName( ctx, restoreCfg.ProtectedResource, nil) - return idname.NewProvider(id, name), clues.Stack(err).OrNil() + return resource, clues.Stack(err).OrNil() } // --------------------------------------------------------------------------- diff --git a/src/internal/operations/test/helper_test.go b/src/internal/operations/test/helper_test.go index 3cc10199a..6c1dde603 100644 --- a/src/internal/operations/test/helper_test.go +++ b/src/internal/operations/test/helper_test.go @@ -550,7 +550,7 @@ func ControllerWithSelector( t.FailNow() } - id, name, err := ctrl.PopulateProtectedResourceIDAndName(ctx, sel.DiscreteOwner, ins) + resource, err := ctrl.PopulateProtectedResourceIDAndName(ctx, sel.DiscreteOwner, ins) if !assert.NoError(t, err, clues.ToCore(err)) { if onFail != nil { onFail(t, ctx) @@ -559,7 +559,7 @@ func ControllerWithSelector( t.FailNow() } - sel = sel.SetDiscreteOwnerIDName(id, name) + sel = sel.SetDiscreteOwnerIDName(resource.ID(), resource.Name()) return ctrl, sel } diff --git a/src/pkg/repository/backups.go b/src/pkg/repository/backups.go index a4314eb01..51a5dee34 100644 --- a/src/pkg/repository/backups.go +++ b/src/pkg/repository/backups.go @@ -76,13 +76,13 @@ func (r repository) NewBackupWithLookup( return operations.BackupOperation{}, clues.Wrap(err, "connecting to m365") } - ownerID, ownerName, err := r.Provider.PopulateProtectedResourceIDAndName(ctx, sel.DiscreteOwner, ins) + resource, err := r.Provider.PopulateProtectedResourceIDAndName(ctx, sel.DiscreteOwner, ins) if err != nil { return operations.BackupOperation{}, clues.Wrap(err, "resolving resource owner details") } // TODO: retrieve display name from gc - sel = sel.SetDiscreteOwnerIDName(ownerID, ownerName) + sel = sel.SetDiscreteOwnerIDName(resource.ID(), resource.Name()) return operations.NewBackupOperation( ctx,