Sent / Receive DateTime Stamp Incorrect (#792)

## Description
Single Legacy Policies added to allow the values for sent / receive times to correspond to the original content for `exchange.Mail` objects

## Type of change
- [x] 🐛 Bugfix


## Issue(s)
<!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. -->

*closes  #645

## Test Plan

<!-- How will this be tested prior to merging.-->

- [x] 💪 Manual
Values can be inspected using e2e restore pipelines.
This commit is contained in:
Danny 2022-09-08 23:39:52 -04:00 committed by GitHub
parent f509543856
commit 2e3ee15fd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 35 deletions

View File

@ -8,6 +8,7 @@ import (
const (
StandardTimeFormat = time.RFC3339Nano
SimpleDateTimeFormat = "02-Jan-2006_15:04:05"
LegacyFormat = time.RFC3339
)
// FormatNow produces the current time in UTC using the provided
@ -28,6 +29,12 @@ func FormatSimpleDateTime(t time.Time) string {
return t.UTC().Format(SimpleDateTimeFormat)
}
// FormatLegacyTime produces standard format for string values
// that are placed in SingleValueExtendedProperty tags
func FormatLegacyTime(t time.Time) string {
return t.UTC().Format(LegacyFormat)
}
// ParseTime makes a best attempt to produce a time value from
// the provided string. Always returns a UTC timezone value.
func ParseTime(s string) (time.Time, error) {

View File

@ -26,6 +26,13 @@ func (suite *CommonTimeUnitSuite) TestFormatTime() {
assert.Equal(t, now.UTC().Format(time.RFC3339Nano), result)
}
func (suite *CommonTimeUnitSuite) TestLegacyTime() {
t := suite.T()
now := time.Now()
result := common.FormatLegacyTime(now)
assert.Equal(t, now.UTC().Format(time.RFC3339), result)
}
func (suite *CommonTimeUnitSuite) TestParseTime() {
t := suite.T()
now := time.Now()

View File

@ -407,6 +407,33 @@ func (suite *ExchangeServiceSuite) TestGetContainerID() {
}
}
// Restore Functions
// TestRestoreMessages uses mock data to ensure GraphConnector
// is able to restore a several messageable item to a Mailbox.
// The result should be all successful items restored within the same folder.
func (suite *ExchangeServiceSuite) TestRestoreMessages() {
t := suite.T()
userID := tester.M365UserID(t)
now := time.Now()
folderName := "TestRestoreMessage: " + common.FormatSimpleDateTime(now)
folder, err := CreateMailFolder(suite.es, userID, folderName)
require.NoError(t, err)
folderID := *folder.GetId()
err = RestoreMailMessage(context.Background(),
mockconnector.GetMockMessageBytes("Exchange Service Mail Test"),
suite.es,
control.Copy,
folderID,
userID,
)
require.NoError(t, err)
err = DeleteMailFolder(suite.es, userID, folderID)
assert.NoError(t, err)
}
// TestRestoreContact ensures contact object can be created, placed into
// the Corso Folder. The function handles test clean-up.
func (suite *ExchangeServiceSuite) TestRestoreContact() {

View File

@ -448,14 +448,29 @@ func RestoreMailMessage(
clone := support.ToMessage(originalMessage)
valueID := RestorePropertyTag
enableValue := RestoreCanonicalEnableValue
sv := models.NewSingleValueLegacyExtendedProperty()
sv.SetId(&valueID)
sv.SetValue(&enableValue)
svlep := []models.SingleValueLegacyExtendedPropertyable{sv}
clone.SetSingleValueExtendedProperties(svlep)
draft := false
clone.SetIsDraft(&draft)
// Set Extended Properties:
// 1st: No transmission
// 2nd: Send Date
// 3rd: Recv Date
sv1 := models.NewSingleValueLegacyExtendedProperty()
sv1.SetId(&valueID)
sv1.SetValue(&enableValue)
sv2 := models.NewSingleValueLegacyExtendedProperty()
sendPropertyValue := common.FormatLegacyTime(*clone.GetSentDateTime())
sendPropertyTag := "SystemTime 0x0039"
sv2.SetId(&sendPropertyTag)
sv2.SetValue(&sendPropertyValue)
sv3 := models.NewSingleValueLegacyExtendedProperty()
recvPropertyValue := common.FormatLegacyTime(*clone.GetReceivedDateTime())
recvPropertyTag := "SystemTime 0x0E06"
sv3.SetId(&recvPropertyTag)
sv3.SetValue(&recvPropertyValue)
svlep := []models.SingleValueLegacyExtendedPropertyable{sv1, sv2, sv3}
clone.SetSingleValueExtendedProperties(svlep)
// Switch workflow based on collision policy
switch cp {
@ -482,5 +497,9 @@ func SendMailToBackStore(service graph.Service, user, destination string, messag
return errors.New("message not Sent: blocked by server")
}
if err != nil {
return support.WrapAndAppend(": "+support.ConnectorStackErrorTrace(err), err, nil)
}
return nil
}

View File

@ -14,10 +14,8 @@ import (
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/internal/connector/exchange"
"github.com/alcionai/corso/src/internal/connector/mockconnector"
"github.com/alcionai/corso/src/internal/connector/support"
"github.com/alcionai/corso/src/internal/data"
"github.com/alcionai/corso/src/internal/path"
"github.com/alcionai/corso/src/internal/tester"
"github.com/alcionai/corso/src/pkg/selectors"
)
@ -240,32 +238,6 @@ func (suite *GraphConnectorIntegrationSuite) TestEventsSerializationRegression()
suite.Equal(status.ObjectCount, status.Successful)
}
// Restore Functions
// TestRestoreMessages uses mock data to ensure GraphConnector
// is able to restore a several messageable item to a Mailbox.
// The result should be all successful items restored within the same folder.
func (suite *GraphConnectorIntegrationSuite) TestRestoreMessages() {
t := suite.T()
category := path.EmailCategory
connector := loadConnector(t)
collection := make([]data.Collection, 0)
for i := 0; i < 3; i++ {
mdc := mockconnector.NewMockExchangeCollection(
[]string{"tenant", path.ExchangeService.String(), suite.user, category.String(), "Inbox"},
1)
collection = append(collection, mdc)
}
err := connector.RestoreExchangeDataCollection(context.Background(), collection)
assert.NoError(suite.T(), err)
status := connector.AwaitStatus()
assert.NotNil(t, status)
assert.Equal(t, status.ObjectCount, status.Successful)
assert.Equal(t, status.FolderCount, 1)
}
// TestAccessOfInboxAllUsers verifies that GraphConnector can
// support `--all-users` for backup operations. Selector.DiscreteScopes
// returns all of the users within one scope. Only users who have

View File

@ -38,6 +38,7 @@ func CloneMessageableFields(orig, message models.Messageable) models.Messageable
message.SetInternetMessageId(orig.GetInternetMessageId())
message.SetInternetMessageHeaders(orig.GetInternetMessageHeaders())
message.SetIsDeliveryReceiptRequested(orig.GetIsDeliveryReceiptRequested())
message.SetIsDraft(orig.GetIsDraft())
message.SetIsRead(orig.GetIsRead())
message.SetIsReadReceiptRequested(orig.GetIsReadReceiptRequested())
message.SetParentFolderId(orig.GetParentFolderId())