From 1cbabdb73a14854fc97fad87f835ab1edac5e7b7 Mon Sep 17 00:00:00 2001 From: ashmrtn <3891298+ashmrtn@users.noreply.github.com> Date: Thu, 16 Nov 2023 10:22:33 -0800 Subject: [PATCH] Exchange restore service level handler functions (#4693) Add service-level restore handlers for exchange --- #### Does this PR need a docs update or release note? - [ ] :white_check_mark: Yes, it's included - [ ] :clock1: Yes, but in a later PR - [x] :no_entry: No #### Type of change - [ ] :sunflower: Feature - [ ] :bug: Bugfix - [ ] :world_map: Documentation - [ ] :robot: Supportability/Tests - [ ] :computer: CI/Deployment - [x] :broom: Tech Debt/Cleanup #### Issue(s) * #4254 merge after: * #4687 * #4651 #### Test Plan - [ ] :muscle: Manual - [x] :zap: Unit test - [ ] :green_heart: E2E --- src/internal/m365/export.go | 2 +- src/internal/m365/service/exchange/export.go | 57 ++++++++++++++++++- .../m365/service/exchange/export_test.go | 3 +- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/internal/m365/export.go b/src/internal/m365/export.go index 30ef85b58..f4bad2dd6 100644 --- a/src/internal/m365/export.go +++ b/src/internal/m365/export.go @@ -31,7 +31,7 @@ func (ctrl *Controller) NewServiceHandler( return groups.NewGroupsHandler(opts, ctrl.AC, ctrl.resourceHandler), nil case path.ExchangeService: - return exchange.NewExchangeHandler(opts), nil + return exchange.NewExchangeHandler(opts, ctrl.AC, ctrl.resourceHandler), nil } return nil, clues.New("unrecognized service"). diff --git a/src/internal/m365/service/exchange/export.go b/src/internal/m365/service/exchange/export.go index 4cb194f8a..9562cf9ad 100644 --- a/src/internal/m365/service/exchange/export.go +++ b/src/internal/m365/service/exchange/export.go @@ -5,8 +5,10 @@ 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/exchange" + "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" @@ -14,18 +16,31 @@ 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 = &baseExchangeHandler{} func NewExchangeHandler( opts control.Options, -) *baseExchangeHandler { - return &baseExchangeHandler{ - opts: opts, + apiClient api.Client, + resourceClient idname.GetResourceIDAndNamer, +) *exchangeHandler { + return &exchangeHandler{ + baseExchangeHandler: baseExchangeHandler{ + opts: opts, + }, + apiClient: apiClient, + resourceClient: resourceClient, } } +// ========================================================================== // +// baseExchangeHandler +// ========================================================================== // + +// baseExchangeHandler contains logic for tracking data and doing operations +// (e.x. export) that don't require contact with external M356 services. type baseExchangeHandler struct { opts control.Options } @@ -72,3 +87,39 @@ func (h *baseExchangeHandler) ProduceExportCollections( return ec, el.Failure() } + +// ========================================================================== // +// exchangeHandler +// ========================================================================== // + +// exchangeHandler contains logic for handling data and performing operations +// (e.x. restore) regardless of whether they require contact with external M365 +// services or not. +type exchangeHandler struct { + baseExchangeHandler + apiClient api.Client + resourceClient idname.GetResourceIDAndNamer +} + +func (h *exchangeHandler) 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 *exchangeHandler) PopulateProtectedResourceIDAndName( + ctx context.Context, + resourceID string, // Can be either ID or name. + ins idname.Cacher, +) (idname.Provider, error) { + if h.resourceClient == nil { + return nil, clues.StackWC(ctx, resource.ErrNoResourceLookup) + } + + pr, err := h.resourceClient.GetResourceIDAndNameFrom(ctx, resourceID, ins) + + return pr, clues.Wrap(err, "identifying resource owner").OrNil() +} diff --git a/src/internal/m365/service/exchange/export_test.go b/src/internal/m365/service/exchange/export_test.go index cd7013008..cfae24096 100644 --- a/src/internal/m365/service/exchange/export_test.go +++ b/src/internal/m365/service/exchange/export_test.go @@ -19,6 +19,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 { @@ -373,7 +374,7 @@ func (suite *ExportUnitSuite) TestExportRestoreCollections() { exportCfg := control.ExportConfig{} stats := data.ExportStats{} - ecs, err := NewExchangeHandler(control.DefaultOptions()). + ecs, err := NewExchangeHandler(control.DefaultOptions(), api.Client{}, nil). ProduceExportCollections( ctx, int(version.Backup),