diff --git a/src/internal/m365/export.go b/src/internal/m365/export.go index 2c21d5363..7ec8de2da 100644 --- a/src/internal/m365/export.go +++ b/src/internal/m365/export.go @@ -21,13 +21,13 @@ func (ctrl *Controller) NewServiceHandler( switch service { case path.OneDriveService: - return onedrive.NewOneDriveHandler(opts), nil + return onedrive.NewOneDriveHandler(opts, ctrl.AC, ctrl.resourceHandler), nil case path.SharePointService: - return sharepoint.NewSharePointHandler(opts), nil + return sharepoint.NewSharePointHandler(opts, ctrl.AC, ctrl.resourceHandler), nil case path.GroupsService: - return groups.NewGroupsHandler(opts), nil + return groups.NewGroupsHandler(opts, ctrl.AC, ctrl.resourceHandler), nil } return nil, clues.New("unrecognized service"). diff --git a/src/internal/m365/resource/resource.go b/src/internal/m365/resource/resource.go index 6aca21924..57d1fef02 100644 --- a/src/internal/m365/resource/resource.go +++ b/src/internal/m365/resource/resource.go @@ -1,5 +1,9 @@ package resource +import "github.com/alcionai/clues" + +var ErrNoResourceLookup = clues.New("missing resource lookup client") + type Category string const ( diff --git a/src/internal/m365/service/groups/export.go b/src/internal/m365/service/groups/export.go index 163acfe1a..5bdc8c0a1 100644 --- a/src/internal/m365/service/groups/export.go +++ b/src/internal/m365/service/groups/export.go @@ -10,6 +10,7 @@ import ( "github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/internal/m365/collection/drive" "github.com/alcionai/corso/src/internal/m365/collection/groups" + "github.com/alcionai/corso/src/internal/m365/resource" "github.com/alcionai/corso/src/internal/operations/inject" "github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/control" @@ -17,20 +18,33 @@ import ( "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/logger" "github.com/alcionai/corso/src/pkg/path" + "github.com/alcionai/corso/src/pkg/services/m365/api" ) -var _ inject.ServiceHandler = &baseGroupsHandler{} +var _ inject.ServiceHandler = &groupsHandler{} func NewGroupsHandler( opts control.Options, -) *baseGroupsHandler { - return &baseGroupsHandler{ - opts: opts, - backupDriveIDNames: idname.NewCache(nil), - backupSiteIDWebURL: idname.NewCache(nil), + apiClient api.Client, + resourceGetter idname.GetResourceIDAndNamer, +) *groupsHandler { + return &groupsHandler{ + baseGroupsHandler: baseGroupsHandler{ + opts: opts, + backupDriveIDNames: idname.NewCache(nil), + backupSiteIDWebURL: idname.NewCache(nil), + }, + apiClient: apiClient, + resourceGetter: resourceGetter, } } +// ========================================================================== // +// baseGroupsHandler +// ========================================================================== // + +// baseGroupsHandler contains logic for tracking data and doing operations +// (e.x. export) that don't require contact with external M356 services. type baseGroupsHandler struct { opts control.Options @@ -134,3 +148,39 @@ func (h *baseGroupsHandler) ProduceExportCollections( return ec, el.Failure() } + +// ========================================================================== // +// groupsHandler +// ========================================================================== // + +// groupsHandler contains logic for handling data and performing operations +// (e.x. restore) regardless of whether they require contact with external M365 +// services or not. +type groupsHandler struct { + baseGroupsHandler + apiClient api.Client + resourceGetter idname.GetResourceIDAndNamer +} + +func (h *groupsHandler) IsServiceEnabled( + ctx context.Context, + resourceID string, +) (bool, error) { + // TODO(ashmrtn): Move free function implementation to this function. + res, err := IsServiceEnabled(ctx, h.apiClient.Groups(), resourceID) + return res, clues.Stack(err).OrNil() +} + +func (h *groupsHandler) PopulateProtectedResourceIDAndName( + ctx context.Context, + resourceID string, // Can be either ID or name. + ins idname.Cacher, +) (idname.Provider, error) { + if h.resourceGetter == nil { + return nil, clues.StackWC(ctx, resource.ErrNoResourceLookup) + } + + pr, err := h.resourceGetter.GetResourceIDAndNameFrom(ctx, resourceID, ins) + + return pr, clues.Wrap(err, "identifying resource owner").OrNil() +} diff --git a/src/internal/m365/service/groups/export_test.go b/src/internal/m365/service/groups/export_test.go index d2f1de8e2..a5a5aaa24 100644 --- a/src/internal/m365/service/groups/export_test.go +++ b/src/internal/m365/service/groups/export_test.go @@ -21,6 +21,7 @@ import ( "github.com/alcionai/corso/src/pkg/export" "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" + "github.com/alcionai/corso/src/pkg/services/m365/api" ) type ExportUnitSuite struct { @@ -96,7 +97,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections_messages() { stats := data.ExportStats{} - ecs, err := NewGroupsHandler(control.DefaultOptions()). + ecs, err := NewGroupsHandler(control.DefaultOptions(), api.Client{}, nil). ProduceExportCollections( ctx, int(version.Backup), @@ -196,7 +197,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections_libraries() { }, } - handler := NewGroupsHandler(control.DefaultOptions()) + handler := NewGroupsHandler(control.DefaultOptions(), api.Client{}, nil) handler.CacheItemInfo(dii) stats := data.ExportStats{} diff --git a/src/internal/m365/service/onedrive/export.go b/src/internal/m365/service/onedrive/export.go index 784e0e731..304e6b4a0 100644 --- a/src/internal/m365/service/onedrive/export.go +++ b/src/internal/m365/service/onedrive/export.go @@ -5,35 +5,58 @@ import ( "github.com/alcionai/clues" + "github.com/alcionai/corso/src/internal/common/idname" "github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/internal/m365/collection/drive" + "github.com/alcionai/corso/src/internal/m365/resource" "github.com/alcionai/corso/src/internal/operations/inject" "github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/control" "github.com/alcionai/corso/src/pkg/export" "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" + "github.com/alcionai/corso/src/pkg/services/m365/api" ) -var _ inject.ServiceHandler = &baseOnedriveHandler{} +var _ inject.ServiceHandler = &onedriveHandler{} func NewOneDriveHandler( opts control.Options, -) *baseOnedriveHandler { - return &baseOnedriveHandler{ - opts: opts, + apiClient api.Client, + resourceGetter idname.GetResourceIDAndNamer, +) *onedriveHandler { + return &onedriveHandler{ + baseOneDriveHandler: baseOneDriveHandler{ + opts: opts, + backupDriveIDNames: idname.NewCache(nil), + }, + apiClient: apiClient, + resourceGetter: resourceGetter, } } -type baseOnedriveHandler struct { - opts control.Options +// ========================================================================== // +// baseOneDriveHandler +// ========================================================================== // + +// baseOneDriveHandler contains logic for tracking data and doing operations +// (e.x. export) that don't require contact with external M356 services. +type baseOneDriveHandler struct { + opts control.Options + backupDriveIDNames idname.CacheBuilder } -func (h *baseOnedriveHandler) CacheItemInfo(v details.ItemInfo) {} +func (h *baseOneDriveHandler) CacheItemInfo(v details.ItemInfo) { + if v.OneDrive == nil { + return + } + + h.backupDriveIDNames.Add(v.OneDrive.DriveID, v.OneDrive.DriveName) +} // ProduceExportCollections will create the export collections for the // given restore collections. -func (h *baseOnedriveHandler) ProduceExportCollections( +func (h *baseOneDriveHandler) ProduceExportCollections( ctx context.Context, backupVersion int, exportCfg control.ExportConfig, @@ -65,3 +88,39 @@ func (h *baseOnedriveHandler) ProduceExportCollections( return ec, el.Failure() } + +// ========================================================================== // +// onedriveHandler +// ========================================================================== // + +// onedriveHandler contains logic for handling data and performing operations +// (e.x. restore) regardless of whether they require contact with external M365 +// services or not. +type onedriveHandler struct { + baseOneDriveHandler + apiClient api.Client + resourceGetter idname.GetResourceIDAndNamer +} + +func (h *onedriveHandler) IsServiceEnabled( + ctx context.Context, + resourceID string, +) (bool, error) { + // TODO(ashmrtn): Move free function implementation to this function. + res, err := IsServiceEnabled(ctx, h.apiClient.Users(), resourceID) + return res, clues.Stack(err).OrNil() +} + +func (h *onedriveHandler) PopulateProtectedResourceIDAndName( + ctx context.Context, + resourceID string, // Can be either ID or name. + ins idname.Cacher, +) (idname.Provider, error) { + if h.resourceGetter == nil { + return nil, clues.StackWC(ctx, resource.ErrNoResourceLookup) + } + + pr, err := h.resourceGetter.GetResourceIDAndNameFrom(ctx, resourceID, ins) + + return pr, clues.Wrap(err, "identifying resource owner").OrNil() +} diff --git a/src/internal/m365/service/onedrive/export_test.go b/src/internal/m365/service/onedrive/export_test.go index bf2cd5cfc..daaa0eaf0 100644 --- a/src/internal/m365/service/onedrive/export_test.go +++ b/src/internal/m365/service/onedrive/export_test.go @@ -20,6 +20,7 @@ import ( "github.com/alcionai/corso/src/pkg/export" "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" + "github.com/alcionai/corso/src/pkg/services/m365/api" ) type ExportUnitSuite struct { @@ -341,7 +342,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections() { stats := data.ExportStats{} - ecs, err := NewOneDriveHandler(control.DefaultOptions()). + ecs, err := NewOneDriveHandler(control.DefaultOptions(), api.Client{}, nil). ProduceExportCollections( ctx, int(version.Backup), diff --git a/src/internal/m365/service/sharepoint/export.go b/src/internal/m365/service/sharepoint/export.go index 99276d80b..bc5ff4009 100644 --- a/src/internal/m365/service/sharepoint/export.go +++ b/src/internal/m365/service/sharepoint/export.go @@ -8,6 +8,7 @@ import ( "github.com/alcionai/corso/src/internal/common/idname" "github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/internal/m365/collection/drive" + "github.com/alcionai/corso/src/internal/m365/resource" "github.com/alcionai/corso/src/internal/operations/inject" "github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/control" @@ -15,25 +16,38 @@ import ( "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/logger" "github.com/alcionai/corso/src/pkg/path" + "github.com/alcionai/corso/src/pkg/services/m365/api" ) -var _ inject.ServiceHandler = &baseSharepointHandler{} +var _ inject.ServiceHandler = &sharepointHandler{} func NewSharePointHandler( opts control.Options, -) *baseSharepointHandler { - return &baseSharepointHandler{ - opts: opts, - backupDriveIDNames: idname.NewCache(nil), + apiClient api.Client, + resourceGetter idname.GetResourceIDAndNamer, +) *sharepointHandler { + return &sharepointHandler{ + baseSharePointHandler: baseSharePointHandler{ + opts: opts, + backupDriveIDNames: idname.NewCache(nil), + }, + apiClient: apiClient, + resourceGetter: resourceGetter, } } -type baseSharepointHandler struct { +// ========================================================================== // +// baseSharePointHandler +// ========================================================================== // + +// baseSharePointHandler contains logic for tracking data and doing operations +// (e.x. export) that don't require contact with external M356 services. +type baseSharePointHandler struct { opts control.Options backupDriveIDNames idname.CacheBuilder } -func (h *baseSharepointHandler) CacheItemInfo(v details.ItemInfo) { +func (h *baseSharePointHandler) CacheItemInfo(v details.ItemInfo) { // Old versions would store SharePoint data as OneDrive. switch { case v.SharePoint != nil: @@ -46,7 +60,7 @@ func (h *baseSharepointHandler) CacheItemInfo(v details.ItemInfo) { // ProduceExportCollections will create the export collections for the // given restore collections. -func (h *baseSharepointHandler) ProduceExportCollections( +func (h *baseSharePointHandler) ProduceExportCollections( ctx context.Context, backupVersion int, exportCfg control.ExportConfig, @@ -88,3 +102,39 @@ func (h *baseSharepointHandler) ProduceExportCollections( return ec, el.Failure() } + +// ========================================================================== // +// sharepointHandler +// ========================================================================== // + +// sharepointHandler contains logic for handling data and performing operations +// (e.x. restore) regardless of whether they require contact with external M365 +// services or not. +type sharepointHandler struct { + baseSharePointHandler + apiClient api.Client + resourceGetter idname.GetResourceIDAndNamer +} + +func (h *sharepointHandler) IsServiceEnabled( + ctx context.Context, + resourceID string, +) (bool, error) { + // TODO(ashmrtn): Move free function implementation to this function. + res, err := IsServiceEnabled(ctx, h.apiClient.Sites(), resourceID) + return res, clues.Stack(err).OrNil() +} + +func (h *sharepointHandler) PopulateProtectedResourceIDAndName( + ctx context.Context, + resourceID string, // Can be either ID or name. + ins idname.Cacher, +) (idname.Provider, error) { + if h.resourceGetter == nil { + return nil, clues.StackWC(ctx, resource.ErrNoResourceLookup) + } + + pr, err := h.resourceGetter.GetResourceIDAndNameFrom(ctx, resourceID, ins) + + return pr, clues.Wrap(err, "identifying resource owner").OrNil() +} diff --git a/src/internal/m365/service/sharepoint/export_test.go b/src/internal/m365/service/sharepoint/export_test.go index 4b2ea2521..a33655a51 100644 --- a/src/internal/m365/service/sharepoint/export_test.go +++ b/src/internal/m365/service/sharepoint/export_test.go @@ -20,6 +20,7 @@ import ( "github.com/alcionai/corso/src/pkg/export" "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" + "github.com/alcionai/corso/src/pkg/services/m365/api" ) type ExportUnitSuite struct { @@ -125,7 +126,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections() { }, } - handler := NewSharePointHandler(control.DefaultOptions()) + handler := NewSharePointHandler(control.DefaultOptions(), api.Client{}, nil) handler.CacheItemInfo(test.itemInfo) stats := data.ExportStats{}