diff --git a/src/internal/m365/collection/groups/conversation_handler.go b/src/internal/m365/collection/groups/conversation_handler.go
index f36be0e93..d5b948ef1 100644
--- a/src/internal/m365/collection/groups/conversation_handler.go
+++ b/src/internal/m365/collection/groups/conversation_handler.go
@@ -129,8 +129,7 @@ func (bh conversationsBackupHandler) getItem(
groupID,
containerIDs[0],
containerIDs[1],
- postID,
- api.CallConfig{})
+ postID)
}
//lint:ignore U1000 false linter issue due to generics
diff --git a/src/pkg/services/m365/api/conversations.go b/src/pkg/services/m365/api/conversations.go
index ebfafe619..00d510947 100644
--- a/src/pkg/services/m365/api/conversations.go
+++ b/src/pkg/services/m365/api/conversations.go
@@ -35,19 +35,17 @@ type Conversations struct {
func (c Conversations) GetConversationPost(
ctx context.Context,
groupID, conversationID, threadID, postID string,
- cc CallConfig,
) (models.Postable, *details.GroupsInfo, error) {
config := &groups.ItemConversationsItemThreadsItemPostsPostItemRequestBuilderGetRequestConfiguration{
QueryParameters: &groups.ItemConversationsItemThreadsItemPostsPostItemRequestBuilderGetQueryParameters{},
}
- if len(cc.Select) > 0 {
- config.QueryParameters.Select = cc.Select
- }
-
- if len(cc.Expand) > 0 {
- config.QueryParameters.Expand = append(config.QueryParameters.Expand, cc.Expand...)
- }
+ // Expand inReplyTo property to additionally get the parent post contents.
+ // This will be persisted as part of post data.
+ //
+ // This additional data will be useful for building a reply tree if we decide to
+ // do in-order restore/export in future.
+ config.QueryParameters.Expand = append(config.QueryParameters.Expand, "inReplyTo")
post, err := c.Stable.
Client().
diff --git a/src/pkg/services/m365/api/conversations_test.go b/src/pkg/services/m365/api/conversations_test.go
index a5ac24de7..97abf3347 100644
--- a/src/pkg/services/m365/api/conversations_test.go
+++ b/src/pkg/services/m365/api/conversations_test.go
@@ -40,8 +40,7 @@ func testGetPostByID(
suite.its.group.id,
ptr.Val(conv.GetId()),
ptr.Val(thread.GetId()),
- ptr.Val(post.GetId()),
- CallConfig{})
+ ptr.Val(post.GetId()))
require.NoError(t, err, clues.ToCore(err))
require.Equal(t, ptr.Val(post.GetId()), ptr.Val(resp.GetId()))
})
@@ -135,118 +134,126 @@ func (suite *ConversationAPIIntgSuite) SetupSuite() {
suite.its = newIntegrationTesterSetup(suite.T())
}
-func (suite *ConversationAPIIntgSuite) TestConversations_attachmentListDownload() {
+func (suite *ConversationAPIIntgSuite) TestGetConversationPost() {
pid := "fake-post-id"
+ replyToID := "fake-reply-to-id"
aid := "fake-attachment-id"
contentWithAttachment := "
"
+ interceptPathWithExpand := func(
+ item *models.Post,
+ expandProperty string,
+ path ...string,
+ ) *gock.Response {
+ return interceptV1Path(
+ "groups",
+ "group",
+ "conversations",
+ "conv",
+ "threads",
+ "thread",
+ "posts",
+ pid).
+ MatchParam("$expand", expandProperty).
+ Reply(200).
+ JSON(graphTD.ParseableToMap(suite.T(), item))
+ }
+
tests := []struct {
- name string
- setupf func()
- attachmentCount int
- size int64
- expect assert.ErrorAssertionFunc
+ name string
+ setupf func()
+ attachmentCount int
+ inReplyToPresent bool
+ size int64
+ expect assert.ErrorAssertionFunc
}{
{
- name: "no attachments",
+ name: "no inReplyTo, no attachment",
setupf: func() {
- itm := models.NewPost()
- itm.SetId(&pid)
+ item := models.NewPost()
+ item.SetId(&pid)
- interceptV1Path(
- "groups",
- "group",
- "conversations",
- "conv",
- "threads",
- "thread",
- "posts",
- pid).
- Reply(200).
- JSON(graphTD.ParseableToMap(suite.T(), itm))
+ interceptPathWithExpand(item, "inReplyTo")
},
expect: assert.NoError,
},
{
- name: "fetch with attachment",
+ name: "with inReplyTo, no attachment",
setupf: func() {
- itm := models.NewPost()
- itm.SetId(&pid)
- itm.SetHasAttachments(ptr.To(true))
+ item := models.NewPost()
+ parentPost := models.NewPost()
- // First call to get the post will not expand attachments.
- interceptV1Path(
- "groups",
- "group",
- "conversations",
- "conv",
- "threads",
- "thread",
- "posts",
- pid).
- Reply(200).
- JSON(graphTD.ParseableToMap(suite.T(), itm))
+ item.SetId(&pid)
+ parentPost.SetId(&replyToID)
+ item.SetInReplyTo(parentPost)
+
+ interceptPathWithExpand(item, "inReplyTo")
+ },
+ inReplyToPresent: true,
+ expect: assert.NoError,
+ },
+ {
+ name: "no inreplyTo, with attachment",
+ setupf: func() {
+ item := models.NewPost()
+ item.SetId(&pid)
+ item.SetHasAttachments(ptr.To(true))
+
+ interceptPathWithExpand(item, "inReplyTo")
attch := models.NewAttachment()
attch.SetSize(ptr.To[int32](50))
+ item.SetAttachments([]models.Attachmentable{attch})
- itm.SetAttachments([]models.Attachmentable{attch})
-
- interceptV1Path(
- "groups",
- "group",
- "conversations",
- "conv",
- "threads",
- "thread",
- "posts",
- pid).
- MatchParam("$expand", "attachments").
- Reply(200).
- JSON(graphTD.ParseableToMap(suite.T(), itm))
+ interceptPathWithExpand(item, "attachments")
},
attachmentCount: 1,
size: 50,
expect: assert.NoError,
},
{
- name: "fetch multiple individual attachments",
+ name: "with inreplyTo, with attachment",
setupf: func() {
- itm := models.NewPost()
+ item := models.NewPost()
+ parentPost := models.NewPost()
- itm.SetId(&pid)
- itm.SetHasAttachments(ptr.To(true))
+ item.SetId(&pid)
+ parentPost.SetId(&replyToID)
+ item.SetInReplyTo(parentPost)
+ item.SetHasAttachments(ptr.To(true))
- interceptV1Path(
- "groups",
- "group",
- "conversations",
- "conv",
- "threads",
- "thread",
- "posts",
- pid).
- Reply(200).
- JSON(graphTD.ParseableToMap(suite.T(), itm))
+ interceptPathWithExpand(item, "inReplyTo")
+
+ attch := models.NewAttachment()
+ attch.SetSize(ptr.To[int32](50))
+ item.SetAttachments([]models.Attachmentable{attch})
+
+ interceptPathWithExpand(item, "attachments")
+ },
+ inReplyToPresent: true,
+ attachmentCount: 1,
+ size: 50,
+ expect: assert.NoError,
+ },
+ // At this point we have tested inReplyTo behavior thoroughly.
+ // Skip for remaining tests.
+ {
+ name: "fetch multiple attachments",
+ setupf: func() {
+ item := models.NewPost()
+
+ item.SetId(&pid)
+ item.SetHasAttachments(ptr.To(true))
+
+ interceptPathWithExpand(item, "inReplyTo")
attch := models.NewAttachment()
attch.SetId(&aid)
attch.SetSize(ptr.To[int32](200))
- itm.SetAttachments([]models.Attachmentable{attch, attch, attch, attch, attch})
+ item.SetAttachments([]models.Attachmentable{attch, attch, attch, attch, attch})
- interceptV1Path(
- "groups",
- "group",
- "conversations",
- "conv",
- "threads",
- "thread",
- "posts",
- pid).
- MatchParam("$expand", "attachments").
- Reply(200).
- JSON(graphTD.ParseableToMap(suite.T(), itm))
+ interceptPathWithExpand(item, "attachments")
},
attachmentCount: 5,
size: 1000,
@@ -255,46 +262,21 @@ func (suite *ConversationAPIIntgSuite) TestConversations_attachmentListDownload(
{
name: "embedded attachment",
setupf: func() {
- itm := models.NewPost()
- itm.SetId(&pid)
+ item := models.NewPost()
+ item.SetId(&pid)
body := models.NewItemBody()
body.SetContentType(ptr.To(models.HTML_BODYTYPE))
-
- // Test html content with embedded attachment.
-
body.SetContent(ptr.To(contentWithAttachment))
+ item.SetBody(body)
- itm.SetBody(body)
-
- interceptV1Path(
- "groups",
- "group",
- "conversations",
- "conv",
- "threads",
- "thread",
- "posts",
- pid).
- Reply(200).
- JSON(graphTD.ParseableToMap(suite.T(), itm))
+ interceptPathWithExpand(item, "inReplyTo")
attch := models.NewAttachment()
attch.SetSize(ptr.To[int32](50))
- itm.SetAttachments([]models.Attachmentable{attch})
+ item.SetAttachments([]models.Attachmentable{attch})
- interceptV1Path(
- "groups",
- "group",
- "conversations",
- "conv",
- "threads",
- "thread",
- "posts",
- pid).
- MatchParam("$expand", "attachments").
- Reply(200).
- JSON(graphTD.ParseableToMap(suite.T(), itm))
+ interceptPathWithExpand(item, "attachments")
},
attachmentCount: 1,
size: 50 + int64(len(contentWithAttachment)),
@@ -319,10 +301,15 @@ func (suite *ConversationAPIIntgSuite) TestConversations_attachmentListDownload(
"group",
"conv",
"thread",
- pid,
- CallConfig{})
+ pid)
test.expect(t, err)
+ // inReplyTo checks
+ if test.inReplyToPresent {
+ require.NotNil(t, item.GetInReplyTo())
+ assert.Equal(t, replyToID, ptr.Val(item.GetInReplyTo().GetId()))
+ }
+
var size int64
if item.GetBody() != nil {