GC: Restore: Split restore data into separate file. (#857)
## Description Places `exchange.Restore` logic into single file <!-- Insert PR description--> ## Type of change - [x] 🐹 Trivial/Minor ## Issue(s) <!-- Can reference multiple issues. Use one of the following "magic words" - "closes, fixes" to auto-close the Github issue. --> * #<issue> ## Test Plan <!-- How will this be tested prior to merging.--> - [ ] 💪 Manual - [x] ⚡ Unit test - [ ] 💚 E2E
This commit is contained in:
parent
76a4f5531c
commit
f8a10b4de6
@ -32,10 +32,6 @@ var (
|
|||||||
const (
|
const (
|
||||||
collectionChannelBufferSize = 1000
|
collectionChannelBufferSize = 1000
|
||||||
numberOfRetries = 4
|
numberOfRetries = 4
|
||||||
// RestorePropertyTag defined:
|
|
||||||
// https://docs.microsoft.com/en-us/office/client-developer/outlook/mapi/pidtagmessageflags-canonical-property
|
|
||||||
RestorePropertyTag = "Integer 0x0E07"
|
|
||||||
RestoreCanonicalEnableValue = "4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Collection implements the interface from data.Collection
|
// Collection implements the interface from data.Collection
|
||||||
|
|||||||
29
src/internal/connector/exchange/exchange_vars.go
Normal file
29
src/internal/connector/exchange/exchange_vars.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
// exchange_vars.go is package level collection of interfaces and
|
||||||
|
// constants that are used within the exchange.
|
||||||
|
|
||||||
|
// Legacy Value Tags and constants are used to override certain values within
|
||||||
|
// M365 objects.
|
||||||
|
// Master Property Value Document:
|
||||||
|
// https://interoperability.blob.core.windows.net/files/MS-OXPROPS/%5bMS-OXPROPS%5d.pdf
|
||||||
|
const (
|
||||||
|
// MailRestorePropertyTag inhibits exchange.Mail.Message from being "resent" through the server.
|
||||||
|
// DEFINED: Section 2.791 PidTagMessageFlags
|
||||||
|
MailRestorePropertyTag = "Integer 0x0E07"
|
||||||
|
|
||||||
|
// RestoreCanonicalEnableValue marks message as sent via RopSubmitMessage
|
||||||
|
// Defined: https://interoperability.blob.core.windows.net/files/MS-OXCMSG/%5bMS-OXCMSG%5d.pdf
|
||||||
|
// Section: 2.2.1.6 PidTagMessageFlags Property
|
||||||
|
//nolint:lll
|
||||||
|
// Additional Information: https://docs.microsoft.com/en-us/office/client-developer/outlook/mapi/pidtagmessageflags-canonical-property
|
||||||
|
RestoreCanonicalEnableValue = "4"
|
||||||
|
|
||||||
|
// MailSendTimeOverrideProperty allows for send time to be updated.
|
||||||
|
// Section: 2.635 PidTagClientSubmitTime
|
||||||
|
MailSendDateTimeOverrideProperty = "SystemTime 0x0039"
|
||||||
|
|
||||||
|
// MailReceiveDateTimeOverrideProperty allows receive date time to be updated.
|
||||||
|
// Section: 2.789 PidTagMessageDeliveryTime
|
||||||
|
MailReceiveDateTimeOverriveProperty = "SystemTime 0x0E06"
|
||||||
|
)
|
||||||
@ -1,7 +1,6 @@
|
|||||||
package exchange
|
package exchange
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -11,13 +10,9 @@ import (
|
|||||||
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/alcionai/corso/src/internal/common"
|
|
||||||
"github.com/alcionai/corso/src/internal/connector/graph"
|
"github.com/alcionai/corso/src/internal/connector/graph"
|
||||||
"github.com/alcionai/corso/src/internal/connector/support"
|
"github.com/alcionai/corso/src/internal/connector/support"
|
||||||
"github.com/alcionai/corso/src/internal/path"
|
|
||||||
"github.com/alcionai/corso/src/pkg/account"
|
"github.com/alcionai/corso/src/pkg/account"
|
||||||
"github.com/alcionai/corso/src/pkg/control"
|
|
||||||
"github.com/alcionai/corso/src/pkg/logger"
|
|
||||||
"github.com/alcionai/corso/src/pkg/selectors"
|
"github.com/alcionai/corso/src/pkg/selectors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -374,221 +369,3 @@ func SetupExchangeCollectionVars(scope selectors.ExchangeScope) (
|
|||||||
|
|
||||||
return nil, nil, nil, errors.New("exchange scope option not supported")
|
return nil, nil, nil, errors.New("exchange scope option not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRestoreContainer utility function to create
|
|
||||||
// an unique folder for the restore process
|
|
||||||
// @param category: input from fullPath()[2]
|
|
||||||
// that defines the application the folder is created in.
|
|
||||||
func GetRestoreContainer(
|
|
||||||
service graph.Service,
|
|
||||||
user string,
|
|
||||||
category path.CategoryType,
|
|
||||||
) (string, error) {
|
|
||||||
name := fmt.Sprintf("Corso_Restore_%s", common.FormatNow(common.SimpleDateTimeFormat))
|
|
||||||
option := categoryToOptionIdentifier(category)
|
|
||||||
|
|
||||||
folderID, err := GetContainerID(service, name, user, option)
|
|
||||||
if err == nil {
|
|
||||||
return *folderID, nil
|
|
||||||
}
|
|
||||||
// Experienced error other than folder does not exist
|
|
||||||
if !errors.Is(err, ErrFolderNotFound) {
|
|
||||||
return "", support.WrapAndAppend(user, err, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch option {
|
|
||||||
case messages:
|
|
||||||
fold, err := CreateMailFolder(service, user, name)
|
|
||||||
if err != nil {
|
|
||||||
return "", support.WrapAndAppend(user, err, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return *fold.GetId(), nil
|
|
||||||
case contacts:
|
|
||||||
fold, err := CreateContactFolder(service, user, name)
|
|
||||||
if err != nil {
|
|
||||||
return "", support.WrapAndAppend(user, err, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return *fold.GetId(), nil
|
|
||||||
case events:
|
|
||||||
calendar, err := CreateCalendar(service, user, name)
|
|
||||||
if err != nil {
|
|
||||||
return "", support.WrapAndAppend(user, err, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return *calendar.GetId(), nil
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("category: %s not supported for folder creation", option)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func RestoreExchangeObject(
|
|
||||||
ctx context.Context,
|
|
||||||
bits []byte,
|
|
||||||
category path.CategoryType,
|
|
||||||
policy control.CollisionPolicy,
|
|
||||||
service graph.Service,
|
|
||||||
destination, user string,
|
|
||||||
) error {
|
|
||||||
if policy != control.Copy {
|
|
||||||
return fmt.Errorf("restore policy: %s not supported", policy)
|
|
||||||
}
|
|
||||||
|
|
||||||
setting := categoryToOptionIdentifier(category)
|
|
||||||
|
|
||||||
switch setting {
|
|
||||||
case messages:
|
|
||||||
return RestoreMailMessage(ctx, bits, service, control.Copy, destination, user)
|
|
||||||
case contacts:
|
|
||||||
return RestoreExchangeContact(ctx, bits, service, control.Copy, destination, user)
|
|
||||||
case events:
|
|
||||||
return RestoreExchangeEvent(ctx, bits, service, control.Copy, destination, user)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("type: %s not supported for exchange restore", category)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RestoreExchangeContact restores a contact to the @bits byte
|
|
||||||
// representation of M365 contact object.
|
|
||||||
// @destination M365 ID representing a M365 Contact_Folder
|
|
||||||
// Returns an error if the input bits do not parse into a models.Contactable object
|
|
||||||
// or if an error is encountered sending data to the M365 account.
|
|
||||||
// Post details: https://docs.microsoft.com/en-us/graph/api/user-post-contacts?view=graph-rest-1.0&tabs=go
|
|
||||||
func RestoreExchangeContact(
|
|
||||||
ctx context.Context,
|
|
||||||
bits []byte,
|
|
||||||
service graph.Service,
|
|
||||||
cp control.CollisionPolicy,
|
|
||||||
destination, user string,
|
|
||||||
) error {
|
|
||||||
contact, err := support.CreateContactFromBytes(bits)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := service.Client().UsersById(user).ContactFoldersById(destination).Contacts().Post(contact)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, support.ConnectorStackErrorTrace(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
if response == nil {
|
|
||||||
return errors.New("msgraph contact post fail: REST response not received")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func RestoreExchangeEvent(
|
|
||||||
ctx context.Context,
|
|
||||||
bits []byte,
|
|
||||||
service graph.Service,
|
|
||||||
cp control.CollisionPolicy,
|
|
||||||
destination, user string,
|
|
||||||
) error {
|
|
||||||
event, err := support.CreateEventFromBytes(bits)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := service.Client().UsersById(user).CalendarsById(destination).Events().Post(event)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, support.ConnectorStackErrorTrace(err))
|
|
||||||
}
|
|
||||||
|
|
||||||
if response == nil {
|
|
||||||
return errors.New("msgraph event post fail: REST response not received")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RestoreMailMessage utility function to place an exchange.Mail
|
|
||||||
// message into the user's M365 Exchange account.
|
|
||||||
// @param bits - byte array representation of exchange.Message from Corso backstore
|
|
||||||
// @param service - connector to M365 graph
|
|
||||||
// @param cp - collision policy that directs restore workflow
|
|
||||||
// @param destination - M365 Folder ID. Verified and sent by higher function. `copy` policy can use directly
|
|
||||||
func RestoreMailMessage(
|
|
||||||
ctx context.Context,
|
|
||||||
bits []byte,
|
|
||||||
service graph.Service,
|
|
||||||
cp control.CollisionPolicy,
|
|
||||||
destination,
|
|
||||||
user string,
|
|
||||||
) error {
|
|
||||||
// Creates messageable object from original bytes
|
|
||||||
originalMessage, err := support.CreateMessageFromBytes(bits)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "restore mail message rcvd: %v", bits)
|
|
||||||
}
|
|
||||||
// Sets fields from original message from storage
|
|
||||||
clone := support.ToMessage(originalMessage)
|
|
||||||
valueID := RestorePropertyTag
|
|
||||||
enableValue := RestoreCanonicalEnableValue
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
default:
|
|
||||||
logger.Ctx(ctx).DPanicw("unrecognized restore policy; defaulting to copy",
|
|
||||||
"policy", cp)
|
|
||||||
fallthrough
|
|
||||||
case control.Copy:
|
|
||||||
return SendMailToBackStore(service, user, destination, clone)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendMailToBackStore function for transporting in-memory messageable item to M365 backstore
|
|
||||||
// @param user string represents M365 ID of user within the tenant
|
|
||||||
// @param destination represents M365 ID of a folder within the users's space
|
|
||||||
// @param message is a models.Messageable interface from "github.com/microsoftgraph/msgraph-sdk-go/models"
|
|
||||||
func SendMailToBackStore(service graph.Service, user, destination string, message models.Messageable) error {
|
|
||||||
var (
|
|
||||||
sentMessage models.Messageable
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
|
|
||||||
for count := 0; count < numberOfRetries; count++ {
|
|
||||||
sentMessage, err = service.Client().UsersById(user).MailFoldersById(destination).Messages().Post(message)
|
|
||||||
if err == nil && sentMessage != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return support.WrapAndAppend(": "+support.ConnectorStackErrorTrace(err), err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
if sentMessage == nil {
|
|
||||||
return errors.New("message not Sent: blocked by server")
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return support.WrapAndAppend(": "+support.ConnectorStackErrorTrace(err), err, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
232
src/internal/connector/exchange/service_restore.go
Normal file
232
src/internal/connector/exchange/service_restore.go
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
package exchange
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
"github.com/alcionai/corso/src/internal/common"
|
||||||
|
"github.com/alcionai/corso/src/internal/connector/graph"
|
||||||
|
"github.com/alcionai/corso/src/internal/connector/support"
|
||||||
|
"github.com/alcionai/corso/src/internal/path"
|
||||||
|
"github.com/alcionai/corso/src/pkg/control"
|
||||||
|
"github.com/alcionai/corso/src/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetRestoreContainer utility function to create
|
||||||
|
// an unique folder for the restore process
|
||||||
|
// @param category: input from fullPath()[2]
|
||||||
|
// that defines the application the folder is created in.
|
||||||
|
func GetRestoreContainer(
|
||||||
|
service graph.Service,
|
||||||
|
user string,
|
||||||
|
category path.CategoryType,
|
||||||
|
) (string, error) {
|
||||||
|
name := fmt.Sprintf("Corso_Restore_%s", common.FormatNow(common.SimpleDateTimeFormat))
|
||||||
|
option := categoryToOptionIdentifier(category)
|
||||||
|
|
||||||
|
folderID, err := GetContainerID(service, name, user, option)
|
||||||
|
if err == nil {
|
||||||
|
return *folderID, nil
|
||||||
|
}
|
||||||
|
// Experienced error other than folder does not exist
|
||||||
|
if !errors.Is(err, ErrFolderNotFound) {
|
||||||
|
return "", support.WrapAndAppend(user, err, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch option {
|
||||||
|
case messages:
|
||||||
|
fold, err := CreateMailFolder(service, user, name)
|
||||||
|
if err != nil {
|
||||||
|
return "", support.WrapAndAppend(user, err, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return *fold.GetId(), nil
|
||||||
|
case contacts:
|
||||||
|
fold, err := CreateContactFolder(service, user, name)
|
||||||
|
if err != nil {
|
||||||
|
return "", support.WrapAndAppend(user, err, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return *fold.GetId(), nil
|
||||||
|
case events:
|
||||||
|
calendar, err := CreateCalendar(service, user, name)
|
||||||
|
if err != nil {
|
||||||
|
return "", support.WrapAndAppend(user, err, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return *calendar.GetId(), nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("category: %s not supported for folder creation", option)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreExchangeObject directs restore pipeline towards restore function
|
||||||
|
// based on the path.CategoryType. All input params are necessary to perform
|
||||||
|
// the type-specific restore function.
|
||||||
|
func RestoreExchangeObject(
|
||||||
|
ctx context.Context,
|
||||||
|
bits []byte,
|
||||||
|
category path.CategoryType,
|
||||||
|
policy control.CollisionPolicy,
|
||||||
|
service graph.Service,
|
||||||
|
destination, user string,
|
||||||
|
) error {
|
||||||
|
if policy != control.Copy {
|
||||||
|
return fmt.Errorf("restore policy: %s not supported", policy)
|
||||||
|
}
|
||||||
|
|
||||||
|
setting := categoryToOptionIdentifier(category)
|
||||||
|
|
||||||
|
switch setting {
|
||||||
|
case messages:
|
||||||
|
return RestoreMailMessage(ctx, bits, service, control.Copy, destination, user)
|
||||||
|
case contacts:
|
||||||
|
return RestoreExchangeContact(ctx, bits, service, control.Copy, destination, user)
|
||||||
|
case events:
|
||||||
|
return RestoreExchangeEvent(ctx, bits, service, control.Copy, destination, user)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("type: %s not supported for exchange restore", category)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreExchangeContact restores a contact to the @bits byte
|
||||||
|
// representation of M365 contact object.
|
||||||
|
// @destination M365 ID representing a M365 Contact_Folder
|
||||||
|
// Returns an error if the input bits do not parse into a models.Contactable object
|
||||||
|
// or if an error is encountered sending data to the M365 account.
|
||||||
|
// Post details: https://docs.microsoft.com/en-us/graph/api/user-post-contacts?view=graph-rest-1.0&tabs=go
|
||||||
|
func RestoreExchangeContact(
|
||||||
|
ctx context.Context,
|
||||||
|
bits []byte,
|
||||||
|
service graph.Service,
|
||||||
|
cp control.CollisionPolicy,
|
||||||
|
destination, user string,
|
||||||
|
) error {
|
||||||
|
contact, err := support.CreateContactFromBytes(bits)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := service.Client().UsersById(user).ContactFoldersById(destination).Contacts().Post(contact)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, support.ConnectorStackErrorTrace(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if response == nil {
|
||||||
|
return errors.New("msgraph contact post fail: REST response not received")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreExchangeEvent restores a contact to the @bits byte
|
||||||
|
// representation of M365 event object.
|
||||||
|
// @param destination is the M365 ID representing Calendar that will receive the event.
|
||||||
|
// Returns an error if input byte array doesn't parse into models.Eventable object
|
||||||
|
// or if an error occurs during sending data to M365 account.
|
||||||
|
// Post details: https://docs.microsoft.com/en-us/graph/api/user-post-events?view=graph-rest-1.0&tabs=http
|
||||||
|
func RestoreExchangeEvent(
|
||||||
|
ctx context.Context,
|
||||||
|
bits []byte,
|
||||||
|
service graph.Service,
|
||||||
|
cp control.CollisionPolicy,
|
||||||
|
destination, user string,
|
||||||
|
) error {
|
||||||
|
event, err := support.CreateEventFromBytes(bits)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := service.Client().UsersById(user).CalendarsById(destination).Events().Post(event)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, support.ConnectorStackErrorTrace(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if response == nil {
|
||||||
|
return errors.New("msgraph event post fail: REST response not received")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreMailMessage utility function to place an exchange.Mail
|
||||||
|
// message into the user's M365 Exchange account.
|
||||||
|
// @param bits - byte array representation of exchange.Message from Corso backstore
|
||||||
|
// @param service - connector to M365 graph
|
||||||
|
// @param cp - collision policy that directs restore workflow
|
||||||
|
// @param destination - M365 Folder ID. Verified and sent by higher function. `copy` policy can use directly
|
||||||
|
func RestoreMailMessage(
|
||||||
|
ctx context.Context,
|
||||||
|
bits []byte,
|
||||||
|
service graph.Service,
|
||||||
|
cp control.CollisionPolicy,
|
||||||
|
destination,
|
||||||
|
user string,
|
||||||
|
) error {
|
||||||
|
// Creates messageable object from original bytes
|
||||||
|
originalMessage, err := support.CreateMessageFromBytes(bits)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Sets fields from original message from storage
|
||||||
|
clone := support.ToMessage(originalMessage)
|
||||||
|
valueID := MailRestorePropertyTag
|
||||||
|
enableValue := RestoreCanonicalEnableValue
|
||||||
|
|
||||||
|
// 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 := MailSendDateTimeOverrideProperty
|
||||||
|
sv2.SetId(&sendPropertyTag)
|
||||||
|
sv2.SetValue(&sendPropertyValue)
|
||||||
|
|
||||||
|
sv3 := models.NewSingleValueLegacyExtendedProperty()
|
||||||
|
recvPropertyValue := common.FormatLegacyTime(*clone.GetReceivedDateTime())
|
||||||
|
recvPropertyTag := MailReceiveDateTimeOverriveProperty
|
||||||
|
sv3.SetId(&recvPropertyTag)
|
||||||
|
sv3.SetValue(&recvPropertyValue)
|
||||||
|
|
||||||
|
svlep := []models.SingleValueLegacyExtendedPropertyable{sv1, sv2, sv3}
|
||||||
|
clone.SetSingleValueExtendedProperties(svlep)
|
||||||
|
|
||||||
|
// Switch workflow based on collision policy
|
||||||
|
switch cp {
|
||||||
|
default:
|
||||||
|
logger.Ctx(ctx).DPanicw("unrecognized restore policy; defaulting to copy",
|
||||||
|
"policy", cp)
|
||||||
|
fallthrough
|
||||||
|
case control.Copy:
|
||||||
|
return SendMailToBackStore(service, user, destination, clone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendMailToBackStore function for transporting in-memory messageable item to M365 backstore
|
||||||
|
// @param user string represents M365 ID of user within the tenant
|
||||||
|
// @param destination represents M365 ID of a folder within the users's space
|
||||||
|
// @param message is a models.Messageable interface from "github.com/microsoftgraph/msgraph-sdk-go/models"
|
||||||
|
func SendMailToBackStore(service graph.Service, user, destination string, message models.Messageable) error {
|
||||||
|
sentMessage, err := service.Client().UsersById(user).MailFoldersById(destination).Messages().Post(message)
|
||||||
|
if err != nil {
|
||||||
|
return support.WrapAndAppend(": "+support.ConnectorStackErrorTrace(err), err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sentMessage == nil {
|
||||||
|
return errors.New("message not Sent: blocked by server")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return support.WrapAndAppend(": "+support.ConnectorStackErrorTrace(err), err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user