From 447321588212266969fa404520e2e2a0e6b5d47b Mon Sep 17 00:00:00 2001 From: Danny Date: Thu, 19 Jan 2023 19:32:18 -0500 Subject: [PATCH] GC: Backup: [FIX]Embedded image requires download (#2189) ## Description Images copy/pasted into a message were not being saved previously. Verified with Corso binary ## Does this PR need a docs update or release note? - [x] :white_check_mark: Yes, in the ChangeLog. ## Type of change - [x] :bug: Bugfix ## Issue(s) * closes #2163 ## Test Plan - [x] :zap: Unit test --- CHANGELOG.md | 2 +- src/internal/connector/exchange/api/events.go | 2 +- src/internal/connector/exchange/api/mail.go | 2 +- src/internal/connector/support/m365Support.go | 13 +++++ .../connector/support/m365Support_test.go | 54 +++++++++++++++++++ 5 files changed, 70 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b981d778a..07c061f12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Check if the user specified for an exchange backup operation has a mailbox. - Handle case where user's drive has not been initialized - +- Inline attachments (e.g. copy/paste ) are discovered and backed up correctly ([#2163](https://github.com/alcionai/corso/issues/2163)) ## [v0.1.0] (alpha) - 2023-01-13 diff --git a/src/internal/connector/exchange/api/events.go b/src/internal/connector/exchange/api/events.go index 0aafaf3f2..f78aef76b 100644 --- a/src/internal/connector/exchange/api/events.go +++ b/src/internal/connector/exchange/api/events.go @@ -268,7 +268,7 @@ func (c Events) Serialize( defer writer.Close() - if *event.GetHasAttachments() { + if *event.GetHasAttachments() || support.HasAttachments(event.GetBody()) { // getting all the attachments might take a couple attempts due to filesize var retriesErr error diff --git a/src/internal/connector/exchange/api/mail.go b/src/internal/connector/exchange/api/mail.go index b3f67ceb8..59085ba96 100644 --- a/src/internal/connector/exchange/api/mail.go +++ b/src/internal/connector/exchange/api/mail.go @@ -257,7 +257,7 @@ func (c Mail) Serialize( defer writer.Close() - if *msg.GetHasAttachments() { + if *msg.GetHasAttachments() || support.HasAttachments(msg.GetBody()) { // getting all the attachments might take a couple attempts due to filesize var retriesErr error diff --git a/src/internal/connector/support/m365Support.go b/src/internal/connector/support/m365Support.go index d7e51e513..99cb95577 100644 --- a/src/internal/connector/support/m365Support.go +++ b/src/internal/connector/support/m365Support.go @@ -1,6 +1,8 @@ package support import ( + "strings" + absser "github.com/microsoft/kiota-abstractions-go/serialization" js "github.com/microsoft/kiota-serialization-json-go" "github.com/microsoftgraph/msgraph-sdk-go/models" @@ -71,3 +73,14 @@ func CreateListFromBytes(bytes []byte) (models.Listable, error) { return list, nil } + +func HasAttachments(body models.ItemBodyable) bool { + if body.GetContent() == nil || body.GetContentType() == nil || + *body.GetContentType() == models.TEXT_BODYTYPE || len(*body.GetContent()) == 0 { + return false + } + + content := *body.GetContent() + + return strings.Contains(content, "src=\"cid:") +} diff --git a/src/internal/connector/support/m365Support_test.go b/src/internal/connector/support/m365Support_test.go index c04c74604..dedde3536 100644 --- a/src/internal/connector/support/m365Support_test.go +++ b/src/internal/connector/support/m365Support_test.go @@ -3,6 +3,7 @@ package support import ( "testing" + "github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -159,3 +160,56 @@ func (suite *DataSupportSuite) TestCreateListFromBytes() { }) } } + +func (suite *DataSupportSuite) TestHasAttachments() { + tests := []struct { + name string + hasAttachment assert.BoolAssertionFunc + getBodyable func(t *testing.T) models.ItemBodyable + }{ + { + name: "Mock w/out attachment", + hasAttachment: assert.False, + getBodyable: func(t *testing.T) models.ItemBodyable { + byteArray := mockconnector.GetMockMessageWithBodyBytes( + "Test", + "This is testing", + "This is testing", + ) + message, err := CreateMessageFromBytes(byteArray) + require.NoError(t, err) + return message.GetBody() + }, + }, + { + name: "Mock w/ inline attachment", + hasAttachment: assert.True, + getBodyable: func(t *testing.T) models.ItemBodyable { + byteArray := mockconnector.GetMessageWithOneDriveAttachment("Test legacy") + message, err := CreateMessageFromBytes(byteArray) + require.NoError(t, err) + return message.GetBody() + }, + }, + { + name: "Edge Case", + hasAttachment: assert.True, + getBodyable: func(t *testing.T) models.ItemBodyable { + //nolint:lll + content := "\r\n
Happy New Year,

In accordance with TPS report guidelines, there have been questions about how to address our activities SharePoint Cover page. Do you believe this is the best picture? 



Let me know if this meets our culture requirements.

Warm Regards,

Dustin
" + body := models.NewItemBody() + body.SetContent(&content) + cat := models.HTML_BODYTYPE + body.SetContentType(&cat) + return body + }, + }, + } + + for _, test := range tests { + suite.T().Run(test.name, func(t *testing.T) { + found := HasAttachments(test.getBodyable(t)) + test.hasAttachment(t, found) + }) + } +}