diff --git a/src/internal/operations/test/exchange_test.go b/src/internal/operations/test/exchange_test.go index fcddb0b42..db3beca94 100644 --- a/src/internal/operations/test/exchange_test.go +++ b/src/internal/operations/test/exchange_test.go @@ -697,6 +697,58 @@ func testExchangeContinuousBackups(suite *ExchangeBackupIntgSuite, toggles contr nonDeltaItemsWritten: 2, nonMetaItemsWritten: 6, }, + { + // Events and contacts have no Graph API call to move something between + // containers. The calendars web UI does support moving events between + // calendars though. + name: "boomerang an email", + updateUserData: func(t *testing.T, ctx context.Context) { + containerInfo := dataset[path.EmailCategory].dests[container1] + tempContainerID := dataset[path.EmailCategory].dests[container3].containerID + + ids := dataset[path.EmailCategory].dests[container1].itemRefs + require.NotEmpty(t, ids, "message ids in folder") + + oldID := ids[0] + + newID, err := ac.Mail().MoveItem( + ctx, + uidn.ID(), + containerInfo.containerID, + tempContainerID, + oldID) + require.NoError(t, err, "moving to temp folder: %s", clues.ToCore(err)) + + newID, err = ac.Mail().MoveItem( + ctx, + uidn.ID(), + tempContainerID, + containerInfo.containerID, + newID) + require.NoError(t, err, "moving back to original folder: %s", clues.ToCore(err)) + + expectDeets.RemoveItem( + path.EmailCategory.String(), + containerInfo.locRef, + oldID) + expectDeets.AddItem( + path.EmailCategory.String(), + containerInfo.locRef, + newID) + + // Will cause a different item to be deleted next. + containerInfo.itemRefs = append(containerInfo.itemRefs[1:], newID) + dataset[path.EmailCategory].dests[container1] = containerInfo + }, + // TODO(ashmrtn): Below values need updated when we start checking them + // again. Unclear what items would be considered the same as I'm not sure + // about all the properties that change with a move. + deltaItemsRead: 2, + deltaItemsWritten: 2, + nonDeltaItemsRead: 10, + nonDeltaItemsWritten: 2, + nonMetaItemsWritten: 6, + }, { name: "delete an existing item", updateUserData: func(t *testing.T, ctx context.Context) { diff --git a/src/internal/operations/test/onedrive_test.go b/src/internal/operations/test/onedrive_test.go index 2482dc0f4..d99268e34 100644 --- a/src/internal/operations/test/onedrive_test.go +++ b/src/internal/operations/test/onedrive_test.go @@ -517,6 +517,38 @@ func runDriveIncrementalTest( itemsWritten: 4, // .data and .meta for newitem, .dirmeta for parent nonMetaItemsWritten: 1, // .data file for new item }, + { + name: "boomerang a file", + updateFiles: func(t *testing.T, ctx context.Context) { + dest := containerInfos[container2] + temp := containerInfos[container1] + + driveItem := models.NewDriveItem() + parentRef := models.NewItemReference() + parentRef.SetId(&temp.id) + driveItem.SetParentReference(parentRef) + + err := ac.PatchItem( + ctx, + driveID, + ptr.Val(newFile.GetId()), + driveItem) + require.NoErrorf(t, err, "moving file to temporary folder %v", clues.ToCore(err)) + + parentRef.SetId(&dest.id) + driveItem.SetParentReference(parentRef) + + err = ac.PatchItem( + ctx, + driveID, + ptr.Val(newFile.GetId()), + driveItem) + require.NoErrorf(t, err, "moving file back to folder %v", clues.ToCore(err)) + }, + itemsRead: 1, // .data file for newitem + itemsWritten: 3, // .data and .meta for newitem, .dirmeta for parent + nonMetaItemsWritten: 1, // .data file for new item + }, { name: "delete file", updateFiles: func(t *testing.T, ctx context.Context) { diff --git a/src/pkg/services/m365/api/mail.go b/src/pkg/services/m365/api/mail.go index 13ddf8644..f4201ce5b 100644 --- a/src/pkg/services/m365/api/mail.go +++ b/src/pkg/services/m365/api/mail.go @@ -444,6 +444,30 @@ func (c Mail) PostItem( return itm, nil } +func (c Mail) MoveItem( + ctx context.Context, + userID, oldContainerID, newContainerID, itemID string, +) (string, error) { + body := users.NewItemMailFoldersItemMessagesItemMovePostRequestBody() + body.SetDestinationId(ptr.To(newContainerID)) + + resp, err := c.Stable. + Client(). + Users(). + ByUserId(userID). + MailFolders(). + ByMailFolderId(oldContainerID). + Messages(). + ByMessageId(itemID). + Move(). + Post(ctx, body, nil) + if err != nil { + return "", graph.Wrap(ctx, err, "moving message") + } + + return ptr.Val(resp.GetId()), nil +} + func (c Mail) DeleteItem( ctx context.Context, userID, itemID string,