Store parent post content (#5096)

<!-- PR description-->

* 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.


---

#### 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

<!--- Please check the type of change your PR introduces: --->
- [x] 🌻 Feature
- [ ] 🐛 Bugfix
- [ ] 🗺️ Documentation
- [ ] 🤖 Supportability/Tests
- [ ] 💻 CI/Deployment
- [ ] 🧹 Tech Debt/Cleanup

#### 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:
Abhishek Pandey 2024-01-23 22:36:44 -08:00 committed by GitHub
parent 5a05223e90
commit b073c204c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 107 additions and 123 deletions

View File

@ -129,8 +129,7 @@ func (bh conversationsBackupHandler) getItem(
groupID, groupID,
containerIDs[0], containerIDs[0],
containerIDs[1], containerIDs[1],
postID, postID)
api.CallConfig{})
} }
//lint:ignore U1000 false linter issue due to generics //lint:ignore U1000 false linter issue due to generics

View File

@ -35,19 +35,17 @@ type Conversations struct {
func (c Conversations) GetConversationPost( func (c Conversations) GetConversationPost(
ctx context.Context, ctx context.Context,
groupID, conversationID, threadID, postID string, groupID, conversationID, threadID, postID string,
cc CallConfig,
) (models.Postable, *details.GroupsInfo, error) { ) (models.Postable, *details.GroupsInfo, error) {
config := &groups.ItemConversationsItemThreadsItemPostsPostItemRequestBuilderGetRequestConfiguration{ config := &groups.ItemConversationsItemThreadsItemPostsPostItemRequestBuilderGetRequestConfiguration{
QueryParameters: &groups.ItemConversationsItemThreadsItemPostsPostItemRequestBuilderGetQueryParameters{}, QueryParameters: &groups.ItemConversationsItemThreadsItemPostsPostItemRequestBuilderGetQueryParameters{},
} }
if len(cc.Select) > 0 { // Expand inReplyTo property to additionally get the parent post contents.
config.QueryParameters.Select = cc.Select // This will be persisted as part of post data.
} //
// This additional data will be useful for building a reply tree if we decide to
if len(cc.Expand) > 0 { // do in-order restore/export in future.
config.QueryParameters.Expand = append(config.QueryParameters.Expand, cc.Expand...) config.QueryParameters.Expand = append(config.QueryParameters.Expand, "inReplyTo")
}
post, err := c.Stable. post, err := c.Stable.
Client(). Client().

View File

@ -40,8 +40,7 @@ func testGetPostByID(
suite.its.group.id, suite.its.group.id,
ptr.Val(conv.GetId()), ptr.Val(conv.GetId()),
ptr.Val(thread.GetId()), ptr.Val(thread.GetId()),
ptr.Val(post.GetId()), ptr.Val(post.GetId()))
CallConfig{})
require.NoError(t, err, clues.ToCore(err)) require.NoError(t, err, clues.ToCore(err))
require.Equal(t, ptr.Val(post.GetId()), ptr.Val(resp.GetId())) require.Equal(t, ptr.Val(post.GetId()), ptr.Val(resp.GetId()))
}) })
@ -135,118 +134,126 @@ func (suite *ConversationAPIIntgSuite) SetupSuite() {
suite.its = newIntegrationTesterSetup(suite.T()) suite.its = newIntegrationTesterSetup(suite.T())
} }
func (suite *ConversationAPIIntgSuite) TestConversations_attachmentListDownload() { func (suite *ConversationAPIIntgSuite) TestGetConversationPost() {
pid := "fake-post-id" pid := "fake-post-id"
replyToID := "fake-reply-to-id"
aid := "fake-attachment-id" aid := "fake-attachment-id"
contentWithAttachment := "<html><body><img src=\"cid:fake-attach-id\"/></body></html>" contentWithAttachment := "<html><body><img src=\"cid:fake-attach-id\"/></body></html>"
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 { tests := []struct {
name string name string
setupf func() setupf func()
attachmentCount int attachmentCount int
inReplyToPresent bool
size int64 size int64
expect assert.ErrorAssertionFunc expect assert.ErrorAssertionFunc
}{ }{
{ {
name: "no attachments", name: "no inReplyTo, no attachment",
setupf: func() { setupf: func() {
itm := models.NewPost() item := models.NewPost()
itm.SetId(&pid) item.SetId(&pid)
interceptV1Path( interceptPathWithExpand(item, "inReplyTo")
"groups",
"group",
"conversations",
"conv",
"threads",
"thread",
"posts",
pid).
Reply(200).
JSON(graphTD.ParseableToMap(suite.T(), itm))
}, },
expect: assert.NoError, expect: assert.NoError,
}, },
{ {
name: "fetch with attachment", name: "with inReplyTo, no attachment",
setupf: func() { setupf: func() {
itm := models.NewPost() item := models.NewPost()
itm.SetId(&pid) parentPost := models.NewPost()
itm.SetHasAttachments(ptr.To(true))
// First call to get the post will not expand attachments. item.SetId(&pid)
interceptV1Path( parentPost.SetId(&replyToID)
"groups", item.SetInReplyTo(parentPost)
"group",
"conversations", interceptPathWithExpand(item, "inReplyTo")
"conv", },
"threads", inReplyToPresent: true,
"thread", expect: assert.NoError,
"posts", },
pid). {
Reply(200). name: "no inreplyTo, with attachment",
JSON(graphTD.ParseableToMap(suite.T(), itm)) setupf: func() {
item := models.NewPost()
item.SetId(&pid)
item.SetHasAttachments(ptr.To(true))
interceptPathWithExpand(item, "inReplyTo")
attch := models.NewAttachment() attch := models.NewAttachment()
attch.SetSize(ptr.To[int32](50)) attch.SetSize(ptr.To[int32](50))
item.SetAttachments([]models.Attachmentable{attch})
itm.SetAttachments([]models.Attachmentable{attch}) interceptPathWithExpand(item, "attachments")
interceptV1Path(
"groups",
"group",
"conversations",
"conv",
"threads",
"thread",
"posts",
pid).
MatchParam("$expand", "attachments").
Reply(200).
JSON(graphTD.ParseableToMap(suite.T(), itm))
}, },
attachmentCount: 1, attachmentCount: 1,
size: 50, size: 50,
expect: assert.NoError, expect: assert.NoError,
}, },
{ {
name: "fetch multiple individual attachments", name: "with inreplyTo, with attachment",
setupf: func() { setupf: func() {
itm := models.NewPost() item := models.NewPost()
parentPost := models.NewPost()
itm.SetId(&pid) item.SetId(&pid)
itm.SetHasAttachments(ptr.To(true)) parentPost.SetId(&replyToID)
item.SetInReplyTo(parentPost)
item.SetHasAttachments(ptr.To(true))
interceptV1Path( interceptPathWithExpand(item, "inReplyTo")
"groups",
"group", attch := models.NewAttachment()
"conversations", attch.SetSize(ptr.To[int32](50))
"conv", item.SetAttachments([]models.Attachmentable{attch})
"threads",
"thread", interceptPathWithExpand(item, "attachments")
"posts", },
pid). inReplyToPresent: true,
Reply(200). attachmentCount: 1,
JSON(graphTD.ParseableToMap(suite.T(), itm)) 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 := models.NewAttachment()
attch.SetId(&aid) attch.SetId(&aid)
attch.SetSize(ptr.To[int32](200)) 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( interceptPathWithExpand(item, "attachments")
"groups",
"group",
"conversations",
"conv",
"threads",
"thread",
"posts",
pid).
MatchParam("$expand", "attachments").
Reply(200).
JSON(graphTD.ParseableToMap(suite.T(), itm))
}, },
attachmentCount: 5, attachmentCount: 5,
size: 1000, size: 1000,
@ -255,46 +262,21 @@ func (suite *ConversationAPIIntgSuite) TestConversations_attachmentListDownload(
{ {
name: "embedded attachment", name: "embedded attachment",
setupf: func() { setupf: func() {
itm := models.NewPost() item := models.NewPost()
itm.SetId(&pid) item.SetId(&pid)
body := models.NewItemBody() body := models.NewItemBody()
body.SetContentType(ptr.To(models.HTML_BODYTYPE)) body.SetContentType(ptr.To(models.HTML_BODYTYPE))
// Test html content with embedded attachment.
body.SetContent(ptr.To(contentWithAttachment)) body.SetContent(ptr.To(contentWithAttachment))
item.SetBody(body)
itm.SetBody(body) interceptPathWithExpand(item, "inReplyTo")
interceptV1Path(
"groups",
"group",
"conversations",
"conv",
"threads",
"thread",
"posts",
pid).
Reply(200).
JSON(graphTD.ParseableToMap(suite.T(), itm))
attch := models.NewAttachment() attch := models.NewAttachment()
attch.SetSize(ptr.To[int32](50)) attch.SetSize(ptr.To[int32](50))
itm.SetAttachments([]models.Attachmentable{attch}) item.SetAttachments([]models.Attachmentable{attch})
interceptV1Path( interceptPathWithExpand(item, "attachments")
"groups",
"group",
"conversations",
"conv",
"threads",
"thread",
"posts",
pid).
MatchParam("$expand", "attachments").
Reply(200).
JSON(graphTD.ParseableToMap(suite.T(), itm))
}, },
attachmentCount: 1, attachmentCount: 1,
size: 50 + int64(len(contentWithAttachment)), size: 50 + int64(len(contentWithAttachment)),
@ -319,10 +301,15 @@ func (suite *ConversationAPIIntgSuite) TestConversations_attachmentListDownload(
"group", "group",
"conv", "conv",
"thread", "thread",
pid, pid)
CallConfig{})
test.expect(t, err) 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 var size int64
if item.GetBody() != nil { if item.GetBody() != nil {