github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/app/post_test.go (about) 1 // Copyright (c) 2017-present Xenia, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package app 5 6 import ( 7 "fmt" 8 "net/http" 9 "sync" 10 "testing" 11 "time" 12 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 16 "github.com/xzl8028/xenia-server/model" 17 "github.com/xzl8028/xenia-server/store/storetest" 18 ) 19 20 func TestCreatePostDeduplicate(t *testing.T) { 21 th := Setup(t).InitBasic() 22 defer th.TearDown() 23 24 t.Run("duplicate create post is idempotent", func(t *testing.T) { 25 pendingPostId := model.NewId() 26 post, err := th.App.CreatePostAsUser(&model.Post{ 27 UserId: th.BasicUser.Id, 28 ChannelId: th.BasicChannel.Id, 29 Message: "message", 30 PendingPostId: pendingPostId, 31 }, "") 32 require.Nil(t, err) 33 require.Equal(t, "message", post.Message) 34 35 duplicatePost, err := th.App.CreatePostAsUser(&model.Post{ 36 UserId: th.BasicUser.Id, 37 ChannelId: th.BasicChannel.Id, 38 Message: "message", 39 PendingPostId: pendingPostId, 40 }, "") 41 require.Nil(t, err) 42 require.Equal(t, post.Id, duplicatePost.Id, "should have returned previously created post id") 43 require.Equal(t, "message", duplicatePost.Message) 44 }) 45 46 t.Run("post rejected by plugin leaves cache ready for non-deduplicated try", func(t *testing.T) { 47 setupPluginApiTest(t, ` 48 package main 49 50 import ( 51 "github.com/xzl8028/xenia-server/plugin" 52 "github.com/xzl8028/xenia-server/model" 53 ) 54 55 type MyPlugin struct { 56 plugin.XeniaPlugin 57 allow bool 58 } 59 60 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 61 if !p.allow { 62 p.allow = true 63 return nil, "rejected" 64 } 65 66 return nil, "" 67 } 68 69 func main() { 70 plugin.ClientMain(&MyPlugin{}) 71 } 72 `, `{"id": "testrejectfirstpost", "backend": {"executable": "backend.exe"}}`, "testrejectfirstpost", th.App) 73 74 pendingPostId := model.NewId() 75 post, err := th.App.CreatePostAsUser(&model.Post{ 76 UserId: th.BasicUser.Id, 77 ChannelId: th.BasicChannel.Id, 78 Message: "message", 79 PendingPostId: pendingPostId, 80 }, "") 81 require.NotNil(t, err) 82 require.Equal(t, "Post rejected by plugin. rejected", err.Id) 83 require.Nil(t, post) 84 85 duplicatePost, err := th.App.CreatePostAsUser(&model.Post{ 86 UserId: th.BasicUser.Id, 87 ChannelId: th.BasicChannel.Id, 88 Message: "message", 89 PendingPostId: pendingPostId, 90 }, "") 91 require.Nil(t, err) 92 require.Equal(t, "message", duplicatePost.Message) 93 }) 94 95 t.Run("slow posting after cache entry blocks duplicate request", func(t *testing.T) { 96 setupPluginApiTest(t, ` 97 package main 98 99 import ( 100 "github.com/xzl8028/xenia-server/plugin" 101 "github.com/xzl8028/xenia-server/model" 102 "time" 103 ) 104 105 type MyPlugin struct { 106 plugin.XeniaPlugin 107 instant bool 108 } 109 110 func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) { 111 if !p.instant { 112 p.instant = true 113 time.Sleep(3 * time.Second) 114 } 115 116 return nil, "" 117 } 118 119 func main() { 120 plugin.ClientMain(&MyPlugin{}) 121 } 122 `, `{"id": "testdelayfirstpost", "backend": {"executable": "backend.exe"}}`, "testdelayfirstpost", th.App) 123 124 var post *model.Post 125 pendingPostId := model.NewId() 126 127 wg := sync.WaitGroup{} 128 129 // Launch a goroutine to make the first CreatePost call that will get delayed 130 // by the plugin above. 131 wg.Add(1) 132 go func() { 133 defer wg.Done() 134 var err error 135 post, err = th.App.CreatePostAsUser(&model.Post{ 136 UserId: th.BasicUser.Id, 137 ChannelId: th.BasicChannel.Id, 138 Message: "plugin delayed", 139 PendingPostId: pendingPostId, 140 }, "") 141 require.Nil(t, err) 142 require.Equal(t, post.Message, "plugin delayed") 143 }() 144 145 // Give the goroutine above a chance to start and get delayed by the plugin. 146 time.Sleep(2 * time.Second) 147 148 // Try creating a duplicate post 149 duplicatePost, err := th.App.CreatePostAsUser(&model.Post{ 150 UserId: th.BasicUser.Id, 151 ChannelId: th.BasicChannel.Id, 152 Message: "plugin delayed", 153 PendingPostId: pendingPostId, 154 }, "") 155 require.NotNil(t, err) 156 require.Equal(t, "api.post.deduplicate_create_post.pending", err.Id) 157 require.Nil(t, duplicatePost) 158 159 // Wait for the first CreatePost to finish to ensure assertions are made. 160 wg.Wait() 161 }) 162 163 t.Run("duplicate create post after cache expires is not idempotent", func(t *testing.T) { 164 pendingPostId := model.NewId() 165 post, err := th.App.CreatePostAsUser(&model.Post{ 166 UserId: th.BasicUser.Id, 167 ChannelId: th.BasicChannel.Id, 168 Message: "message", 169 PendingPostId: pendingPostId, 170 }, "") 171 require.Nil(t, err) 172 require.Equal(t, "message", post.Message) 173 174 time.Sleep(PENDING_POST_IDS_CACHE_TTL) 175 176 duplicatePost, err := th.App.CreatePostAsUser(&model.Post{ 177 UserId: th.BasicUser.Id, 178 ChannelId: th.BasicChannel.Id, 179 Message: "message", 180 PendingPostId: pendingPostId, 181 }, "") 182 require.Nil(t, err) 183 require.NotEqual(t, post.Id, duplicatePost.Id, "should have created new post id") 184 require.Equal(t, "message", duplicatePost.Message) 185 }) 186 } 187 188 func TestAttachFilesToPost(t *testing.T) { 189 t.Run("should attach files", func(t *testing.T) { 190 th := Setup(t).InitBasic() 191 defer th.TearDown() 192 193 info1, err := th.App.Srv.Store.FileInfo().Save(&model.FileInfo{ 194 CreatorId: th.BasicUser.Id, 195 Path: "path.txt", 196 }) 197 require.Nil(t, err) 198 199 info2, err := th.App.Srv.Store.FileInfo().Save(&model.FileInfo{ 200 CreatorId: th.BasicUser.Id, 201 Path: "path.txt", 202 }) 203 require.Nil(t, err) 204 205 post := th.BasicPost 206 post.FileIds = []string{info1.Id, info2.Id} 207 208 err = th.App.attachFilesToPost(post) 209 assert.Nil(t, err) 210 211 infos, err := th.App.GetFileInfosForPost(post.Id, false) 212 assert.Nil(t, err) 213 assert.Len(t, infos, 2) 214 }) 215 216 t.Run("should update File.PostIds after failing to add files", func(t *testing.T) { 217 th := Setup(t).InitBasic() 218 defer th.TearDown() 219 220 info1, err := th.App.Srv.Store.FileInfo().Save(&model.FileInfo{ 221 CreatorId: th.BasicUser.Id, 222 Path: "path.txt", 223 PostId: model.NewId(), 224 }) 225 require.Nil(t, err) 226 227 info2, err := th.App.Srv.Store.FileInfo().Save(&model.FileInfo{ 228 CreatorId: th.BasicUser.Id, 229 Path: "path.txt", 230 }) 231 require.Nil(t, err) 232 233 post := th.BasicPost 234 post.FileIds = []string{info1.Id, info2.Id} 235 236 err = th.App.attachFilesToPost(post) 237 assert.Nil(t, err) 238 239 infos, err := th.App.GetFileInfosForPost(post.Id, false) 240 assert.Nil(t, err) 241 assert.Len(t, infos, 1) 242 assert.Equal(t, info2.Id, infos[0].Id) 243 244 updated, err := th.App.GetSinglePost(post.Id) 245 require.Nil(t, err) 246 assert.Len(t, updated.FileIds, 1) 247 assert.Contains(t, updated.FileIds, info2.Id) 248 }) 249 } 250 251 func TestUpdatePostEditAt(t *testing.T) { 252 th := Setup(t).InitBasic() 253 defer th.TearDown() 254 255 post := &model.Post{} 256 *post = *th.BasicPost 257 258 post.IsPinned = true 259 if saved, err := th.App.UpdatePost(post, true); err != nil { 260 t.Fatal(err) 261 } else if saved.EditAt != post.EditAt { 262 t.Fatal("shouldn't have updated post.EditAt when pinning post") 263 264 *post = *saved 265 } 266 267 time.Sleep(time.Millisecond * 100) 268 269 post.Message = model.NewId() 270 if saved, err := th.App.UpdatePost(post, true); err != nil { 271 t.Fatal(err) 272 } else if saved.EditAt == post.EditAt { 273 t.Fatal("should have updated post.EditAt when updating post message") 274 } 275 276 time.Sleep(time.Millisecond * 200) 277 } 278 279 func TestUpdatePostTimeLimit(t *testing.T) { 280 th := Setup(t).InitBasic() 281 defer th.TearDown() 282 283 post := &model.Post{} 284 *post = *th.BasicPost 285 286 th.App.SetLicense(model.NewTestLicense()) 287 288 th.App.UpdateConfig(func(cfg *model.Config) { 289 *cfg.ServiceSettings.PostEditTimeLimit = -1 290 }) 291 if _, err := th.App.UpdatePost(post, true); err != nil { 292 t.Fatal(err) 293 } 294 295 th.App.UpdateConfig(func(cfg *model.Config) { 296 *cfg.ServiceSettings.PostEditTimeLimit = 1000000000 297 }) 298 post.Message = model.NewId() 299 if _, err := th.App.UpdatePost(post, true); err != nil { 300 t.Fatal("should allow you to edit the post") 301 } 302 303 th.App.UpdateConfig(func(cfg *model.Config) { 304 *cfg.ServiceSettings.PostEditTimeLimit = 1 305 }) 306 post.Message = model.NewId() 307 if _, err := th.App.UpdatePost(post, true); err == nil { 308 t.Fatal("should fail on update old post") 309 } 310 311 th.App.UpdateConfig(func(cfg *model.Config) { 312 *cfg.ServiceSettings.PostEditTimeLimit = -1 313 }) 314 } 315 316 func TestUpdatePostInArchivedChannel(t *testing.T) { 317 th := Setup(t).InitBasic() 318 defer th.TearDown() 319 320 archivedChannel := th.CreateChannel(th.BasicTeam) 321 post := th.CreatePost(archivedChannel) 322 th.App.DeleteChannel(archivedChannel, "") 323 324 _, err := th.App.UpdatePost(post, true) 325 require.NotNil(t, err) 326 require.Equal(t, "api.post.update_post.can_not_update_post_in_deleted.error", err.Id) 327 } 328 329 func TestPostReplyToPostWhereRootPosterLeftChannel(t *testing.T) { 330 // This test ensures that when replying to a root post made by a user who has since left the channel, the reply 331 // post completes successfully. This is a regression test for PLT-6523. 332 th := Setup(t).InitBasic() 333 defer th.TearDown() 334 335 channel := th.BasicChannel 336 userInChannel := th.BasicUser2 337 userNotInChannel := th.BasicUser 338 rootPost := th.BasicPost 339 340 if _, err := th.App.AddUserToChannel(userInChannel, channel); err != nil { 341 t.Fatal(err) 342 } 343 344 if err := th.App.RemoveUserFromChannel(userNotInChannel.Id, "", channel); err != nil { 345 t.Fatal(err) 346 } 347 348 replyPost := model.Post{ 349 Message: "asd", 350 ChannelId: channel.Id, 351 RootId: rootPost.Id, 352 ParentId: rootPost.Id, 353 PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()), 354 UserId: userInChannel.Id, 355 CreateAt: 0, 356 } 357 358 if _, err := th.App.CreatePostAsUser(&replyPost, ""); err != nil { 359 t.Fatal(err) 360 } 361 } 362 363 func TestPostAttachPostToChildPost(t *testing.T) { 364 th := Setup(t).InitBasic() 365 defer th.TearDown() 366 367 channel := th.BasicChannel 368 user := th.BasicUser 369 rootPost := th.BasicPost 370 371 replyPost1 := model.Post{ 372 Message: "reply one", 373 ChannelId: channel.Id, 374 RootId: rootPost.Id, 375 ParentId: rootPost.Id, 376 PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()), 377 UserId: user.Id, 378 CreateAt: 0, 379 } 380 381 res1, err := th.App.CreatePostAsUser(&replyPost1, "") 382 if err != nil { 383 t.Fatal(err) 384 } 385 386 replyPost2 := model.Post{ 387 Message: "reply two", 388 ChannelId: channel.Id, 389 RootId: res1.Id, 390 ParentId: res1.Id, 391 PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()), 392 UserId: user.Id, 393 CreateAt: 0, 394 } 395 396 _, err = th.App.CreatePostAsUser(&replyPost2, "") 397 if err.StatusCode != http.StatusBadRequest { 398 t.Fatal(fmt.Sprintf("Expected BadRequest error, got %v", err)) 399 } 400 401 replyPost3 := model.Post{ 402 Message: "reply three", 403 ChannelId: channel.Id, 404 RootId: rootPost.Id, 405 ParentId: rootPost.Id, 406 PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()), 407 UserId: user.Id, 408 CreateAt: 0, 409 } 410 411 if _, err := th.App.CreatePostAsUser(&replyPost3, ""); err != nil { 412 t.Fatal(err) 413 } 414 } 415 416 func TestPostChannelMentions(t *testing.T) { 417 th := Setup(t).InitBasic() 418 defer th.TearDown() 419 420 channel := th.BasicChannel 421 user := th.BasicUser 422 423 channelToMention, err := th.App.CreateChannel(&model.Channel{ 424 DisplayName: "Mention Test", 425 Name: "mention-test", 426 Type: model.CHANNEL_OPEN, 427 TeamId: th.BasicTeam.Id, 428 }, false) 429 if err != nil { 430 t.Fatal(err.Error()) 431 } 432 defer th.App.PermanentDeleteChannel(channelToMention) 433 434 _, err = th.App.AddUserToChannel(user, channel) 435 require.Nil(t, err) 436 437 post := &model.Post{ 438 Message: fmt.Sprintf("hello, ~%v!", channelToMention.Name), 439 ChannelId: channel.Id, 440 PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()), 441 UserId: user.Id, 442 CreateAt: 0, 443 } 444 445 result, err := th.App.CreatePostAsUser(post, "") 446 require.Nil(t, err) 447 assert.Equal(t, map[string]interface{}{ 448 "mention-test": map[string]interface{}{ 449 "display_name": "Mention Test", 450 }, 451 }, result.Props["channel_mentions"]) 452 453 post.Message = fmt.Sprintf("goodbye, ~%v!", channelToMention.Name) 454 result, err = th.App.UpdatePost(post, false) 455 require.Nil(t, err) 456 assert.Equal(t, map[string]interface{}{ 457 "mention-test": map[string]interface{}{ 458 "display_name": "Mention Test", 459 }, 460 }, result.Props["channel_mentions"]) 461 } 462 463 func TestImageProxy(t *testing.T) { 464 th := Setup(t).InitBasic() 465 defer th.TearDown() 466 467 th.App.UpdateConfig(func(cfg *model.Config) { 468 *cfg.ServiceSettings.SiteURL = "http://myxenia.com" 469 }) 470 471 for name, tc := range map[string]struct { 472 ProxyType string 473 ProxyURL string 474 ProxyOptions string 475 ImageURL string 476 ProxiedImageURL string 477 }{ 478 "atmos/camo": { 479 ProxyType: model.IMAGE_PROXY_TYPE_ATMOS_CAMO, 480 ProxyURL: "https://127.0.0.1", 481 ProxyOptions: "foo", 482 ImageURL: "http://mydomain.com/myimage", 483 ProxiedImageURL: "http://myxenia.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage", 484 }, 485 "atmos/camo_SameSite": { 486 ProxyType: model.IMAGE_PROXY_TYPE_ATMOS_CAMO, 487 ProxyURL: "https://127.0.0.1", 488 ProxyOptions: "foo", 489 ImageURL: "http://myxenia.com/myimage", 490 ProxiedImageURL: "http://myxenia.com/myimage", 491 }, 492 "atmos/camo_PathOnly": { 493 ProxyType: model.IMAGE_PROXY_TYPE_ATMOS_CAMO, 494 ProxyURL: "https://127.0.0.1", 495 ProxyOptions: "foo", 496 ImageURL: "/myimage", 497 ProxiedImageURL: "/myimage", 498 }, 499 "atmos/camo_EmptyImageURL": { 500 ProxyType: model.IMAGE_PROXY_TYPE_ATMOS_CAMO, 501 ProxyURL: "https://127.0.0.1", 502 ProxyOptions: "foo", 503 ImageURL: "", 504 ProxiedImageURL: "", 505 }, 506 "local": { 507 ProxyType: model.IMAGE_PROXY_TYPE_LOCAL, 508 ImageURL: "http://mydomain.com/myimage", 509 ProxiedImageURL: "http://myxenia.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage", 510 }, 511 "local_SameSite": { 512 ProxyType: model.IMAGE_PROXY_TYPE_LOCAL, 513 ImageURL: "http://myxenia.com/myimage", 514 ProxiedImageURL: "http://myxenia.com/myimage", 515 }, 516 "local_PathOnly": { 517 ProxyType: model.IMAGE_PROXY_TYPE_LOCAL, 518 ImageURL: "/myimage", 519 ProxiedImageURL: "/myimage", 520 }, 521 "local_EmptyImageURL": { 522 ProxyType: model.IMAGE_PROXY_TYPE_LOCAL, 523 ImageURL: "", 524 ProxiedImageURL: "", 525 }, 526 } { 527 t.Run(name, func(t *testing.T) { 528 th.App.UpdateConfig(func(cfg *model.Config) { 529 cfg.ImageProxySettings.Enable = model.NewBool(true) 530 cfg.ImageProxySettings.ImageProxyType = model.NewString(tc.ProxyType) 531 cfg.ImageProxySettings.RemoteImageProxyOptions = model.NewString(tc.ProxyOptions) 532 cfg.ImageProxySettings.RemoteImageProxyURL = model.NewString(tc.ProxyURL) 533 }) 534 535 post := &model.Post{ 536 Id: model.NewId(), 537 Message: "![foo](" + tc.ImageURL + ")", 538 } 539 540 list := model.NewPostList() 541 list.Posts[post.Id] = post 542 543 assert.Equal(t, "![foo]("+tc.ProxiedImageURL+")", th.App.PostWithProxyAddedToImageURLs(post).Message) 544 545 assert.Equal(t, "![foo]("+tc.ImageURL+")", th.App.PostWithProxyRemovedFromImageURLs(post).Message) 546 post.Message = "![foo](" + tc.ProxiedImageURL + ")" 547 assert.Equal(t, "![foo]("+tc.ImageURL+")", th.App.PostWithProxyRemovedFromImageURLs(post).Message) 548 549 if tc.ImageURL != "" { 550 post.Message = "![foo](" + tc.ImageURL + " =500x200)" 551 assert.Equal(t, "![foo]("+tc.ProxiedImageURL+" =500x200)", th.App.PostWithProxyAddedToImageURLs(post).Message) 552 assert.Equal(t, "![foo]("+tc.ImageURL+" =500x200)", th.App.PostWithProxyRemovedFromImageURLs(post).Message) 553 post.Message = "![foo](" + tc.ProxiedImageURL + " =500x200)" 554 assert.Equal(t, "![foo]("+tc.ImageURL+" =500x200)", th.App.PostWithProxyRemovedFromImageURLs(post).Message) 555 } 556 }) 557 } 558 } 559 560 func TestMaxPostSize(t *testing.T) { 561 t.Parallel() 562 563 testCases := []struct { 564 Description string 565 StoreMaxPostSize int 566 ExpectedMaxPostSize int 567 }{ 568 { 569 "Max post size less than model.model.POST_MESSAGE_MAX_RUNES_V1 ", 570 0, 571 model.POST_MESSAGE_MAX_RUNES_V1, 572 }, 573 { 574 "4000 rune limit", 575 4000, 576 4000, 577 }, 578 { 579 "16383 rune limit", 580 16383, 581 16383, 582 }, 583 } 584 585 for _, testCase := range testCases { 586 testCase := testCase 587 t.Run(testCase.Description, func(t *testing.T) { 588 t.Parallel() 589 590 mockStore := &storetest.Store{} 591 defer mockStore.AssertExpectations(t) 592 593 mockStore.PostStore.On("GetMaxPostSize").Return(testCase.StoreMaxPostSize) 594 595 app := App{ 596 Srv: &Server{ 597 Store: mockStore, 598 }, 599 } 600 601 assert.Equal(t, testCase.ExpectedMaxPostSize, app.MaxPostSize()) 602 }) 603 } 604 } 605 606 func TestDeletePostWithFileAttachments(t *testing.T) { 607 th := Setup(t).InitBasic() 608 defer th.TearDown() 609 610 // Create a post with a file attachment. 611 teamId := th.BasicTeam.Id 612 channelId := th.BasicChannel.Id 613 userId := th.BasicUser.Id 614 filename := "test" 615 data := []byte("abcd") 616 617 info1, err := th.App.DoUploadFile(time.Date(2007, 2, 4, 1, 2, 3, 4, time.Local), teamId, channelId, userId, filename, data) 618 if err != nil { 619 t.Fatal(err) 620 } else { 621 defer func() { 622 th.App.Srv.Store.FileInfo().PermanentDelete(info1.Id) 623 th.App.RemoveFile(info1.Path) 624 }() 625 } 626 627 post := &model.Post{ 628 Message: "asd", 629 ChannelId: channelId, 630 PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()), 631 UserId: userId, 632 CreateAt: 0, 633 FileIds: []string{info1.Id}, 634 } 635 636 post, err = th.App.CreatePost(post, th.BasicChannel, false) 637 assert.Nil(t, err) 638 639 // Delete the post. 640 post, err = th.App.DeletePost(post.Id, userId) 641 assert.Nil(t, err) 642 643 // Wait for the cleanup routine to finish. 644 time.Sleep(time.Millisecond * 100) 645 646 // Check that the file can no longer be reached. 647 _, err = th.App.GetFileInfo(info1.Id) 648 assert.NotNil(t, err) 649 } 650 651 func TestDeletePostInArchivedChannel(t *testing.T) { 652 th := Setup(t).InitBasic() 653 defer th.TearDown() 654 655 archivedChannel := th.CreateChannel(th.BasicTeam) 656 post := th.CreatePost(archivedChannel) 657 th.App.DeleteChannel(archivedChannel, "") 658 659 _, err := th.App.DeletePost(post.Id, "") 660 require.NotNil(t, err) 661 require.Equal(t, "api.post.delete_post.can_not_delete_post_in_deleted.error", err.Id) 662 } 663 664 func TestCreatePost(t *testing.T) { 665 t.Run("call PreparePostForClient before returning", func(t *testing.T) { 666 th := Setup(t).InitBasic() 667 defer th.TearDown() 668 669 th.App.UpdateConfig(func(cfg *model.Config) { 670 *cfg.ServiceSettings.SiteURL = "http://myxenia.com" 671 *cfg.ImageProxySettings.Enable = true 672 *cfg.ImageProxySettings.ImageProxyType = "atmos/camo" 673 *cfg.ImageProxySettings.RemoteImageProxyURL = "https://127.0.0.1" 674 *cfg.ImageProxySettings.RemoteImageProxyOptions = "foo" 675 }) 676 677 imageURL := "http://mydomain.com/myimage" 678 proxiedImageURL := "http://myxenia.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage" 679 680 post := &model.Post{ 681 ChannelId: th.BasicChannel.Id, 682 Message: "![image](" + imageURL + ")", 683 UserId: th.BasicUser.Id, 684 } 685 686 rpost, err := th.App.CreatePost(post, th.BasicChannel, false) 687 require.Nil(t, err) 688 assert.Equal(t, "![image]("+proxiedImageURL+")", rpost.Message) 689 }) 690 } 691 692 func TestPatchPost(t *testing.T) { 693 t.Run("call PreparePostForClient before returning", func(t *testing.T) { 694 th := Setup(t).InitBasic() 695 defer th.TearDown() 696 697 th.App.UpdateConfig(func(cfg *model.Config) { 698 *cfg.ServiceSettings.SiteURL = "http://myxenia.com" 699 *cfg.ImageProxySettings.Enable = true 700 *cfg.ImageProxySettings.ImageProxyType = "atmos/camo" 701 *cfg.ImageProxySettings.RemoteImageProxyURL = "https://127.0.0.1" 702 *cfg.ImageProxySettings.RemoteImageProxyOptions = "foo" 703 }) 704 705 imageURL := "http://mydomain.com/myimage" 706 proxiedImageURL := "http://myxenia.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage" 707 708 post := &model.Post{ 709 ChannelId: th.BasicChannel.Id, 710 Message: "![image](http://mydomain/anotherimage)", 711 UserId: th.BasicUser.Id, 712 } 713 714 rpost, err := th.App.CreatePost(post, th.BasicChannel, false) 715 require.Nil(t, err) 716 assert.NotEqual(t, "![image]("+proxiedImageURL+")", rpost.Message) 717 718 patch := &model.PostPatch{ 719 Message: model.NewString("![image](" + imageURL + ")"), 720 } 721 722 rpost, err = th.App.PatchPost(rpost.Id, patch) 723 require.Nil(t, err) 724 assert.Equal(t, "![image]("+proxiedImageURL+")", rpost.Message) 725 }) 726 } 727 728 func TestPatchPostInArchivedChannel(t *testing.T) { 729 th := Setup(t).InitBasic() 730 defer th.TearDown() 731 732 archivedChannel := th.CreateChannel(th.BasicTeam) 733 post := th.CreatePost(archivedChannel) 734 th.App.DeleteChannel(archivedChannel, "") 735 736 _, err := th.App.PatchPost(post.Id, &model.PostPatch{IsPinned: model.NewBool(true)}) 737 require.NotNil(t, err) 738 require.Equal(t, "api.post.patch_post.can_not_update_post_in_deleted.error", err.Id) 739 } 740 741 func TestUpdatePost(t *testing.T) { 742 t.Run("call PreparePostForClient before returning", func(t *testing.T) { 743 th := Setup(t).InitBasic() 744 defer th.TearDown() 745 746 th.App.UpdateConfig(func(cfg *model.Config) { 747 *cfg.ServiceSettings.SiteURL = "http://myxenia.com" 748 *cfg.ImageProxySettings.Enable = true 749 *cfg.ImageProxySettings.ImageProxyType = "atmos/camo" 750 *cfg.ImageProxySettings.RemoteImageProxyURL = "https://127.0.0.1" 751 *cfg.ImageProxySettings.RemoteImageProxyOptions = "foo" 752 }) 753 754 imageURL := "http://mydomain.com/myimage" 755 proxiedImageURL := "http://myxenia.com/api/v4/image?url=http%3A%2F%2Fmydomain.com%2Fmyimage" 756 757 post := &model.Post{ 758 ChannelId: th.BasicChannel.Id, 759 Message: "![image](http://mydomain/anotherimage)", 760 UserId: th.BasicUser.Id, 761 } 762 763 rpost, err := th.App.CreatePost(post, th.BasicChannel, false) 764 require.Nil(t, err) 765 assert.NotEqual(t, "![image]("+proxiedImageURL+")", rpost.Message) 766 767 post.Id = rpost.Id 768 post.Message = "![image](" + imageURL + ")" 769 770 rpost, err = th.App.UpdatePost(post, false) 771 require.Nil(t, err) 772 assert.Equal(t, "![image]("+proxiedImageURL+")", rpost.Message) 773 }) 774 }