Add immutable ID header to Get requests (#3157)
This allows using immutable IDs for Exchange objects. It does not add this header to put requests as we don't record the IDs of restored objects anywhere. May slightly increase performance of events backups as it now sets the delta query page size to 200 like with other requests --- #### Does this PR need a docs update or release note? - [ ] ✅ Yes, it's included - [ ] 🕐 Yes, but in a later PR - [x] ⛔ No #### Type of change - [x] 🌻 Feature - [ ] 🐛 Bugfix - [ ] 🗺️ Documentation - [ ] 🤖 Supportability/Tests - [ ] 💻 CI/Deployment - [ ] 🧹 Tech Debt/Cleanup #### Issue(s) * #2861 #### Test Plan - [x] 💪 Manual - [ ] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
9664afaa12
commit
ba724ac63d
@ -98,11 +98,11 @@ func runDisplayM365JSON(
|
|||||||
|
|
||||||
switch cat {
|
switch cat {
|
||||||
case path.EmailCategory:
|
case path.EmailCategory:
|
||||||
bs, err = getItem(ctx, ac.Mail(), user, itemID, errs)
|
bs, err = getItem(ctx, ac.Mail(), user, itemID, true, errs)
|
||||||
case path.EventsCategory:
|
case path.EventsCategory:
|
||||||
bs, err = getItem(ctx, ac.Events(), user, itemID, errs)
|
bs, err = getItem(ctx, ac.Events(), user, itemID, true, errs)
|
||||||
case path.ContactsCategory:
|
case path.ContactsCategory:
|
||||||
bs, err = getItem(ctx, ac.Contacts(), user, itemID, errs)
|
bs, err = getItem(ctx, ac.Contacts(), user, itemID, true, errs)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unable to process category: %s", cat)
|
return fmt.Errorf("unable to process category: %s", cat)
|
||||||
}
|
}
|
||||||
@ -132,6 +132,7 @@ type itemer interface {
|
|||||||
GetItem(
|
GetItem(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
user, itemID string,
|
user, itemID string,
|
||||||
|
immutableID bool,
|
||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
) (serialization.Parsable, *details.ExchangeInfo, error)
|
) (serialization.Parsable, *details.ExchangeInfo, error)
|
||||||
Serialize(
|
Serialize(
|
||||||
@ -145,9 +146,10 @@ func getItem(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
itm itemer,
|
itm itemer,
|
||||||
user, itemID string,
|
user, itemID string,
|
||||||
|
immutableIDs bool,
|
||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
) ([]byte, error) {
|
) ([]byte, error) {
|
||||||
sp, _, err := itm.GetItem(ctx, user, itemID, errs)
|
sp, _, err := itm.GetItem(ctx, user, itemID, immutableIDs, errs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, clues.Wrap(err, "getting item")
|
return nil, clues.Wrap(err, "getting item")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,9 +79,14 @@ func (c Contacts) DeleteContainer(
|
|||||||
func (c Contacts) GetItem(
|
func (c Contacts) GetItem(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
user, itemID string,
|
user, itemID string,
|
||||||
|
immutableIDs bool,
|
||||||
_ *fault.Bus, // no attachments to iterate over, so this goes unused
|
_ *fault.Bus, // no attachments to iterate over, so this goes unused
|
||||||
) (serialization.Parsable, *details.ExchangeInfo, error) {
|
) (serialization.Parsable, *details.ExchangeInfo, error) {
|
||||||
cont, err := c.Stable.Client().UsersById(user).ContactsById(itemID).Get(ctx, nil)
|
options := &users.ItemContactsContactItemRequestBuilderGetRequestConfiguration{
|
||||||
|
Headers: buildPreferHeaders(false, immutableIDs),
|
||||||
|
}
|
||||||
|
|
||||||
|
cont, err := c.Stable.Client().UsersById(user).ContactsById(itemID).Get(ctx, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, graph.Stack(ctx, err)
|
return nil, nil, graph.Stack(ctx, err)
|
||||||
}
|
}
|
||||||
@ -210,6 +215,7 @@ func (p *contactPager) valuesIn(pl api.DeltaPageLinker) ([]getIDAndAddtler, erro
|
|||||||
func (c Contacts) GetAddedAndRemovedItemIDs(
|
func (c Contacts) GetAddedAndRemovedItemIDs(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
user, directoryID, oldDelta string,
|
user, directoryID, oldDelta string,
|
||||||
|
immutableIDs bool,
|
||||||
) ([]string, []string, DeltaUpdate, error) {
|
) ([]string, []string, DeltaUpdate, error) {
|
||||||
service, err := c.service()
|
service, err := c.service()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -223,7 +229,9 @@ func (c Contacts) GetAddedAndRemovedItemIDs(
|
|||||||
"category", selectors.ExchangeContact,
|
"category", selectors.ExchangeContact,
|
||||||
"container_id", directoryID)
|
"container_id", directoryID)
|
||||||
|
|
||||||
options, err := optionsForContactFoldersItemDelta([]string{"parentFolderId"})
|
options, err := optionsForContactFoldersItemDelta(
|
||||||
|
[]string{"parentFolderId"},
|
||||||
|
immutableIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil,
|
return nil,
|
||||||
nil,
|
nil,
|
||||||
|
|||||||
@ -103,14 +103,19 @@ func (c Events) GetContainerByID(
|
|||||||
func (c Events) GetItem(
|
func (c Events) GetItem(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
user, itemID string,
|
user, itemID string,
|
||||||
|
immutableIDs bool,
|
||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
) (serialization.Parsable, *details.ExchangeInfo, error) {
|
) (serialization.Parsable, *details.ExchangeInfo, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
event models.Eventable
|
event models.Eventable
|
||||||
|
header = buildPreferHeaders(false, immutableIDs)
|
||||||
|
itemOpts = &users.ItemEventsEventItemRequestBuilderGetRequestConfiguration{
|
||||||
|
Headers: header,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
event, err = c.Stable.Client().UsersById(user).EventsById(itemID).Get(ctx, nil)
|
event, err = c.Stable.Client().UsersById(user).EventsById(itemID).Get(ctx, itemOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, graph.Stack(ctx, err)
|
return nil, nil, graph.Stack(ctx, err)
|
||||||
}
|
}
|
||||||
@ -120,6 +125,7 @@ func (c Events) GetItem(
|
|||||||
QueryParameters: &users.ItemEventsItemAttachmentsRequestBuilderGetQueryParameters{
|
QueryParameters: &users.ItemEventsItemAttachmentsRequestBuilderGetQueryParameters{
|
||||||
Expand: []string{"microsoft.graph.itemattachment/item"},
|
Expand: []string{"microsoft.graph.itemattachment/item"},
|
||||||
},
|
},
|
||||||
|
Headers: header,
|
||||||
}
|
}
|
||||||
|
|
||||||
attached, err := c.LargeItem.
|
attached, err := c.LargeItem.
|
||||||
@ -245,13 +251,19 @@ func (p *eventPager) valuesIn(pl api.DeltaPageLinker) ([]getIDAndAddtler, error)
|
|||||||
func (c Events) GetAddedAndRemovedItemIDs(
|
func (c Events) GetAddedAndRemovedItemIDs(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
user, calendarID, oldDelta string,
|
user, calendarID, oldDelta string,
|
||||||
|
immutableIDs bool,
|
||||||
) ([]string, []string, DeltaUpdate, error) {
|
) ([]string, []string, DeltaUpdate, error) {
|
||||||
service, err := c.service()
|
service, err := c.service()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, DeltaUpdate{}, err
|
return nil, nil, DeltaUpdate{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var resetDelta bool
|
var (
|
||||||
|
resetDelta bool
|
||||||
|
opts = &users.ItemCalendarsItemEventsDeltaRequestBuilderGetRequestConfiguration{
|
||||||
|
Headers: buildPreferHeaders(true, immutableIDs),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
ctx = clues.Add(
|
ctx = clues.Add(
|
||||||
ctx,
|
ctx,
|
||||||
@ -260,7 +272,7 @@ func (c Events) GetAddedAndRemovedItemIDs(
|
|||||||
if len(oldDelta) > 0 {
|
if len(oldDelta) > 0 {
|
||||||
var (
|
var (
|
||||||
builder = users.NewItemCalendarsItemEventsDeltaRequestBuilder(oldDelta, service.Adapter())
|
builder = users.NewItemCalendarsItemEventsDeltaRequestBuilder(oldDelta, service.Adapter())
|
||||||
pgr = &eventPager{service, builder, nil}
|
pgr = &eventPager{service, builder, opts}
|
||||||
)
|
)
|
||||||
|
|
||||||
added, removed, deltaURL, err := getItemsAddedAndRemovedFromContainer(ctx, pgr)
|
added, removed, deltaURL, err := getItemsAddedAndRemovedFromContainer(ctx, pgr)
|
||||||
@ -287,7 +299,7 @@ func (c Events) GetAddedAndRemovedItemIDs(
|
|||||||
// works as intended (until, at least, we want to _not_ call the beta anymore).
|
// works as intended (until, at least, we want to _not_ call the beta anymore).
|
||||||
rawURL := fmt.Sprintf(eventBetaDeltaURLTemplate, user, calendarID)
|
rawURL := fmt.Sprintf(eventBetaDeltaURLTemplate, user, calendarID)
|
||||||
builder := users.NewItemCalendarsItemEventsDeltaRequestBuilder(rawURL, service.Adapter())
|
builder := users.NewItemCalendarsItemEventsDeltaRequestBuilder(rawURL, service.Adapter())
|
||||||
pgr := &eventPager{service, builder, nil}
|
pgr := &eventPager{service, builder, opts}
|
||||||
|
|
||||||
if len(os.Getenv("CORSO_URL_LOGGING")) > 0 {
|
if len(os.Getenv("CORSO_URL_LOGGING")) > 0 {
|
||||||
gri, err := builder.ToGetRequestInformation(ctx, nil)
|
gri, err := builder.ToGetRequestInformation(ctx, nil)
|
||||||
|
|||||||
@ -131,9 +131,16 @@ func (c Mail) GetContainerByID(
|
|||||||
func (c Mail) GetItem(
|
func (c Mail) GetItem(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
user, itemID string,
|
user, itemID string,
|
||||||
|
immutableIDs bool,
|
||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
) (serialization.Parsable, *details.ExchangeInfo, error) {
|
) (serialization.Parsable, *details.ExchangeInfo, error) {
|
||||||
mail, err := c.Stable.Client().UsersById(user).MessagesById(itemID).Get(ctx, nil)
|
// Will need adjusted if attachments start allowing paging.
|
||||||
|
headers := buildPreferHeaders(false, immutableIDs)
|
||||||
|
itemOpts := &users.ItemMessagesMessageItemRequestBuilderGetRequestConfiguration{
|
||||||
|
Headers: headers,
|
||||||
|
}
|
||||||
|
|
||||||
|
mail, err := c.Stable.Client().UsersById(user).MessagesById(itemID).Get(ctx, itemOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, graph.Stack(ctx, err)
|
return nil, nil, graph.Stack(ctx, err)
|
||||||
}
|
}
|
||||||
@ -146,6 +153,7 @@ func (c Mail) GetItem(
|
|||||||
QueryParameters: &users.ItemMessagesItemAttachmentsRequestBuilderGetQueryParameters{
|
QueryParameters: &users.ItemMessagesItemAttachmentsRequestBuilderGetQueryParameters{
|
||||||
Expand: []string{"microsoft.graph.itemattachment/item"},
|
Expand: []string{"microsoft.graph.itemattachment/item"},
|
||||||
},
|
},
|
||||||
|
Headers: headers,
|
||||||
}
|
}
|
||||||
|
|
||||||
attached, err := c.LargeItem.
|
attached, err := c.LargeItem.
|
||||||
@ -190,6 +198,7 @@ func (c Mail) GetItem(
|
|||||||
QueryParameters: &users.ItemMessagesItemAttachmentsAttachmentItemRequestBuilderGetQueryParameters{
|
QueryParameters: &users.ItemMessagesItemAttachmentsAttachmentItemRequestBuilderGetQueryParameters{
|
||||||
Expand: []string{"microsoft.graph.itemattachment/item"},
|
Expand: []string{"microsoft.graph.itemattachment/item"},
|
||||||
},
|
},
|
||||||
|
Headers: headers,
|
||||||
}
|
}
|
||||||
|
|
||||||
att, err := c.Stable.
|
att, err := c.Stable.
|
||||||
@ -304,6 +313,7 @@ func (p *mailPager) valuesIn(pl api.DeltaPageLinker) ([]getIDAndAddtler, error)
|
|||||||
func (c Mail) GetAddedAndRemovedItemIDs(
|
func (c Mail) GetAddedAndRemovedItemIDs(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
user, directoryID, oldDelta string,
|
user, directoryID, oldDelta string,
|
||||||
|
immutableIDs bool,
|
||||||
) ([]string, []string, DeltaUpdate, error) {
|
) ([]string, []string, DeltaUpdate, error) {
|
||||||
service, err := c.service()
|
service, err := c.service()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -320,7 +330,7 @@ func (c Mail) GetAddedAndRemovedItemIDs(
|
|||||||
"category", selectors.ExchangeMail,
|
"category", selectors.ExchangeMail,
|
||||||
"container_id", directoryID)
|
"container_id", directoryID)
|
||||||
|
|
||||||
options, err := optionsForFolderMessagesDelta([]string{"isRead"})
|
options, err := optionsForFolderMessagesDelta([]string{"isRead"}, immutableIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil,
|
return nil,
|
||||||
nil,
|
nil,
|
||||||
|
|||||||
@ -342,7 +342,7 @@ func (suite *MailAPIE2ESuite) TestHugeAttachmentListDownload() {
|
|||||||
defer gock.Off()
|
defer gock.Off()
|
||||||
tt.setupf()
|
tt.setupf()
|
||||||
|
|
||||||
item, _, err := suite.ac.Mail().GetItem(ctx, "user", mid, fault.New(true))
|
item, _, err := suite.ac.Mail().GetItem(ctx, "user", mid, false, fault.New(true))
|
||||||
tt.expect(suite.T(), err)
|
tt.expect(suite.T(), err)
|
||||||
|
|
||||||
it, ok := item.(models.Messageable)
|
it, ok := item.(models.Messageable)
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/alcionai/clues"
|
"github.com/alcionai/clues"
|
||||||
abstractions "github.com/microsoft/kiota-abstractions-go"
|
abstractions "github.com/microsoft/kiota-abstractions-go"
|
||||||
@ -63,6 +64,8 @@ const (
|
|||||||
maxPageSizeHeaderFmt = "odata.maxpagesize=%d"
|
maxPageSizeHeaderFmt = "odata.maxpagesize=%d"
|
||||||
// deltaMaxPageSize is the max page size to use for delta queries
|
// deltaMaxPageSize is the max page size to use for delta queries
|
||||||
deltaMaxPageSize = 200
|
deltaMaxPageSize = 200
|
||||||
|
idTypeFmt = "IdType=%q"
|
||||||
|
immutableIDType = "ImmutableId"
|
||||||
)
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
@ -74,6 +77,7 @@ const (
|
|||||||
|
|
||||||
func optionsForFolderMessagesDelta(
|
func optionsForFolderMessagesDelta(
|
||||||
moreOps []string,
|
moreOps []string,
|
||||||
|
immutableIDs bool,
|
||||||
) (*users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration, error) {
|
) (*users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration, error) {
|
||||||
selecting, err := buildOptions(moreOps, fieldsForMessages)
|
selecting, err := buildOptions(moreOps, fieldsForMessages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -86,7 +90,7 @@ func optionsForFolderMessagesDelta(
|
|||||||
|
|
||||||
options := &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration{
|
options := &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration{
|
||||||
QueryParameters: requestParameters,
|
QueryParameters: requestParameters,
|
||||||
Headers: buildDeltaRequestHeaders(),
|
Headers: buildPreferHeaders(true, immutableIDs),
|
||||||
}
|
}
|
||||||
|
|
||||||
return options, nil
|
return options, nil
|
||||||
@ -178,6 +182,7 @@ func optionsForMailFoldersItem(
|
|||||||
|
|
||||||
func optionsForContactFoldersItemDelta(
|
func optionsForContactFoldersItemDelta(
|
||||||
moreOps []string,
|
moreOps []string,
|
||||||
|
immutableIDs bool,
|
||||||
) (*users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration, error) {
|
) (*users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration, error) {
|
||||||
selecting, err := buildOptions(moreOps, fieldsForContacts)
|
selecting, err := buildOptions(moreOps, fieldsForContacts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -190,7 +195,7 @@ func optionsForContactFoldersItemDelta(
|
|||||||
|
|
||||||
options := &users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration{
|
options := &users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration{
|
||||||
QueryParameters: requestParameters,
|
QueryParameters: requestParameters,
|
||||||
Headers: buildDeltaRequestHeaders(),
|
Headers: buildPreferHeaders(true, immutableIDs),
|
||||||
}
|
}
|
||||||
|
|
||||||
return options, nil
|
return options, nil
|
||||||
@ -231,10 +236,21 @@ func buildOptions(fields []string, allowed map[string]struct{}) ([]string, error
|
|||||||
return append(returnedOptions, fields...), nil
|
return append(returnedOptions, fields...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildDeltaRequestHeaders returns the headers we add to delta page requests
|
// buildPreferHeaders returns the headers we add to item delta page
|
||||||
func buildDeltaRequestHeaders() *abstractions.RequestHeaders {
|
// requests.
|
||||||
|
func buildPreferHeaders(pageSize, immutableID bool) *abstractions.RequestHeaders {
|
||||||
|
var allHeaders []string
|
||||||
|
|
||||||
|
if pageSize {
|
||||||
|
allHeaders = append(allHeaders, fmt.Sprintf(maxPageSizeHeaderFmt, deltaMaxPageSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
if immutableID {
|
||||||
|
allHeaders = append(allHeaders, fmt.Sprintf(idTypeFmt, immutableIDType))
|
||||||
|
}
|
||||||
|
|
||||||
headers := abstractions.NewRequestHeaders()
|
headers := abstractions.NewRequestHeaders()
|
||||||
headers.Add(headerKeyPrefer, fmt.Sprintf(maxPageSizeHeaderFmt, deltaMaxPageSize))
|
headers.Add(headerKeyPrefer, strings.Join(allHeaders, ","))
|
||||||
|
|
||||||
return headers
|
return headers
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,6 +45,7 @@ type itemer interface {
|
|||||||
GetItem(
|
GetItem(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
user, itemID string,
|
user, itemID string,
|
||||||
|
immutableIDs bool,
|
||||||
errs *fault.Bus,
|
errs *fault.Bus,
|
||||||
) (serialization.Parsable, *details.ExchangeInfo, error)
|
) (serialization.Parsable, *details.ExchangeInfo, error)
|
||||||
Serialize(
|
Serialize(
|
||||||
@ -256,6 +257,7 @@ func (col *Collection) streamItems(ctx context.Context, errs *fault.Bus) {
|
|||||||
ctx,
|
ctx,
|
||||||
user,
|
user,
|
||||||
id,
|
id,
|
||||||
|
col.ctrl.ToggleFeatures.ExchangeImmutableIDs,
|
||||||
fault.New(true)) // temporary way to force a failFast error
|
fault.New(true)) // temporary way to force a failFast error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Don't report errors for deleted items as there's no way for us to
|
// Don't report errors for deleted items as there's no way for us to
|
||||||
|
|||||||
@ -30,6 +30,7 @@ type mockItemer struct {
|
|||||||
func (mi *mockItemer) GetItem(
|
func (mi *mockItemer) GetItem(
|
||||||
context.Context,
|
context.Context,
|
||||||
string, string,
|
string, string,
|
||||||
|
bool,
|
||||||
*fault.Bus,
|
*fault.Bus,
|
||||||
) (serialization.Parsable, *details.ExchangeInfo, error) {
|
) (serialization.Parsable, *details.ExchangeInfo, error) {
|
||||||
mi.getCount++
|
mi.getCount++
|
||||||
@ -228,7 +229,7 @@ func (suite *ExchangeDataCollectionSuite) TestGetItemWithRetries() {
|
|||||||
defer flush()
|
defer flush()
|
||||||
|
|
||||||
// itemer is mocked, so only the errors are configured atm.
|
// itemer is mocked, so only the errors are configured atm.
|
||||||
_, _, err := test.items.GetItem(ctx, "userID", "itemID", fault.New(true))
|
_, _, err := test.items.GetItem(ctx, "userID", "itemID", false, fault.New(true))
|
||||||
test.expectErr(suite.T(), err)
|
test.expectErr(suite.T(), err)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ type addedAndRemovedItemIDsGetter interface {
|
|||||||
GetAddedAndRemovedItemIDs(
|
GetAddedAndRemovedItemIDs(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
user, containerID, oldDeltaToken string,
|
user, containerID, oldDeltaToken string,
|
||||||
|
immutableIDs bool,
|
||||||
) ([]string, []string, api.DeltaUpdate, error)
|
) ([]string, []string, api.DeltaUpdate, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +109,12 @@ func filterContainersAndFillCollections(
|
|||||||
|
|
||||||
ictx = clues.Add(ictx, "previous_path", prevPath)
|
ictx = clues.Add(ictx, "previous_path", prevPath)
|
||||||
|
|
||||||
added, removed, newDelta, err := getter.GetAddedAndRemovedItemIDs(ictx, qp.ResourceOwner.ID(), cID, prevDelta)
|
added, removed, newDelta, err := getter.GetAddedAndRemovedItemIDs(
|
||||||
|
ictx,
|
||||||
|
qp.ResourceOwner.ID(),
|
||||||
|
cID,
|
||||||
|
prevDelta,
|
||||||
|
ctrlOpts.ToggleFeatures.ExchangeImmutableIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !graph.IsErrDeletedInFlight(err) {
|
if !graph.IsErrDeletedInFlight(err) {
|
||||||
el.AddRecoverable(clues.Stack(err).Label(fault.LabelForceNoBackupCreation))
|
el.AddRecoverable(clues.Stack(err).Label(fault.LabelForceNoBackupCreation))
|
||||||
|
|||||||
@ -41,6 +41,7 @@ type (
|
|||||||
func (mg mockGetter) GetAddedAndRemovedItemIDs(
|
func (mg mockGetter) GetAddedAndRemovedItemIDs(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
userID, cID, prevDelta string,
|
userID, cID, prevDelta string,
|
||||||
|
_ bool,
|
||||||
) (
|
) (
|
||||||
[]string,
|
[]string,
|
||||||
[]string,
|
[]string,
|
||||||
|
|||||||
@ -1078,7 +1078,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_exchangeIncrementals() {
|
|||||||
|
|
||||||
switch category {
|
switch category {
|
||||||
case path.EmailCategory:
|
case path.EmailCategory:
|
||||||
ids, _, _, err := ac.Mail().GetAddedAndRemovedItemIDs(ctx, suite.user, containerID, "")
|
ids, _, _, err := ac.Mail().GetAddedAndRemovedItemIDs(ctx, suite.user, containerID, "", false)
|
||||||
require.NoError(t, err, "getting message ids", clues.ToCore(err))
|
require.NoError(t, err, "getting message ids", clues.ToCore(err))
|
||||||
require.NotEmpty(t, ids, "message ids in folder")
|
require.NotEmpty(t, ids, "message ids in folder")
|
||||||
|
|
||||||
@ -1086,7 +1086,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_exchangeIncrementals() {
|
|||||||
require.NoError(t, err, "deleting email item", clues.ToCore(err))
|
require.NoError(t, err, "deleting email item", clues.ToCore(err))
|
||||||
|
|
||||||
case path.ContactsCategory:
|
case path.ContactsCategory:
|
||||||
ids, _, _, err := ac.Contacts().GetAddedAndRemovedItemIDs(ctx, suite.user, containerID, "")
|
ids, _, _, err := ac.Contacts().GetAddedAndRemovedItemIDs(ctx, suite.user, containerID, "", false)
|
||||||
require.NoError(t, err, "getting contact ids", clues.ToCore(err))
|
require.NoError(t, err, "getting contact ids", clues.ToCore(err))
|
||||||
require.NotEmpty(t, ids, "contact ids in folder")
|
require.NotEmpty(t, ids, "contact ids in folder")
|
||||||
|
|
||||||
@ -1094,7 +1094,7 @@ func (suite *BackupOpIntegrationSuite) TestBackup_Run_exchangeIncrementals() {
|
|||||||
require.NoError(t, err, "deleting contact item", clues.ToCore(err))
|
require.NoError(t, err, "deleting contact item", clues.ToCore(err))
|
||||||
|
|
||||||
case path.EventsCategory:
|
case path.EventsCategory:
|
||||||
ids, _, _, err := ac.Events().GetAddedAndRemovedItemIDs(ctx, suite.user, containerID, "")
|
ids, _, _, err := ac.Events().GetAddedAndRemovedItemIDs(ctx, suite.user, containerID, "", false)
|
||||||
require.NoError(t, err, "getting event ids", clues.ToCore(err))
|
require.NoError(t, err, "getting event ids", clues.ToCore(err))
|
||||||
require.NotEmpty(t, ids, "event ids in folder")
|
require.NotEmpty(t, ids, "event ids in folder")
|
||||||
|
|
||||||
|
|||||||
@ -88,4 +88,8 @@ type Toggles struct {
|
|||||||
// DisableIncrementals prevents backups from using incremental lookups,
|
// DisableIncrementals prevents backups from using incremental lookups,
|
||||||
// forcing a new, complete backup of all data regardless of prior state.
|
// forcing a new, complete backup of all data regardless of prior state.
|
||||||
DisableIncrementals bool `json:"exchangeIncrementals,omitempty"`
|
DisableIncrementals bool `json:"exchangeIncrementals,omitempty"`
|
||||||
|
// ExchangeImmutableIDs denotes whether Corso should store items with
|
||||||
|
// immutable Exchange IDs. This is only safe to set if the previous backup for
|
||||||
|
// incremental backups used immutable IDs or if a full backup is being done.
|
||||||
|
ExchangeImmutableIDs bool `json:"exchangeImmutableIDs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user