diff --git a/app/export_converters.go b/app/export_converters.go index 89d00c64f2..3c6eae442e 100644 --- a/app/export_converters.go +++ b/app/export_converters.go @@ -156,6 +156,7 @@ func ImportLineForPost(post *model.PostForExport) *LineImportData { Channel: &post.ChannelName, User: &post.Username, Message: &post.Message, + Props: &post.Props, CreateAt: &post.CreateAt, }, } @@ -172,6 +173,7 @@ func ImportLineForDirectPost(post *model.DirectPostForExport) *LineImportData { ChannelMembers: &channelMembers, User: &post.User, Message: &post.Message, + Props: &post.Props, CreateAt: &post.CreateAt, }, } diff --git a/app/export_test.go b/app/export_test.go index cc3d005489..6c3f9889c3 100644 --- a/app/export_test.go +++ b/app/export_test.go @@ -446,6 +446,81 @@ func TestExportDMandGMPost(t *testing.T) { assert.ElementsMatch(t, dmMembers, *posts[3].ChannelMembers) } +func TestExportPostWithProps(t *testing.T) { + th1 := Setup(t).InitBasic() + + attachments := []*model.SlackAttachment{{Footer: "footer"}} + + // DM Channel + dmChannel := th1.CreateDmChannel(th1.BasicUser2) + dmMembers := []string{th1.BasicUser.Username, th1.BasicUser2.Username} + + user1 := th1.CreateUser() + th1.LinkUserToTeam(user1, th1.BasicTeam) + user2 := th1.CreateUser() + th1.LinkUserToTeam(user2, th1.BasicTeam) + + // GM Channel + gmChannel := th1.CreateGroupChannel(user1, user2) + gmMembers := []string{th1.BasicUser.Username, user1.Username, user2.Username} + + // DM posts + p1 := &model.Post{ + ChannelId: dmChannel.Id, + Message: "aa" + model.NewId() + "a", + Props: map[string]interface{}{ + "attachments": attachments, + }, + UserId: th1.BasicUser.Id, + } + th1.App.CreatePost(p1, dmChannel, false) + + p2 := &model.Post{ + ChannelId: gmChannel.Id, + Message: "dd" + model.NewId() + "a", + Props: map[string]interface{}{ + "attachments": attachments, + }, + UserId: th1.BasicUser.Id, + } + th1.App.CreatePost(p2, gmChannel, false) + + posts, err := th1.App.Srv().Store.Post().GetDirectPostParentsForExportAfter(1000, "0000000") + require.Nil(t, err) + assert.Len(t, posts, 2) + require.NotEmpty(t, posts[0].Props) + require.NotEmpty(t, posts[1].Props) + + var b bytes.Buffer + err = th1.App.BulkExport(&b, "somefile", "somePath", "someDir") + require.Nil(t, err) + + th1.TearDown() + + th2 := Setup(t) + defer th2.TearDown() + + posts, err = th2.App.Srv().Store.Post().GetDirectPostParentsForExportAfter(1000, "0000000") + require.Nil(t, err) + assert.Len(t, posts, 0) + + // import the exported posts + err, i := th2.App.BulkImport(&b, false, 5) + assert.Nil(t, err) + assert.Equal(t, 0, i) + + posts, err = th2.App.Srv().Store.Post().GetDirectPostParentsForExportAfter(1000, "0000000") + require.Nil(t, err) + + // Adding some determinism so its possible to assert on slice index + sort.Slice(posts, func(i, j int) bool { return posts[i].Message > posts[j].Message }) + assert.Len(t, posts, 2) + assert.ElementsMatch(t, gmMembers, *posts[0].ChannelMembers) + assert.ElementsMatch(t, dmMembers, *posts[1].ChannelMembers) + assert.Contains(t, posts[0].Props["attachments"].([]interface{})[0], "footer") + assert.Contains(t, posts[1].Props["attachments"].([]interface{})[0], "footer") +} + func TestExportDMPostWithSelf(t *testing.T) { th1 := Setup(t).InitBasic() diff --git a/app/import_functions.go b/app/import_functions.go index 56699afe3b..2a6bbb2122 100644 --- a/app/import_functions.go +++ b/app/import_functions.go @@ -1111,6 +1111,10 @@ func (a *App) importMultiplePosts(data []*PostImportData, dryRun bool) *model.Ap post.CreateAt = *postData.CreateAt post.Hashtags, _ = model.ParseHashtags(post.Message) + if postData.Props != nil { + post.Props = *postData.Props + } + fileIds, err := a.uploadAttachments(postData.Attachments, post, team.Id, dryRun) if err != nil { return err @@ -1382,6 +1386,10 @@ func (a *App) importMultipleDirectPosts(data []*DirectPostImportData, dryRun boo post.CreateAt = *postData.CreateAt post.Hashtags, _ = model.ParseHashtags(post.Message) + if postData.Props != nil { + post.Props = *postData.Props + } + fileIds, err := a.uploadAttachments(postData.Attachments, post, "noteam", dryRun) if err != nil { return err diff --git a/app/import_test.go b/app/import_test.go index e9efc571ec..6d25f1b2fc 100644 --- a/app/import_test.go +++ b/app/import_test.go @@ -210,6 +210,20 @@ func TestImportBulkImport(t *testing.T) { require.NotNil(t, err, "Should have failed due to invalid type on line 2.") require.Equal(t, 2, line, "Should have failed due to invalid type on line 2.") }) + + t.Run("Posts with prop information", func(t *testing.T) { + data6 := `{"type": "version", "version": 1} +{"type": "team", "team": {"type": "O", "display_name": "lskmw2d7a5ao7ppwqh5ljchvr4", "name": "` + teamName + `"}} +{"type": "channel", "channel": {"type": "O", "display_name": "xr6m6udffngark2uekvr3hoeny", "team": "` + teamName + `", "name": "` + channelName + `"}} +{"type": "user", "user": {"username": "` + username + `", "email": "` + username + `@example.com", "teams": [{"name": "` + teamName + `","theme": "` + teamTheme1 + `", "channels": [{"name": "` + channelName + `"}]}]}} +{"type": "post", "post": {"team": "` + teamName + `", "channel": "` + channelName + `", "user": "` + username + `", "message": "Hello World", "create_at": 123456789012, "attachments":[{"path": "` + testImage + `"}], "props":{"attachments":[{"id":0,"fallback":"[February 4th, 2020 2:46 PM] author: fallback","color":"D0D0D0","pretext":"","author_name":"author","author_link":"","title":"","title_link":"","text":"this post has props","fields":null,"image_url":"","thumb_url":"","footer":"Posted in #general","footer_icon":"","ts":"1580823992.000100"}]}}} +{"type": "direct_channel", "direct_channel": {"members": ["` + username + `", "` + username + `"]}} +{"type": "direct_post", "direct_post": {"channel_members": ["` + username + `", "` + username + `"], "user": "` + username + `", "message": "Hello Direct Channel to myself", "create_at": 123456789014, "props":{"attachments":[{"id":0,"fallback":"[February 4th, 2020 2:46 PM] author: fallback","color":"D0D0D0","pretext":"","author_name":"author","author_link":"","title":"","title_link":"","text":"this post has props","fields":null,"image_url":"","thumb_url":"","footer":"Posted in #general","footer_icon":"","ts":"1580823992.000100"}]}}}}` + + err, line := th.App.BulkImport(strings.NewReader(data6), false, 2) + require.Nil(t, err, "BulkImport should have succeeded") + require.Equal(t, 0, line, "BulkImport line should be 0") + }) } func TestImportProcessImportDataFileVersionLine(t *testing.T) { diff --git a/app/import_types.go b/app/import_types.go index 5577c51493..57d517263e 100644 --- a/app/import_types.go +++ b/app/import_types.go @@ -131,8 +131,9 @@ type PostImportData struct { Channel *string `json:"channel"` User *string `json:"user"` - Message *string `json:"message"` - CreateAt *int64 `json:"create_at"` + Message *string `json:"message"` + Props *model.StringInterface `json:"props"` + CreateAt *int64 `json:"create_at"` FlaggedBy *[]string `json:"flagged_by,omitempty"` Reactions *[]ReactionImportData `json:"reactions,omitempty"` @@ -151,8 +152,9 @@ type DirectPostImportData struct { ChannelMembers *[]string `json:"channel_members"` User *string `json:"user"` - Message *string `json:"message"` - CreateAt *int64 `json:"create_at"` + Message *string `json:"message"` + Props *model.StringInterface `json:"props"` + CreateAt *int64 `json:"create_at"` FlaggedBy *[]string `json:"flagged_by"` Reactions *[]ReactionImportData `json:"reactions"`