github.com/turgay/mattermost-server@v5.3.2-0.20181002173352-2945e8a2b0ce+incompatible/api4/post_test.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package api4 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "net/http" 10 "net/http/httptest" 11 "net/url" 12 "reflect" 13 "strconv" 14 "strings" 15 "testing" 16 "time" 17 18 "github.com/stretchr/testify/assert" 19 20 "github.com/mattermost/mattermost-server/app" 21 "github.com/mattermost/mattermost-server/model" 22 "github.com/mattermost/mattermost-server/utils" 23 ) 24 25 func TestCreatePost(t *testing.T) { 26 th := Setup().InitBasic().InitSystemAdmin() 27 defer th.TearDown() 28 Client := th.Client 29 30 post := &model.Post{ChannelId: th.BasicChannel.Id, Message: "#hashtag a" + model.NewId() + "a", Props: model.StringInterface{model.PROPS_ADD_CHANNEL_MEMBER: "no good"}} 31 rpost, resp := Client.CreatePost(post) 32 CheckNoError(t, resp) 33 CheckCreatedStatus(t, resp) 34 35 if rpost.Message != post.Message { 36 t.Fatal("message didn't match") 37 } 38 39 if rpost.Hashtags != "#hashtag" { 40 t.Fatal("hashtag didn't match") 41 } 42 43 if len(rpost.FileIds) != 0 { 44 t.Fatal("shouldn't have files") 45 } 46 47 if rpost.EditAt != 0 { 48 t.Fatal("newly created post shouldn't have EditAt set") 49 } 50 51 if rpost.Props[model.PROPS_ADD_CHANNEL_MEMBER] != nil { 52 t.Fatal("newly created post shouldn't have Props['add_channel_member'] set") 53 } 54 55 post.RootId = rpost.Id 56 post.ParentId = rpost.Id 57 _, resp = Client.CreatePost(post) 58 CheckNoError(t, resp) 59 60 post.RootId = "junk" 61 _, resp = Client.CreatePost(post) 62 CheckBadRequestStatus(t, resp) 63 64 post.RootId = rpost.Id 65 post.ParentId = "junk" 66 _, resp = Client.CreatePost(post) 67 CheckBadRequestStatus(t, resp) 68 69 post2 := &model.Post{ChannelId: th.BasicChannel2.Id, Message: "zz" + model.NewId() + "a", CreateAt: 123} 70 rpost2, _ := Client.CreatePost(post2) 71 72 if rpost2.CreateAt == post2.CreateAt { 73 t.Fatal("create at should not match") 74 } 75 76 post.RootId = "" 77 post.ParentId = "" 78 post.Type = model.POST_SYSTEM_GENERIC 79 _, resp = Client.CreatePost(post) 80 CheckBadRequestStatus(t, resp) 81 82 post.Type = "" 83 post.RootId = rpost2.Id 84 post.ParentId = rpost2.Id 85 _, resp = Client.CreatePost(post) 86 CheckBadRequestStatus(t, resp) 87 88 post.RootId = "" 89 post.ParentId = "" 90 post.ChannelId = "junk" 91 _, resp = Client.CreatePost(post) 92 CheckForbiddenStatus(t, resp) 93 94 post.ChannelId = model.NewId() 95 _, resp = Client.CreatePost(post) 96 CheckForbiddenStatus(t, resp) 97 98 if r, err := Client.DoApiPost("/posts", "garbage"); err == nil { 99 t.Fatal("should have errored") 100 } else { 101 if r.StatusCode != http.StatusBadRequest { 102 t.Log("actual: " + strconv.Itoa(r.StatusCode)) 103 t.Log("expected: " + strconv.Itoa(http.StatusBadRequest)) 104 t.Fatal("wrong status code") 105 } 106 } 107 108 Client.Logout() 109 _, resp = Client.CreatePost(post) 110 CheckUnauthorizedStatus(t, resp) 111 112 post.ChannelId = th.BasicChannel.Id 113 post.CreateAt = 123 114 rpost, resp = th.SystemAdminClient.CreatePost(post) 115 CheckNoError(t, resp) 116 117 if rpost.CreateAt != post.CreateAt { 118 t.Fatal("create at should match") 119 } 120 } 121 122 func TestCreatePostEphemeral(t *testing.T) { 123 th := Setup().InitBasic().InitSystemAdmin() 124 defer th.TearDown() 125 Client := th.SystemAdminClient 126 127 ephemeralPost := &model.PostEphemeral{ 128 UserID: th.BasicUser2.Id, 129 Post: &model.Post{ChannelId: th.BasicChannel.Id, Message: "a" + model.NewId() + "a", Props: model.StringInterface{model.PROPS_ADD_CHANNEL_MEMBER: "no good"}}, 130 } 131 132 rpost, resp := Client.CreatePostEphemeral(ephemeralPost) 133 CheckNoError(t, resp) 134 CheckCreatedStatus(t, resp) 135 136 if rpost.Message != ephemeralPost.Post.Message { 137 t.Fatal("message didn't match") 138 } 139 140 if rpost.EditAt != 0 { 141 t.Fatal("newly created ephemeral post shouldn't have EditAt set") 142 } 143 144 if r, err := Client.DoApiPost("/posts/ephemeral", "garbage"); err == nil { 145 t.Fatal("should have errored") 146 } else { 147 if r.StatusCode != http.StatusBadRequest { 148 t.Log("actual: " + strconv.Itoa(r.StatusCode)) 149 t.Log("expected: " + strconv.Itoa(http.StatusBadRequest)) 150 t.Fatal("wrong status code") 151 } 152 } 153 154 Client.Logout() 155 _, resp = Client.CreatePostEphemeral(ephemeralPost) 156 CheckUnauthorizedStatus(t, resp) 157 158 Client = th.Client 159 _, resp = Client.CreatePostEphemeral(ephemeralPost) 160 CheckForbiddenStatus(t, resp) 161 } 162 163 func testCreatePostWithOutgoingHook( 164 t *testing.T, 165 hookContentType, expectedContentType, message, triggerWord string, 166 fileIds []string, 167 triggerWhen int, 168 commentPostType bool, 169 ) { 170 th := Setup().InitBasic().InitSystemAdmin() 171 defer th.TearDown() 172 user := th.SystemAdminUser 173 team := th.BasicTeam 174 channel := th.BasicChannel 175 176 enableOutgoingWebhooks := th.App.Config().ServiceSettings.EnableOutgoingWebhooks 177 allowedUntrustedInternalConnections := th.App.Config().ServiceSettings.AllowedUntrustedInternalConnections 178 defer func() { 179 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingWebhooks }) 180 th.App.UpdateConfig(func(cfg *model.Config) { 181 cfg.ServiceSettings.AllowedUntrustedInternalConnections = allowedUntrustedInternalConnections 182 }) 183 }() 184 185 th.App.UpdateConfig(func(cfg *model.Config) { cfg.ServiceSettings.EnableOutgoingWebhooks = true }) 186 th.App.UpdateConfig(func(cfg *model.Config) { 187 *cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost 127.0.0.1" 188 }) 189 190 var hook *model.OutgoingWebhook 191 var post *model.Post 192 193 // Create a test server that is the target of the outgoing webhook. It will 194 // validate the webhook body fields and write to the success channel on 195 // success/failure. 196 success := make(chan bool) 197 wait := make(chan bool, 1) 198 ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 199 <-wait 200 201 requestContentType := r.Header.Get("Content-Type") 202 if requestContentType != expectedContentType { 203 t.Logf("Content-Type is %s, should be %s", requestContentType, expectedContentType) 204 success <- false 205 return 206 } 207 208 expectedPayload := &model.OutgoingWebhookPayload{ 209 Token: hook.Token, 210 TeamId: hook.TeamId, 211 TeamDomain: team.Name, 212 ChannelId: post.ChannelId, 213 ChannelName: channel.Name, 214 Timestamp: post.CreateAt, 215 UserId: post.UserId, 216 UserName: user.Username, 217 PostId: post.Id, 218 Text: post.Message, 219 TriggerWord: triggerWord, 220 FileIds: strings.Join(post.FileIds, ","), 221 } 222 223 // depending on the Content-Type, we expect to find a JSON or form encoded payload 224 if requestContentType == "application/json" { 225 decoder := json.NewDecoder(r.Body) 226 o := &model.OutgoingWebhookPayload{} 227 decoder.Decode(&o) 228 229 if !reflect.DeepEqual(expectedPayload, o) { 230 t.Logf("JSON payload is %+v, should be %+v", o, expectedPayload) 231 success <- false 232 return 233 } 234 } else { 235 err := r.ParseForm() 236 if err != nil { 237 t.Logf("Error parsing form: %q", err) 238 success <- false 239 return 240 } 241 242 expectedFormValues, _ := url.ParseQuery(expectedPayload.ToFormValues()) 243 244 if !reflect.DeepEqual(expectedFormValues, r.Form) { 245 t.Logf("Form values are: %q\n, should be: %q\n", r.Form, expectedFormValues) 246 success <- false 247 return 248 } 249 } 250 251 respPostType := "" //if is empty or post will do a normal post. 252 if commentPostType { 253 respPostType = model.OUTGOING_HOOK_RESPONSE_TYPE_COMMENT 254 } 255 256 outGoingHookResponse := &model.OutgoingWebhookResponse{ 257 Text: model.NewString("some test text"), 258 Username: "TestCommandServer", 259 IconURL: "https://www.mattermost.org/wp-content/uploads/2016/04/icon.png", 260 Type: "custom_as", 261 ResponseType: respPostType, 262 } 263 264 fmt.Fprintf(w, outGoingHookResponse.ToJson()) 265 success <- true 266 })) 267 defer ts.Close() 268 269 // create an outgoing webhook, passing it the test server URL 270 var triggerWords []string 271 if triggerWord != "" { 272 triggerWords = []string{triggerWord} 273 } 274 275 hook = &model.OutgoingWebhook{ 276 ChannelId: channel.Id, 277 TeamId: team.Id, 278 ContentType: hookContentType, 279 TriggerWords: triggerWords, 280 TriggerWhen: triggerWhen, 281 CallbackURLs: []string{ts.URL}, 282 } 283 284 hook, resp := th.SystemAdminClient.CreateOutgoingWebhook(hook) 285 CheckNoError(t, resp) 286 287 // create a post to trigger the webhook 288 post = &model.Post{ 289 ChannelId: channel.Id, 290 Message: message, 291 FileIds: fileIds, 292 } 293 294 post, resp = th.SystemAdminClient.CreatePost(post) 295 CheckNoError(t, resp) 296 297 wait <- true 298 299 // We wait for the test server to write to the success channel and we make 300 // the test fail if that doesn't happen before the timeout. 301 select { 302 case ok := <-success: 303 if !ok { 304 t.Fatal("Test server did send an invalid webhook.") 305 } 306 case <-time.After(time.Second): 307 t.Fatal("Timeout, test server did not send the webhook.") 308 } 309 310 if commentPostType { 311 time.Sleep(time.Millisecond * 100) 312 postList, resp := th.SystemAdminClient.GetPostThread(post.Id, "") 313 CheckNoError(t, resp) 314 if postList.Order[0] != post.Id { 315 t.Fatal("wrong order") 316 } 317 318 if _, ok := postList.Posts[post.Id]; !ok { 319 t.Fatal("should have had post") 320 } 321 322 if len(postList.Posts) != 2 { 323 t.Fatal("should have 2 posts") 324 } 325 326 } 327 } 328 329 func TestCreatePostWithOutgoingHook_form_urlencoded(t *testing.T) { 330 testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false) 331 testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false) 332 testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false) 333 testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false) 334 testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, true) 335 testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, true) 336 } 337 338 func TestCreatePostWithOutgoingHook_json(t *testing.T) { 339 testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, false) 340 testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH, false) 341 testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false) 342 testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false) 343 testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, true) 344 testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, true) 345 } 346 347 // hooks created before we added the ContentType field should be considered as 348 // application/x-www-form-urlencoded 349 func TestCreatePostWithOutgoingHook_no_content_type(t *testing.T) { 350 testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false) 351 testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false) 352 testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, false) 353 testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH, false) 354 testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, true) 355 testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, true) 356 } 357 358 func TestCreatePostPublic(t *testing.T) { 359 th := Setup().InitBasic().InitSystemAdmin() 360 defer th.TearDown() 361 Client := th.Client 362 363 post := &model.Post{ChannelId: th.BasicChannel.Id, Message: "#hashtag a" + model.NewId() + "a"} 364 365 user := model.User{Email: th.GenerateTestEmail(), Nickname: "Joram Wilander", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SYSTEM_USER_ROLE_ID} 366 367 ruser, resp := Client.CreateUser(&user) 368 CheckNoError(t, resp) 369 370 Client.Login(user.Email, user.Password) 371 372 _, resp = Client.CreatePost(post) 373 CheckForbiddenStatus(t, resp) 374 375 th.App.UpdateUserRoles(ruser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_POST_ALL_PUBLIC_ROLE_ID, false) 376 th.App.InvalidateAllCaches() 377 378 Client.Login(user.Email, user.Password) 379 380 _, resp = Client.CreatePost(post) 381 CheckNoError(t, resp) 382 383 post.ChannelId = th.BasicPrivateChannel.Id 384 _, resp = Client.CreatePost(post) 385 CheckForbiddenStatus(t, resp) 386 387 th.App.UpdateUserRoles(ruser.Id, model.SYSTEM_USER_ROLE_ID, false) 388 th.App.JoinUserToTeam(th.BasicTeam, ruser, "") 389 th.App.UpdateTeamMemberRoles(th.BasicTeam.Id, ruser.Id, model.TEAM_USER_ROLE_ID+" "+model.TEAM_POST_ALL_PUBLIC_ROLE_ID) 390 th.App.InvalidateAllCaches() 391 392 Client.Login(user.Email, user.Password) 393 394 post.ChannelId = th.BasicPrivateChannel.Id 395 _, resp = Client.CreatePost(post) 396 CheckForbiddenStatus(t, resp) 397 398 post.ChannelId = th.BasicChannel.Id 399 _, resp = Client.CreatePost(post) 400 CheckNoError(t, resp) 401 } 402 403 func TestCreatePostAll(t *testing.T) { 404 th := Setup().InitBasic().InitSystemAdmin() 405 defer th.TearDown() 406 Client := th.Client 407 408 post := &model.Post{ChannelId: th.BasicChannel.Id, Message: "#hashtag a" + model.NewId() + "a"} 409 410 user := model.User{Email: th.GenerateTestEmail(), Nickname: "Joram Wilander", Password: "hello1", Username: GenerateTestUsername(), Roles: model.SYSTEM_USER_ROLE_ID} 411 412 directChannel, _ := th.App.CreateDirectChannel(th.BasicUser.Id, th.BasicUser2.Id) 413 414 ruser, resp := Client.CreateUser(&user) 415 CheckNoError(t, resp) 416 417 Client.Login(user.Email, user.Password) 418 419 _, resp = Client.CreatePost(post) 420 CheckForbiddenStatus(t, resp) 421 422 th.App.UpdateUserRoles(ruser.Id, model.SYSTEM_USER_ROLE_ID+" "+model.SYSTEM_POST_ALL_ROLE_ID, false) 423 th.App.InvalidateAllCaches() 424 425 Client.Login(user.Email, user.Password) 426 427 _, resp = Client.CreatePost(post) 428 CheckNoError(t, resp) 429 430 post.ChannelId = th.BasicPrivateChannel.Id 431 _, resp = Client.CreatePost(post) 432 CheckNoError(t, resp) 433 434 post.ChannelId = directChannel.Id 435 _, resp = Client.CreatePost(post) 436 CheckNoError(t, resp) 437 438 th.App.UpdateUserRoles(ruser.Id, model.SYSTEM_USER_ROLE_ID, false) 439 th.App.JoinUserToTeam(th.BasicTeam, ruser, "") 440 th.App.UpdateTeamMemberRoles(th.BasicTeam.Id, ruser.Id, model.TEAM_USER_ROLE_ID+" "+model.TEAM_POST_ALL_ROLE_ID) 441 th.App.InvalidateAllCaches() 442 443 Client.Login(user.Email, user.Password) 444 445 post.ChannelId = th.BasicPrivateChannel.Id 446 _, resp = Client.CreatePost(post) 447 CheckNoError(t, resp) 448 449 post.ChannelId = th.BasicChannel.Id 450 _, resp = Client.CreatePost(post) 451 CheckNoError(t, resp) 452 453 post.ChannelId = directChannel.Id 454 _, resp = Client.CreatePost(post) 455 CheckForbiddenStatus(t, resp) 456 } 457 458 func TestCreatePostSendOutOfChannelMentions(t *testing.T) { 459 th := Setup().InitBasic().InitSystemAdmin() 460 defer th.TearDown() 461 Client := th.Client 462 463 WebSocketClient, err := th.CreateWebSocketClient() 464 if err != nil { 465 t.Fatal(err) 466 } 467 WebSocketClient.Listen() 468 469 inChannelUser := th.CreateUser() 470 th.LinkUserToTeam(inChannelUser, th.BasicTeam) 471 th.App.AddUserToChannel(inChannelUser, th.BasicChannel) 472 473 post1 := &model.Post{ChannelId: th.BasicChannel.Id, Message: "@" + inChannelUser.Username} 474 _, resp := Client.CreatePost(post1) 475 CheckNoError(t, resp) 476 CheckCreatedStatus(t, resp) 477 478 timeout := time.After(300 * time.Millisecond) 479 waiting := true 480 for waiting { 481 select { 482 case event := <-WebSocketClient.EventChannel: 483 if event.Event == model.WEBSOCKET_EVENT_EPHEMERAL_MESSAGE { 484 t.Fatal("should not have ephemeral message event") 485 } 486 487 case <-timeout: 488 waiting = false 489 } 490 } 491 492 outOfChannelUser := th.CreateUser() 493 th.LinkUserToTeam(outOfChannelUser, th.BasicTeam) 494 495 post2 := &model.Post{ChannelId: th.BasicChannel.Id, Message: "@" + outOfChannelUser.Username} 496 _, resp = Client.CreatePost(post2) 497 CheckNoError(t, resp) 498 CheckCreatedStatus(t, resp) 499 500 timeout = time.After(300 * time.Millisecond) 501 waiting = true 502 for waiting { 503 select { 504 case event := <-WebSocketClient.EventChannel: 505 if event.Event != model.WEBSOCKET_EVENT_EPHEMERAL_MESSAGE { 506 // Ignore any other events 507 continue 508 } 509 510 wpost := model.PostFromJson(strings.NewReader(event.Data["post"].(string))) 511 if acm, ok := wpost.Props[model.PROPS_ADD_CHANNEL_MEMBER].(map[string]interface{}); !ok { 512 t.Fatal("should have received ephemeral post with 'add_channel_member' in props") 513 } else { 514 if acm["post_id"] == nil || acm["user_ids"] == nil || acm["usernames"] == nil { 515 t.Fatal("should not be nil") 516 } 517 } 518 waiting = false 519 case <-timeout: 520 t.Fatal("timed out waiting for ephemeral message event") 521 } 522 } 523 } 524 525 func TestUpdatePost(t *testing.T) { 526 th := Setup().InitBasic().InitSystemAdmin() 527 defer th.TearDown() 528 Client := th.Client 529 channel := th.BasicChannel 530 531 th.App.SetLicense(model.NewTestLicense()) 532 533 post := &model.Post{ChannelId: channel.Id, Message: "zz" + model.NewId() + "a"} 534 rpost, resp := Client.CreatePost(post) 535 CheckNoError(t, resp) 536 537 if rpost.Message != post.Message { 538 t.Fatal("full name didn't match") 539 } 540 541 if rpost.EditAt != 0 { 542 t.Fatal("Newly created post shouldn't have EditAt set") 543 } 544 545 msg := "zz" + model.NewId() + " update post" 546 rpost.Message = msg 547 rpost.UserId = "" 548 549 rupost, resp := Client.UpdatePost(rpost.Id, rpost) 550 CheckNoError(t, resp) 551 552 if rupost.Message != msg { 553 t.Fatal("failed to updates") 554 } 555 if rupost.EditAt == 0 { 556 t.Fatal("EditAt not updated for post") 557 } 558 559 msg1 := "#hashtag a" + model.NewId() + " update post again" 560 rpost.Message = msg1 561 rpost.Props[model.PROPS_ADD_CHANNEL_MEMBER] = "no good" 562 rrupost, resp := Client.UpdatePost(rpost.Id, rpost) 563 CheckNoError(t, resp) 564 565 if rrupost.Message != msg1 && rrupost.Hashtags != "#hashtag" { 566 t.Fatal("failed to updates") 567 } 568 569 if rrupost.Props[model.PROPS_ADD_CHANNEL_MEMBER] != nil { 570 t.Fatal("failed to sanitize Props['add_channel_member'], should be nil") 571 } 572 573 rpost2, err := th.App.CreatePost(&model.Post{ChannelId: channel.Id, Message: "zz" + model.NewId() + "a", Type: model.POST_JOIN_LEAVE, UserId: th.BasicUser.Id}, channel, false) 574 if err != nil { 575 t.Fatal(err) 576 } 577 578 up2 := &model.Post{Id: rpost2.Id, ChannelId: channel.Id, Message: "zz" + model.NewId() + " update post 2"} 579 _, resp = Client.UpdatePost(rpost2.Id, up2) 580 CheckBadRequestStatus(t, resp) 581 582 Client.Logout() 583 _, resp = Client.UpdatePost(rpost.Id, rpost) 584 CheckUnauthorizedStatus(t, resp) 585 586 th.LoginBasic2() 587 _, resp = Client.UpdatePost(rpost.Id, rpost) 588 CheckForbiddenStatus(t, resp) 589 590 Client.Logout() 591 592 th.LoginTeamAdmin() 593 _, resp = Client.UpdatePost(rpost.Id, rpost) 594 CheckForbiddenStatus(t, resp) 595 596 Client.Logout() 597 598 _, resp = th.SystemAdminClient.UpdatePost(rpost.Id, rpost) 599 CheckNoError(t, resp) 600 } 601 602 func TestUpdateOthersPostInDirectMessageChannel(t *testing.T) { 603 // This test checks that a sysadmin with the "EDIT_OTHERS_POSTS" permission can edit someone else's post in a 604 // channel without a team (DM/GM). This indirectly checks for the proper cascading all the way to system-wide roles 605 // on the user object of permissions based on a post in a channel with no team ID. 606 th := Setup().InitBasic().InitSystemAdmin() 607 defer th.TearDown() 608 609 dmChannel := th.CreateDmChannel(th.SystemAdminUser) 610 611 post := &model.Post{ 612 Message: "asd", 613 ChannelId: dmChannel.Id, 614 PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()), 615 UserId: th.BasicUser.Id, 616 CreateAt: 0, 617 } 618 619 post, resp := th.Client.CreatePost(post) 620 CheckNoError(t, resp) 621 622 post.Message = "changed" 623 post, resp = th.SystemAdminClient.UpdatePost(post.Id, post) 624 CheckNoError(t, resp) 625 } 626 627 func TestPatchPost(t *testing.T) { 628 th := Setup().InitBasic().InitSystemAdmin() 629 defer th.TearDown() 630 Client := th.Client 631 channel := th.BasicChannel 632 633 th.App.SetLicense(model.NewTestLicense()) 634 635 post := &model.Post{ 636 ChannelId: channel.Id, 637 IsPinned: true, 638 Message: "#hashtag a message", 639 Props: model.StringInterface{"channel_header": "old_header"}, 640 FileIds: model.StringArray{"file1", "file2"}, 641 HasReactions: true, 642 } 643 post, _ = Client.CreatePost(post) 644 645 patch := &model.PostPatch{} 646 647 patch.IsPinned = model.NewBool(false) 648 patch.Message = model.NewString("#otherhashtag other message") 649 patch.Props = new(model.StringInterface) 650 *patch.Props = model.StringInterface{"channel_header": "new_header"} 651 patch.FileIds = new(model.StringArray) 652 *patch.FileIds = model.StringArray{"file1", "otherfile2", "otherfile3"} 653 patch.HasReactions = model.NewBool(false) 654 655 rpost, resp := Client.PatchPost(post.Id, patch) 656 CheckNoError(t, resp) 657 658 if rpost.IsPinned { 659 t.Fatal("IsPinned did not update properly") 660 } 661 if rpost.Message != "#otherhashtag other message" { 662 t.Fatal("Message did not update properly") 663 } 664 if len(rpost.Props) != 1 { 665 t.Fatal("Props did not update properly") 666 } 667 if !reflect.DeepEqual(rpost.Props, *patch.Props) { 668 t.Fatal("Props did not update properly") 669 } 670 if rpost.Hashtags != "#otherhashtag" { 671 t.Fatal("Message did not update properly") 672 } 673 if len(rpost.FileIds) != 3 { 674 t.Fatal("FileIds did not update properly") 675 } 676 if !reflect.DeepEqual(rpost.FileIds, *patch.FileIds) { 677 t.Fatal("FileIds did not update properly") 678 } 679 if rpost.HasReactions { 680 t.Fatal("HasReactions did not update properly") 681 } 682 683 if r, err := Client.DoApiPut("/posts/"+post.Id+"/patch", "garbage"); err == nil { 684 t.Fatal("should have errored") 685 } else { 686 if r.StatusCode != http.StatusBadRequest { 687 t.Log("actual: " + strconv.Itoa(r.StatusCode)) 688 t.Log("expected: " + strconv.Itoa(http.StatusBadRequest)) 689 t.Fatal("wrong status code") 690 } 691 } 692 693 _, resp = Client.PatchPost("junk", patch) 694 CheckBadRequestStatus(t, resp) 695 696 _, resp = Client.PatchPost(GenerateTestId(), patch) 697 CheckForbiddenStatus(t, resp) 698 699 Client.Logout() 700 _, resp = Client.PatchPost(post.Id, patch) 701 CheckUnauthorizedStatus(t, resp) 702 703 th.LoginBasic2() 704 _, resp = Client.PatchPost(post.Id, patch) 705 CheckForbiddenStatus(t, resp) 706 707 th.LoginTeamAdmin() 708 _, resp = Client.PatchPost(post.Id, patch) 709 CheckForbiddenStatus(t, resp) 710 711 _, resp = th.SystemAdminClient.PatchPost(post.Id, patch) 712 CheckNoError(t, resp) 713 } 714 715 func TestPinPost(t *testing.T) { 716 th := Setup().InitBasic().InitSystemAdmin() 717 defer th.TearDown() 718 Client := th.Client 719 720 post := th.BasicPost 721 pass, resp := Client.PinPost(post.Id) 722 CheckNoError(t, resp) 723 724 if !pass { 725 t.Fatal("should have passed") 726 } 727 728 if rpost, err := th.App.GetSinglePost(post.Id); err != nil && !rpost.IsPinned { 729 t.Fatal("failed to pin post") 730 } 731 732 pass, resp = Client.PinPost("junk") 733 CheckBadRequestStatus(t, resp) 734 735 if pass { 736 t.Fatal("should have failed") 737 } 738 739 _, resp = Client.PinPost(GenerateTestId()) 740 CheckForbiddenStatus(t, resp) 741 742 Client.Logout() 743 _, resp = Client.PinPost(post.Id) 744 CheckUnauthorizedStatus(t, resp) 745 746 _, resp = th.SystemAdminClient.PinPost(post.Id) 747 CheckNoError(t, resp) 748 } 749 750 func TestUnpinPost(t *testing.T) { 751 th := Setup().InitBasic().InitSystemAdmin() 752 defer th.TearDown() 753 Client := th.Client 754 755 pinnedPost := th.CreatePinnedPost() 756 pass, resp := Client.UnpinPost(pinnedPost.Id) 757 CheckNoError(t, resp) 758 759 if !pass { 760 t.Fatal("should have passed") 761 } 762 763 if rpost, err := th.App.GetSinglePost(pinnedPost.Id); err != nil && rpost.IsPinned { 764 t.Fatal("failed to pin post") 765 } 766 767 pass, resp = Client.UnpinPost("junk") 768 CheckBadRequestStatus(t, resp) 769 770 if pass { 771 t.Fatal("should have failed") 772 } 773 774 _, resp = Client.UnpinPost(GenerateTestId()) 775 CheckForbiddenStatus(t, resp) 776 777 Client.Logout() 778 _, resp = Client.UnpinPost(pinnedPost.Id) 779 CheckUnauthorizedStatus(t, resp) 780 781 _, resp = th.SystemAdminClient.UnpinPost(pinnedPost.Id) 782 CheckNoError(t, resp) 783 } 784 785 func TestGetPostsForChannel(t *testing.T) { 786 th := Setup().InitBasic().InitSystemAdmin() 787 defer th.TearDown() 788 Client := th.Client 789 790 post1 := th.CreatePost() 791 post2 := th.CreatePost() 792 post3 := &model.Post{ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a", RootId: post1.Id} 793 post3, _ = Client.CreatePost(post3) 794 795 time.Sleep(300 * time.Millisecond) 796 since := model.GetMillis() 797 time.Sleep(300 * time.Millisecond) 798 799 post4 := th.CreatePost() 800 801 posts, resp := Client.GetPostsForChannel(th.BasicChannel.Id, 0, 60, "") 802 CheckNoError(t, resp) 803 804 if posts.Order[0] != post4.Id { 805 t.Fatal("wrong order") 806 } 807 808 if posts.Order[1] != post3.Id { 809 t.Fatal("wrong order") 810 } 811 812 if posts.Order[2] != post2.Id { 813 t.Fatal("wrong order") 814 } 815 816 if posts.Order[3] != post1.Id { 817 t.Fatal("wrong order") 818 } 819 820 posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 0, 3, resp.Etag) 821 CheckEtag(t, posts, resp) 822 823 posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 0, 3, "") 824 CheckNoError(t, resp) 825 826 if len(posts.Order) != 3 { 827 t.Fatal("wrong number returned") 828 } 829 830 if _, ok := posts.Posts[post3.Id]; !ok { 831 t.Fatal("missing comment") 832 } 833 834 if _, ok := posts.Posts[post1.Id]; !ok { 835 t.Fatal("missing root post") 836 } 837 838 posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 1, 1, "") 839 CheckNoError(t, resp) 840 841 if posts.Order[0] != post3.Id { 842 t.Fatal("wrong order") 843 } 844 845 posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 10000, 10000, "") 846 CheckNoError(t, resp) 847 848 if len(posts.Order) != 0 { 849 t.Fatal("should be no posts") 850 } 851 852 post5 := th.CreatePost() 853 854 posts, resp = Client.GetPostsSince(th.BasicChannel.Id, since) 855 CheckNoError(t, resp) 856 857 if len(posts.Posts) != 2 { 858 t.Log(posts.Posts) 859 t.Fatal("should return 2 posts") 860 } 861 862 found := make([]bool, 2) 863 for _, p := range posts.Posts { 864 if p.CreateAt < since { 865 t.Fatal("bad create at for post returned") 866 } 867 if p.Id == post4.Id { 868 found[0] = true 869 } else if p.Id == post5.Id { 870 found[1] = true 871 } 872 } 873 874 for _, f := range found { 875 if !f { 876 t.Fatal("missing post") 877 } 878 } 879 880 _, resp = Client.GetPostsForChannel("", 0, 60, "") 881 CheckBadRequestStatus(t, resp) 882 883 _, resp = Client.GetPostsForChannel("junk", 0, 60, "") 884 CheckBadRequestStatus(t, resp) 885 886 _, resp = Client.GetPostsForChannel(model.NewId(), 0, 60, "") 887 CheckForbiddenStatus(t, resp) 888 889 Client.Logout() 890 _, resp = Client.GetPostsForChannel(model.NewId(), 0, 60, "") 891 CheckUnauthorizedStatus(t, resp) 892 893 _, resp = th.SystemAdminClient.GetPostsForChannel(th.BasicChannel.Id, 0, 60, "") 894 CheckNoError(t, resp) 895 } 896 897 func TestGetFlaggedPostsForUser(t *testing.T) { 898 th := Setup().InitBasic().InitSystemAdmin() 899 defer th.TearDown() 900 Client := th.Client 901 user := th.BasicUser 902 team1 := th.BasicTeam 903 channel1 := th.BasicChannel 904 post1 := th.CreatePost() 905 channel2 := th.CreatePublicChannel() 906 post2 := th.CreatePostWithClient(Client, channel2) 907 908 preference := model.Preference{ 909 UserId: user.Id, 910 Category: model.PREFERENCE_CATEGORY_FLAGGED_POST, 911 Name: post1.Id, 912 Value: "true", 913 } 914 Client.UpdatePreferences(user.Id, &model.Preferences{preference}) 915 preference.Name = post2.Id 916 Client.UpdatePreferences(user.Id, &model.Preferences{preference}) 917 918 opl := model.NewPostList() 919 opl.AddPost(post1) 920 opl.AddOrder(post1.Id) 921 922 rpl, resp := Client.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 10) 923 CheckNoError(t, resp) 924 925 if len(rpl.Posts) != 1 { 926 t.Fatal("should have returned 1 post") 927 } 928 929 if !reflect.DeepEqual(rpl.Posts, opl.Posts) { 930 t.Fatal("posts should have matched") 931 } 932 933 rpl, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 1) 934 CheckNoError(t, resp) 935 936 if len(rpl.Posts) != 1 { 937 t.Fatal("should have returned 1 post") 938 } 939 940 rpl, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 1, 1) 941 CheckNoError(t, resp) 942 943 if len(rpl.Posts) != 0 { 944 t.Fatal("should be empty") 945 } 946 947 rpl, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, GenerateTestId(), 0, 10) 948 CheckNoError(t, resp) 949 950 if len(rpl.Posts) != 0 { 951 t.Fatal("should be empty") 952 } 953 954 rpl, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, "junk", 0, 10) 955 CheckBadRequestStatus(t, resp) 956 957 if rpl != nil { 958 t.Fatal("should be nil") 959 } 960 961 opl.AddPost(post2) 962 opl.AddOrder(post2.Id) 963 964 rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 10) 965 CheckNoError(t, resp) 966 967 if len(rpl.Posts) != 2 { 968 t.Fatal("should have returned 2 posts") 969 } 970 971 if !reflect.DeepEqual(rpl.Posts, opl.Posts) { 972 t.Fatal("posts should have matched") 973 } 974 975 rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 1) 976 CheckNoError(t, resp) 977 978 if len(rpl.Posts) != 1 { 979 t.Fatal("should have returned 1 post") 980 } 981 982 rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 1, 1) 983 CheckNoError(t, resp) 984 985 if len(rpl.Posts) != 1 { 986 t.Fatal("should have returned 1 post") 987 } 988 989 rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 1000, 10) 990 CheckNoError(t, resp) 991 992 if len(rpl.Posts) != 0 { 993 t.Fatal("should be empty") 994 } 995 996 rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, GenerateTestId(), 0, 10) 997 CheckNoError(t, resp) 998 999 if len(rpl.Posts) != 0 { 1000 t.Fatal("should be empty") 1001 } 1002 1003 rpl, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, "junk", 0, 10) 1004 CheckBadRequestStatus(t, resp) 1005 1006 if rpl != nil { 1007 t.Fatal("should be nil") 1008 } 1009 1010 channel3 := th.CreatePrivateChannel() 1011 post4 := th.CreatePostWithClient(Client, channel3) 1012 1013 preference.Name = post4.Id 1014 Client.UpdatePreferences(user.Id, &model.Preferences{preference}) 1015 1016 opl.AddPost(post4) 1017 opl.AddOrder(post4.Id) 1018 1019 rpl, resp = Client.GetFlaggedPostsForUser(user.Id, 0, 10) 1020 CheckNoError(t, resp) 1021 1022 if len(rpl.Posts) != 3 { 1023 t.Fatal("should have returned 3 posts") 1024 } 1025 1026 if !reflect.DeepEqual(rpl.Posts, opl.Posts) { 1027 t.Fatal("posts should have matched") 1028 } 1029 1030 rpl, resp = Client.GetFlaggedPostsForUser(user.Id, 0, 2) 1031 CheckNoError(t, resp) 1032 1033 if len(rpl.Posts) != 2 { 1034 t.Fatal("should have returned 2 posts") 1035 } 1036 1037 rpl, resp = Client.GetFlaggedPostsForUser(user.Id, 2, 2) 1038 CheckNoError(t, resp) 1039 1040 if len(rpl.Posts) != 1 { 1041 t.Fatal("should have returned 1 post") 1042 } 1043 1044 rpl, resp = Client.GetFlaggedPostsForUser(user.Id, 1000, 10) 1045 CheckNoError(t, resp) 1046 1047 if len(rpl.Posts) != 0 { 1048 t.Fatal("should be empty") 1049 } 1050 1051 _, resp = Client.GetFlaggedPostsForUser("junk", 0, 10) 1052 CheckBadRequestStatus(t, resp) 1053 1054 _, resp = Client.GetFlaggedPostsForUser(GenerateTestId(), 0, 10) 1055 CheckForbiddenStatus(t, resp) 1056 1057 Client.Logout() 1058 1059 _, resp = Client.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 10) 1060 CheckUnauthorizedStatus(t, resp) 1061 1062 _, resp = Client.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 10) 1063 CheckUnauthorizedStatus(t, resp) 1064 1065 _, resp = Client.GetFlaggedPostsForUser(user.Id, 0, 10) 1066 CheckUnauthorizedStatus(t, resp) 1067 1068 _, resp = th.SystemAdminClient.GetFlaggedPostsForUserInChannel(user.Id, channel1.Id, 0, 10) 1069 CheckNoError(t, resp) 1070 1071 _, resp = th.SystemAdminClient.GetFlaggedPostsForUserInTeam(user.Id, team1.Id, 0, 10) 1072 CheckNoError(t, resp) 1073 1074 _, resp = th.SystemAdminClient.GetFlaggedPostsForUser(user.Id, 0, 10) 1075 CheckNoError(t, resp) 1076 } 1077 1078 func TestGetPostsAfterAndBefore(t *testing.T) { 1079 th := Setup().InitBasic() 1080 defer th.TearDown() 1081 Client := th.Client 1082 1083 post1 := th.CreatePost() 1084 post2 := th.CreatePost() 1085 post3 := th.CreatePost() 1086 post4 := th.CreatePost() 1087 post5 := th.CreatePost() 1088 1089 posts, resp := Client.GetPostsBefore(th.BasicChannel.Id, post3.Id, 0, 100, "") 1090 CheckNoError(t, resp) 1091 1092 found := make([]bool, 2) 1093 for _, p := range posts.Posts { 1094 if p.Id == post1.Id { 1095 found[0] = true 1096 } else if p.Id == post2.Id { 1097 found[1] = true 1098 } 1099 1100 if p.Id == post4.Id || p.Id == post5.Id { 1101 t.Fatal("returned posts after") 1102 } 1103 } 1104 1105 for _, f := range found { 1106 if !f { 1107 t.Fatal("missing post") 1108 } 1109 } 1110 1111 posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post3.Id, 1, 1, "") 1112 CheckNoError(t, resp) 1113 1114 if len(posts.Posts) != 1 { 1115 t.Fatal("too many posts returned") 1116 } 1117 1118 posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, "junk", 1, 1, "") 1119 CheckNoError(t, resp) 1120 1121 if len(posts.Posts) != 0 { 1122 t.Fatal("should have no posts") 1123 } 1124 1125 posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post3.Id, 0, 100, "") 1126 CheckNoError(t, resp) 1127 1128 found = make([]bool, 2) 1129 for _, p := range posts.Posts { 1130 if p.Id == post4.Id { 1131 found[0] = true 1132 } else if p.Id == post5.Id { 1133 found[1] = true 1134 } 1135 1136 if p.Id == post1.Id || p.Id == post2.Id { 1137 t.Fatal("returned posts before") 1138 } 1139 } 1140 1141 for _, f := range found { 1142 if !f { 1143 t.Fatal("missing post") 1144 } 1145 } 1146 1147 posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post3.Id, 1, 1, "") 1148 CheckNoError(t, resp) 1149 1150 if len(posts.Posts) != 1 { 1151 t.Fatal("too many posts returned") 1152 } 1153 1154 posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, "junk", 1, 1, "") 1155 CheckNoError(t, resp) 1156 1157 if len(posts.Posts) != 0 { 1158 t.Fatal("should have no posts") 1159 } 1160 } 1161 1162 func TestGetPost(t *testing.T) { 1163 th := Setup().InitBasic().InitSystemAdmin() 1164 defer th.TearDown() 1165 Client := th.Client 1166 1167 post, resp := Client.GetPost(th.BasicPost.Id, "") 1168 CheckNoError(t, resp) 1169 1170 if post.Id != th.BasicPost.Id { 1171 t.Fatal("post ids don't match") 1172 } 1173 1174 post, resp = Client.GetPost(th.BasicPost.Id, resp.Etag) 1175 CheckEtag(t, post, resp) 1176 1177 _, resp = Client.GetPost("", "") 1178 CheckNotFoundStatus(t, resp) 1179 1180 _, resp = Client.GetPost("junk", "") 1181 CheckBadRequestStatus(t, resp) 1182 1183 _, resp = Client.GetPost(model.NewId(), "") 1184 CheckNotFoundStatus(t, resp) 1185 1186 Client.RemoveUserFromChannel(th.BasicChannel.Id, th.BasicUser.Id) 1187 1188 // Channel is public, should be able to read post 1189 _, resp = Client.GetPost(th.BasicPost.Id, "") 1190 CheckNoError(t, resp) 1191 1192 privatePost := th.CreatePostWithClient(Client, th.BasicPrivateChannel) 1193 1194 _, resp = Client.GetPost(privatePost.Id, "") 1195 CheckNoError(t, resp) 1196 1197 Client.RemoveUserFromChannel(th.BasicPrivateChannel.Id, th.BasicUser.Id) 1198 1199 // Channel is private, should not be able to read post 1200 _, resp = Client.GetPost(privatePost.Id, "") 1201 CheckForbiddenStatus(t, resp) 1202 1203 Client.Logout() 1204 _, resp = Client.GetPost(model.NewId(), "") 1205 CheckUnauthorizedStatus(t, resp) 1206 1207 _, resp = th.SystemAdminClient.GetPost(th.BasicPost.Id, "") 1208 CheckNoError(t, resp) 1209 } 1210 1211 func TestDeletePost(t *testing.T) { 1212 th := Setup().InitBasic().InitSystemAdmin() 1213 defer th.TearDown() 1214 Client := th.Client 1215 1216 _, resp := Client.DeletePost("") 1217 CheckNotFoundStatus(t, resp) 1218 1219 _, resp = Client.DeletePost("junk") 1220 CheckBadRequestStatus(t, resp) 1221 1222 _, resp = Client.DeletePost(th.BasicPost.Id) 1223 CheckForbiddenStatus(t, resp) 1224 1225 Client.Login(th.TeamAdminUser.Email, th.TeamAdminUser.Password) 1226 _, resp = Client.DeletePost(th.BasicPost.Id) 1227 CheckNoError(t, resp) 1228 1229 post := th.CreatePost() 1230 user := th.CreateUser() 1231 1232 Client.Logout() 1233 Client.Login(user.Email, user.Password) 1234 1235 _, resp = Client.DeletePost(post.Id) 1236 CheckForbiddenStatus(t, resp) 1237 1238 Client.Logout() 1239 _, resp = Client.DeletePost(model.NewId()) 1240 CheckUnauthorizedStatus(t, resp) 1241 1242 status, resp := th.SystemAdminClient.DeletePost(post.Id) 1243 if !status { 1244 t.Fatal("post should return status OK") 1245 } 1246 CheckNoError(t, resp) 1247 } 1248 1249 func TestGetPostThread(t *testing.T) { 1250 th := Setup().InitBasic().InitSystemAdmin() 1251 defer th.TearDown() 1252 Client := th.Client 1253 1254 post := &model.Post{ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a", RootId: th.BasicPost.Id} 1255 post, _ = Client.CreatePost(post) 1256 1257 list, resp := Client.GetPostThread(th.BasicPost.Id, "") 1258 CheckNoError(t, resp) 1259 1260 var list2 *model.PostList 1261 list2, resp = Client.GetPostThread(th.BasicPost.Id, resp.Etag) 1262 CheckEtag(t, list2, resp) 1263 1264 if list.Order[0] != th.BasicPost.Id { 1265 t.Fatal("wrong order") 1266 } 1267 1268 if _, ok := list.Posts[th.BasicPost.Id]; !ok { 1269 t.Fatal("should have had post") 1270 } 1271 1272 if _, ok := list.Posts[post.Id]; !ok { 1273 t.Fatal("should have had post") 1274 } 1275 1276 _, resp = Client.GetPostThread("junk", "") 1277 CheckBadRequestStatus(t, resp) 1278 1279 _, resp = Client.GetPostThread(model.NewId(), "") 1280 CheckNotFoundStatus(t, resp) 1281 1282 Client.RemoveUserFromChannel(th.BasicChannel.Id, th.BasicUser.Id) 1283 1284 // Channel is public, should be able to read post 1285 _, resp = Client.GetPostThread(th.BasicPost.Id, "") 1286 CheckNoError(t, resp) 1287 1288 privatePost := th.CreatePostWithClient(Client, th.BasicPrivateChannel) 1289 1290 _, resp = Client.GetPostThread(privatePost.Id, "") 1291 CheckNoError(t, resp) 1292 1293 Client.RemoveUserFromChannel(th.BasicPrivateChannel.Id, th.BasicUser.Id) 1294 1295 // Channel is private, should not be able to read post 1296 _, resp = Client.GetPostThread(privatePost.Id, "") 1297 CheckForbiddenStatus(t, resp) 1298 1299 Client.Logout() 1300 _, resp = Client.GetPostThread(model.NewId(), "") 1301 CheckUnauthorizedStatus(t, resp) 1302 1303 _, resp = th.SystemAdminClient.GetPostThread(th.BasicPost.Id, "") 1304 CheckNoError(t, resp) 1305 } 1306 1307 func TestSearchPosts(t *testing.T) { 1308 th := Setup().InitBasic() 1309 defer th.TearDown() 1310 experimentalViewArchivedChannels := *th.App.Config().TeamSettings.ExperimentalViewArchivedChannels 1311 defer func() { 1312 th.App.UpdateConfig(func(cfg *model.Config) { 1313 cfg.TeamSettings.ExperimentalViewArchivedChannels = &experimentalViewArchivedChannels 1314 }) 1315 }() 1316 th.App.UpdateConfig(func(cfg *model.Config) { 1317 *cfg.TeamSettings.ExperimentalViewArchivedChannels = true 1318 }) 1319 1320 th.LoginBasic() 1321 Client := th.Client 1322 1323 message := "search for post1" 1324 _ = th.CreateMessagePost(message) 1325 1326 message = "search for post2" 1327 post2 := th.CreateMessagePost(message) 1328 1329 message = "#hashtag search for post3" 1330 post3 := th.CreateMessagePost(message) 1331 1332 message = "hashtag for post4" 1333 _ = th.CreateMessagePost(message) 1334 1335 archivedChannel := th.CreatePublicChannel() 1336 _ = th.CreateMessagePostWithClient(th.Client, archivedChannel, "#hashtag for post3") 1337 th.Client.DeleteChannel(archivedChannel.Id) 1338 1339 terms := "search" 1340 isOrSearch := false 1341 timezoneOffset := 5 1342 searchParams := model.SearchParameter{ 1343 Terms: &terms, 1344 IsOrSearch: &isOrSearch, 1345 TimeZoneOffset: &timezoneOffset, 1346 } 1347 posts, resp := Client.SearchPostsWithParams(th.BasicTeam.Id, &searchParams) 1348 CheckNoError(t, resp) 1349 if len(posts.Order) != 3 { 1350 t.Fatal("wrong search") 1351 } 1352 1353 terms = "search" 1354 page := 0 1355 perPage := 2 1356 searchParams = model.SearchParameter{ 1357 Terms: &terms, 1358 IsOrSearch: &isOrSearch, 1359 TimeZoneOffset: &timezoneOffset, 1360 Page: &page, 1361 PerPage: &perPage, 1362 } 1363 posts2, resp := Client.SearchPostsWithParams(th.BasicTeam.Id, &searchParams) 1364 CheckNoError(t, resp) 1365 if len(posts2.Order) != 3 { // We don't support paging for DB search yet, modify this when we do. 1366 t.Fatal("Wrong number of posts", len(posts2.Order)) 1367 } 1368 assert.Equal(t, posts.Order[0], posts2.Order[0]) 1369 assert.Equal(t, posts.Order[1], posts2.Order[1]) 1370 1371 page = 1 1372 searchParams = model.SearchParameter{ 1373 Terms: &terms, 1374 IsOrSearch: &isOrSearch, 1375 TimeZoneOffset: &timezoneOffset, 1376 Page: &page, 1377 PerPage: &perPage, 1378 } 1379 posts2, resp = Client.SearchPostsWithParams(th.BasicTeam.Id, &searchParams) 1380 CheckNoError(t, resp) 1381 if len(posts2.Order) != 0 { // We don't support paging for DB search yet, modify this when we do. 1382 t.Fatal("Wrong number of posts", len(posts2.Order)) 1383 } 1384 1385 posts, resp = Client.SearchPosts(th.BasicTeam.Id, "search", false) 1386 CheckNoError(t, resp) 1387 if len(posts.Order) != 3 { 1388 t.Fatal("wrong search") 1389 } 1390 1391 posts, resp = Client.SearchPosts(th.BasicTeam.Id, "post2", false) 1392 CheckNoError(t, resp) 1393 if len(posts.Order) != 1 && posts.Order[0] == post2.Id { 1394 t.Fatal("wrong search") 1395 } 1396 1397 posts, resp = Client.SearchPosts(th.BasicTeam.Id, "#hashtag", false) 1398 CheckNoError(t, resp) 1399 if len(posts.Order) != 1 && posts.Order[0] == post3.Id { 1400 t.Fatal("wrong search") 1401 } 1402 1403 terms = "#hashtag" 1404 includeDeletedChannels := true 1405 searchParams = model.SearchParameter{ 1406 Terms: &terms, 1407 IsOrSearch: &isOrSearch, 1408 TimeZoneOffset: &timezoneOffset, 1409 IncludeDeletedChannels: &includeDeletedChannels, 1410 } 1411 posts, resp = Client.SearchPostsWithParams(th.BasicTeam.Id, &searchParams) 1412 CheckNoError(t, resp) 1413 if len(posts.Order) != 2 { 1414 t.Fatal("wrong search") 1415 } 1416 1417 th.App.UpdateConfig(func(cfg *model.Config) { 1418 *cfg.TeamSettings.ExperimentalViewArchivedChannels = false 1419 }) 1420 1421 posts, resp = Client.SearchPostsWithParams(th.BasicTeam.Id, &searchParams) 1422 CheckNoError(t, resp) 1423 if len(posts.Order) != 1 { 1424 t.Fatal("wrong search") 1425 } 1426 1427 if posts, _ = Client.SearchPosts(th.BasicTeam.Id, "*", false); len(posts.Order) != 0 { 1428 t.Fatal("searching for just * shouldn't return any results") 1429 } 1430 1431 posts, resp = Client.SearchPosts(th.BasicTeam.Id, "post1 post2", true) 1432 CheckNoError(t, resp) 1433 1434 if len(posts.Order) != 2 { 1435 t.Fatal("wrong search results") 1436 } 1437 1438 _, resp = Client.SearchPosts("junk", "#sgtitlereview", false) 1439 CheckBadRequestStatus(t, resp) 1440 1441 _, resp = Client.SearchPosts(model.NewId(), "#sgtitlereview", false) 1442 CheckForbiddenStatus(t, resp) 1443 1444 _, resp = Client.SearchPosts(th.BasicTeam.Id, "", false) 1445 CheckBadRequestStatus(t, resp) 1446 1447 Client.Logout() 1448 _, resp = Client.SearchPosts(th.BasicTeam.Id, "#sgtitlereview", false) 1449 CheckUnauthorizedStatus(t, resp) 1450 } 1451 1452 func TestSearchHashtagPosts(t *testing.T) { 1453 th := Setup().InitBasic() 1454 defer th.TearDown() 1455 th.LoginBasic() 1456 Client := th.Client 1457 1458 message := "#sgtitlereview with space" 1459 assert.NotNil(t, th.CreateMessagePost(message)) 1460 1461 message = "#sgtitlereview\n with return" 1462 assert.NotNil(t, th.CreateMessagePost(message)) 1463 1464 message = "no hashtag" 1465 assert.NotNil(t, th.CreateMessagePost(message)) 1466 1467 posts, resp := Client.SearchPosts(th.BasicTeam.Id, "#sgtitlereview", false) 1468 CheckNoError(t, resp) 1469 if len(posts.Order) != 2 { 1470 t.Fatal("wrong search results") 1471 } 1472 1473 Client.Logout() 1474 _, resp = Client.SearchPosts(th.BasicTeam.Id, "#sgtitlereview", false) 1475 CheckUnauthorizedStatus(t, resp) 1476 } 1477 1478 func TestSearchPostsInChannel(t *testing.T) { 1479 th := Setup().InitBasic() 1480 defer th.TearDown() 1481 th.LoginBasic() 1482 Client := th.Client 1483 1484 channel := th.CreatePublicChannel() 1485 1486 message := "sgtitlereview with space" 1487 _ = th.CreateMessagePost(message) 1488 1489 message = "sgtitlereview\n with return" 1490 _ = th.CreateMessagePostWithClient(Client, th.BasicChannel2, message) 1491 1492 message = "other message with no return" 1493 _ = th.CreateMessagePostWithClient(Client, th.BasicChannel2, message) 1494 1495 message = "other message with no return" 1496 _ = th.CreateMessagePostWithClient(Client, channel, message) 1497 1498 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "channel:", false); len(posts.Order) != 0 { 1499 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1500 } 1501 1502 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "in:", false); len(posts.Order) != 0 { 1503 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1504 } 1505 1506 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "channel:"+th.BasicChannel.Name, false); len(posts.Order) != 2 { 1507 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1508 } 1509 1510 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "in:"+th.BasicChannel2.Name, false); len(posts.Order) != 2 { 1511 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1512 } 1513 1514 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "channel:"+th.BasicChannel2.Name, false); len(posts.Order) != 2 { 1515 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1516 } 1517 1518 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "ChAnNeL:"+th.BasicChannel2.Name, false); len(posts.Order) != 2 { 1519 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1520 } 1521 1522 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "sgtitlereview", false); len(posts.Order) != 2 { 1523 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1524 } 1525 1526 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "sgtitlereview channel:"+th.BasicChannel.Name, false); len(posts.Order) != 1 { 1527 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1528 } 1529 1530 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "sgtitlereview in: "+th.BasicChannel2.Name, false); len(posts.Order) != 1 { 1531 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1532 } 1533 1534 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "sgtitlereview channel: "+th.BasicChannel2.Name, false); len(posts.Order) != 1 { 1535 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1536 } 1537 1538 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "channel: "+th.BasicChannel2.Name+" channel: "+channel.Name, false); len(posts.Order) != 3 { 1539 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1540 } 1541 1542 } 1543 1544 func TestSearchPostsFromUser(t *testing.T) { 1545 th := Setup().InitBasic() 1546 defer th.TearDown() 1547 Client := th.Client 1548 1549 th.LoginTeamAdmin() 1550 user := th.CreateUser() 1551 th.LinkUserToTeam(user, th.BasicTeam) 1552 th.App.AddUserToChannel(user, th.BasicChannel) 1553 th.App.AddUserToChannel(user, th.BasicChannel2) 1554 1555 message := "sgtitlereview with space" 1556 _ = th.CreateMessagePost(message) 1557 1558 Client.Logout() 1559 th.LoginBasic2() 1560 1561 message = "sgtitlereview\n with return" 1562 _ = th.CreateMessagePostWithClient(Client, th.BasicChannel2, message) 1563 1564 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.TeamAdminUser.Username, false); len(posts.Order) != 2 { 1565 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1566 } 1567 1568 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username, false); len(posts.Order) != 1 { 1569 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1570 } 1571 1572 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username+" sgtitlereview", false); len(posts.Order) != 1 { 1573 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1574 } 1575 1576 message = "hullo" 1577 _ = th.CreateMessagePost(message) 1578 1579 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username+" in:"+th.BasicChannel.Name, false); len(posts.Order) != 1 { 1580 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1581 } 1582 1583 Client.Login(user.Email, user.Password) 1584 1585 // wait for the join/leave messages to be created for user3 since they're done asynchronously 1586 time.Sleep(100 * time.Millisecond) 1587 1588 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username, false); len(posts.Order) != 2 { 1589 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1590 } 1591 1592 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username+" from: "+user.Username, false); len(posts.Order) != 2 { 1593 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1594 } 1595 1596 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username+" from: "+user.Username+" in:"+th.BasicChannel2.Name, false); len(posts.Order) != 1 { 1597 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1598 } 1599 1600 message = "coconut" 1601 _ = th.CreateMessagePostWithClient(Client, th.BasicChannel2, message) 1602 1603 if posts, _ := Client.SearchPosts(th.BasicTeam.Id, "from: "+th.BasicUser2.Username+" from: "+user.Username+" in:"+th.BasicChannel2.Name+" coconut", false); len(posts.Order) != 1 { 1604 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1605 } 1606 } 1607 1608 func TestSearchPostsWithDateFlags(t *testing.T) { 1609 th := Setup().InitBasic() 1610 defer th.TearDown() 1611 th.LoginBasic() 1612 Client := th.Client 1613 1614 message := "sgtitlereview\n with return" 1615 createDate := time.Date(2018, 8, 1, 5, 0, 0, 0, time.UTC) 1616 _ = th.CreateMessagePostNoClient(th.BasicChannel, message, utils.MillisFromTime(createDate)) 1617 1618 message = "other message with no return" 1619 createDate = time.Date(2018, 8, 2, 5, 0, 0, 0, time.UTC) 1620 _ = th.CreateMessagePostNoClient(th.BasicChannel, message, utils.MillisFromTime(createDate)) 1621 1622 message = "other message with no return" 1623 createDate = time.Date(2018, 8, 3, 5, 0, 0, 0, time.UTC) 1624 _ = th.CreateMessagePostNoClient(th.BasicChannel, message, utils.MillisFromTime(createDate)) 1625 1626 posts, _ := Client.SearchPosts(th.BasicTeam.Id, "return", false) 1627 if len(posts.Order) != 3 { 1628 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1629 } 1630 1631 posts, _ = Client.SearchPosts(th.BasicTeam.Id, "on:", false) 1632 if len(posts.Order) != 0 { 1633 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1634 } 1635 1636 posts, _ = Client.SearchPosts(th.BasicTeam.Id, "after:", false) 1637 if len(posts.Order) != 0 { 1638 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1639 } 1640 1641 posts, _ = Client.SearchPosts(th.BasicTeam.Id, "before:", false) 1642 if len(posts.Order) != 0 { 1643 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1644 } 1645 1646 posts, _ = Client.SearchPosts(th.BasicTeam.Id, "on:2018-08-01", false) 1647 if len(posts.Order) != 1 { 1648 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1649 } 1650 1651 posts, _ = Client.SearchPosts(th.BasicTeam.Id, "after:2018-08-01", false) 1652 resultCount := 0 1653 for _, post := range posts.Posts { 1654 if post.UserId == th.BasicUser.Id { 1655 resultCount = resultCount + 1 1656 } 1657 } 1658 if resultCount != 2 { 1659 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1660 } 1661 1662 posts, _ = Client.SearchPosts(th.BasicTeam.Id, "before:2018-08-02", false) 1663 if len(posts.Order) != 1 { 1664 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1665 } 1666 1667 posts, _ = Client.SearchPosts(th.BasicTeam.Id, "before:2018-08-03 after:2018-08-02", false) 1668 if len(posts.Order) != 0 { 1669 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1670 } 1671 1672 posts, _ = Client.SearchPosts(th.BasicTeam.Id, "before:2018-08-03 after:2018-08-01", false) 1673 if len(posts.Order) != 1 { 1674 t.Fatalf("wrong number of posts returned %v", len(posts.Order)) 1675 } 1676 } 1677 1678 func TestGetFileInfosForPost(t *testing.T) { 1679 th := Setup().InitBasic().InitSystemAdmin() 1680 defer th.TearDown() 1681 Client := th.Client 1682 1683 fileIds := make([]string, 3) 1684 if data, err := readTestFile("test.png"); err != nil { 1685 t.Fatal(err) 1686 } else { 1687 for i := 0; i < 3; i++ { 1688 fileResp, _ := Client.UploadFile(data, th.BasicChannel.Id, "test.png") 1689 fileIds[i] = fileResp.FileInfos[0].Id 1690 } 1691 } 1692 1693 post := &model.Post{ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a", FileIds: fileIds} 1694 post, _ = Client.CreatePost(post) 1695 1696 infos, resp := Client.GetFileInfosForPost(post.Id, "") 1697 CheckNoError(t, resp) 1698 1699 if len(infos) != 3 { 1700 t.Fatal("missing file infos") 1701 } 1702 1703 found := false 1704 for _, info := range infos { 1705 if info.Id == fileIds[0] { 1706 found = true 1707 } 1708 } 1709 1710 if !found { 1711 t.Fatal("missing file info") 1712 } 1713 1714 infos, resp = Client.GetFileInfosForPost(post.Id, resp.Etag) 1715 CheckEtag(t, infos, resp) 1716 1717 infos, resp = Client.GetFileInfosForPost(th.BasicPost.Id, "") 1718 CheckNoError(t, resp) 1719 1720 if len(infos) != 0 { 1721 t.Fatal("should have no file infos") 1722 } 1723 1724 _, resp = Client.GetFileInfosForPost("junk", "") 1725 CheckBadRequestStatus(t, resp) 1726 1727 _, resp = Client.GetFileInfosForPost(model.NewId(), "") 1728 CheckForbiddenStatus(t, resp) 1729 1730 Client.Logout() 1731 _, resp = Client.GetFileInfosForPost(model.NewId(), "") 1732 CheckUnauthorizedStatus(t, resp) 1733 1734 _, resp = th.SystemAdminClient.GetFileInfosForPost(th.BasicPost.Id, "") 1735 CheckNoError(t, resp) 1736 }