Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

add teamschats restore shim for export support #5127

Merged
merged 1 commit into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions src/internal/m365/service/teamschats/restore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package teamschats

import (
"context"
"errors"

"github.com/alcionai/clues"

"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/internal/m365/support"
"github.com/alcionai/corso/src/internal/operations/inject"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/count"
"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/graph"
)

// ConsumeRestoreCollections will restore the specified data collections
func (h *teamsChatsHandler) ConsumeRestoreCollections(
ctx context.Context,
rcc inject.RestoreConsumerConfig,
dcs []data.RestoreCollection,
errs *fault.Bus,
ctr *count.Bus,
) (*details.Details, *data.CollectionStats, error) {
if len(dcs) == 0 {
return nil, nil, clues.WrapWC(ctx, data.ErrNoData, "performing restore")
}

// TODO(ashmrtn): We should stop relying on the context for rate limiter stuff
// and instead configure this when we make the handler instance. We can't
// initialize it in the NewHandler call right now because those functions
// aren't (and shouldn't be) returning a context along with the handler. Since
// that call isn't directly calling into this function even if we did
// initialize the rate limiter there it would be lost because it wouldn't get
// stored in an ancestor of the context passed to this function.
ctx = graph.BindRateLimiterConfig(
ctx,
graph.LimiterCfg{Service: path.TeamsChatsService})

var (
deets = &details.Builder{}
restoreMetrics support.CollectionMetrics
el = errs.Local()
)

// Reorder collections so that the parents directories are created
// before the child directories; a requirement for permissions.
data.SortRestoreCollections(dcs)

// Iterate through the data collections and restore the contents of each
for _, dc := range dcs {
if el.Failure() != nil {
break
}

var (
err error
category = dc.FullPath().Category()
metrics support.CollectionMetrics
ictx = clues.Add(ctx,
"category", category,
"restore_location", clues.Hide(rcc.RestoreConfig.Location),
"protected_resource", clues.Hide(dc.FullPath().ProtectedResource()),
"full_path", dc.FullPath())
)

switch dc.FullPath().Category() {
case path.ChatsCategory:
// chats cannot be restored using Graph API.
// a delegated token is required, and Corso has no
// good way of obtaining such a token.
logger.Ctx(ictx).Debug("Skipping restore for channel messages")
default:
return nil, nil, clues.NewWC(ictx, "data category not supported").
With("category", category)
}

restoreMetrics = support.CombineMetrics(restoreMetrics, metrics)

if err != nil {
el.AddRecoverable(ictx, err)
}

if errors.Is(err, context.Canceled) {
break
}
}

status := support.CreateStatus(
ctx,
support.Restore,
len(dcs),
restoreMetrics,
rcc.RestoreConfig.Location)

return deets.Details(), status.ToCollectionStats(), el.Failure()
}
54 changes: 54 additions & 0 deletions src/internal/m365/service/teamschats/restore_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package teamschats

import (
"testing"

"github.com/alcionai/clues"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"

"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/internal/data/mock"
"github.com/alcionai/corso/src/internal/operations/inject"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/fault"
"github.com/alcionai/corso/src/pkg/path"
"github.com/alcionai/corso/src/pkg/services/m365/api"
)

type RestoreUnitSuite struct {
tester.Suite
}

func TestRestoreUnitSuite(t *testing.T) {
suite.Run(t, &RestoreUnitSuite{Suite: tester.NewUnitSuite(t)})
}

func (suite *RestoreUnitSuite) TestConsumeRestoreCollections_noErrorOnChats() {
t := suite.T()

ctx, flush := tester.NewContext(t)
defer flush()

rcc := inject.RestoreConsumerConfig{}
pth, err := path.BuildPrefix(
"t",
"pr",
path.TeamsChatsService,
path.ChatsCategory)
require.NoError(t, err, clues.ToCore(err))

dcs := []data.RestoreCollection{
mock.Collection{Path: pth},
}

_, _, err = NewTeamsChatsHandler(api.Client{}, nil).
ConsumeRestoreCollections(
ctx,
rcc,
dcs,
fault.New(false),
nil)
assert.NoError(t, err, "Chats restore")
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ func makeRestorePathsForEntry(
// * OneDrive/SharePoint (needs drive information)
switch true {
case ent.Exchange != nil ||
ent.TeamsChats != nil ||
(ent.Groups != nil && ent.Groups.ItemType == details.GroupsChannelMessage) ||
(ent.SharePoint != nil && ent.SharePoint.ItemType == details.SharePointList):
// TODO(ashmrtn): Eventually make Events have it's own function to handle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,30 @@ func (suite *RestorePathTransformerUnitSuite) TestGetPaths() {
},
},
},
{
name: "TeamsChats Chats",
backupVersion: version.Groups9Update,
input: []*details.Entry{
{
RepoRef: testdata.ExchangeEmailItemPath3.RR.String(),
LocationRef: testdata.ExchangeEmailItemPath3.Loc.String(),
ItemInfo: details.ItemInfo{
Exchange: &details.ExchangeInfo{
ItemType: details.ExchangeMail,
},
},
},
},
expectErr: assert.NoError,
expected: []expectPaths{
{
storage: testdata.ExchangeEmailItemPath3.RR.String(),
restore: toRestore(
testdata.ExchangeEmailItemPath3.RR,
testdata.ExchangeEmailItemPath3.Loc.Elements()...),
},
},
},
}

for _, test := range table {
Expand Down
Loading