github.com/kongr45gpen/mattermost-server@v5.11.1+incompatible/api4/reaction_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 "strings" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 12 "github.com/mattermost/mattermost-server/model" 13 ) 14 15 func TestSaveReaction(t *testing.T) { 16 th := Setup().InitBasic() 17 defer th.TearDown() 18 Client := th.Client 19 userId := th.BasicUser.Id 20 postId := th.BasicPost.Id 21 22 // Check the appropriate permissions are enforced. 23 defaultRolePermissions := th.SaveDefaultRolePermissions() 24 defer func() { 25 th.RestoreDefaultRolePermissions(defaultRolePermissions) 26 }() 27 28 reaction := &model.Reaction{ 29 UserId: userId, 30 PostId: postId, 31 EmojiName: "smile", 32 } 33 34 t.Run("successful-reaction", func(t *testing.T) { 35 rr, resp := Client.SaveReaction(reaction) 36 CheckNoError(t, resp) 37 38 if rr.UserId != reaction.UserId { 39 t.Fatal("UserId did not match") 40 } 41 42 if rr.PostId != reaction.PostId { 43 t.Fatal("PostId did not match") 44 } 45 46 if rr.EmojiName != reaction.EmojiName { 47 t.Fatal("EmojiName did not match") 48 } 49 50 if rr.CreateAt == 0 { 51 t.Fatal("CreateAt should exist") 52 } 53 54 if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 1 { 55 t.Fatal("didn't save reaction correctly") 56 } 57 }) 58 59 t.Run("duplicated-reaction", func(t *testing.T) { 60 _, resp := Client.SaveReaction(reaction) 61 CheckNoError(t, resp) 62 63 if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 1 { 64 t.Fatal("should have not save duplicated reaction") 65 } 66 }) 67 68 t.Run("save-second-reaction", func(t *testing.T) { 69 reaction.EmojiName = "sad" 70 71 rr, resp := Client.SaveReaction(reaction) 72 CheckNoError(t, resp) 73 74 if rr.EmojiName != reaction.EmojiName { 75 t.Fatal("EmojiName did not match") 76 } 77 78 if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 2 { 79 t.Fatal("should have save multiple reactions") 80 } 81 }) 82 83 t.Run("saving-special-case", func(t *testing.T) { 84 reaction.EmojiName = "+1" 85 86 rr, resp := Client.SaveReaction(reaction) 87 CheckNoError(t, resp) 88 89 if rr.EmojiName != reaction.EmojiName { 90 t.Fatal("EmojiName did not match") 91 } 92 93 if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 3 { 94 t.Fatal("should have save multiple reactions") 95 } 96 }) 97 98 t.Run("react-to-not-existing-post-id", func(t *testing.T) { 99 reaction.PostId = GenerateTestId() 100 101 _, resp := Client.SaveReaction(reaction) 102 CheckForbiddenStatus(t, resp) 103 }) 104 105 t.Run("react-to-not-valid-post-id", func(t *testing.T) { 106 reaction.PostId = "junk" 107 108 _, resp := Client.SaveReaction(reaction) 109 CheckBadRequestStatus(t, resp) 110 }) 111 112 t.Run("react-as-not-existing-user-id", func(t *testing.T) { 113 reaction.PostId = postId 114 reaction.UserId = GenerateTestId() 115 116 _, resp := Client.SaveReaction(reaction) 117 CheckForbiddenStatus(t, resp) 118 }) 119 120 t.Run("react-as-not-valid-user-id", func(t *testing.T) { 121 reaction.UserId = "junk" 122 123 _, resp := Client.SaveReaction(reaction) 124 CheckBadRequestStatus(t, resp) 125 }) 126 127 t.Run("react-as-empty-emoji-name", func(t *testing.T) { 128 reaction.UserId = userId 129 reaction.EmojiName = "" 130 131 _, resp := Client.SaveReaction(reaction) 132 CheckBadRequestStatus(t, resp) 133 }) 134 135 t.Run("react-as-not-valid-emoji-name", func(t *testing.T) { 136 reaction.EmojiName = strings.Repeat("a", 65) 137 138 _, resp := Client.SaveReaction(reaction) 139 CheckBadRequestStatus(t, resp) 140 }) 141 142 t.Run("react-as-other-user", func(t *testing.T) { 143 reaction.EmojiName = "smile" 144 otherUser := th.CreateUser() 145 Client.Logout() 146 Client.Login(otherUser.Email, otherUser.Password) 147 148 _, resp := Client.SaveReaction(reaction) 149 CheckForbiddenStatus(t, resp) 150 }) 151 152 t.Run("react-being-not-logged-in", func(t *testing.T) { 153 Client.Logout() 154 _, resp := Client.SaveReaction(reaction) 155 CheckUnauthorizedStatus(t, resp) 156 }) 157 158 t.Run("react-as-other-user-being-system-admin", func(t *testing.T) { 159 _, resp := th.SystemAdminClient.SaveReaction(reaction) 160 CheckForbiddenStatus(t, resp) 161 }) 162 163 t.Run("unable-to-create-reaction-without-permissions", func(t *testing.T) { 164 th.LoginBasic() 165 166 th.RemovePermissionFromRole(model.PERMISSION_ADD_REACTION.Id, model.CHANNEL_USER_ROLE_ID) 167 _, resp := Client.SaveReaction(reaction) 168 CheckForbiddenStatus(t, resp) 169 170 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 3 { 171 t.Fatal("should have not created a reactions") 172 } 173 th.AddPermissionToRole(model.PERMISSION_ADD_REACTION.Id, model.CHANNEL_USER_ROLE_ID) 174 }) 175 176 t.Run("unable-to-react-in-read-only-town-square", func(t *testing.T) { 177 th.LoginBasic() 178 179 channel, err := th.App.GetChannelByName("town-square", th.BasicTeam.Id, true) 180 assert.Nil(t, err) 181 post := th.CreatePostWithClient(th.Client, channel) 182 183 th.App.SetLicense(model.NewTestLicense()) 184 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = true }) 185 186 reaction := &model.Reaction{ 187 UserId: userId, 188 PostId: post.Id, 189 EmojiName: "smile", 190 } 191 192 _, resp := Client.SaveReaction(reaction) 193 CheckForbiddenStatus(t, resp) 194 195 if reactions, err := th.App.GetReactionsForPost(post.Id); err != nil || len(reactions) != 0 { 196 t.Fatal("should have not created a reaction") 197 } 198 199 th.App.RemoveLicense() 200 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = false }) 201 }) 202 203 t.Run("unable-to-react-in-an-archived-channel", func(t *testing.T) { 204 th.LoginBasic() 205 206 channel := th.CreatePublicChannel() 207 post := th.CreatePostWithClient(th.Client, channel) 208 209 reaction := &model.Reaction{ 210 UserId: userId, 211 PostId: post.Id, 212 EmojiName: "smile", 213 } 214 215 err := th.App.DeleteChannel(channel, userId) 216 assert.Nil(t, err) 217 218 _, resp := Client.SaveReaction(reaction) 219 CheckForbiddenStatus(t, resp) 220 221 if reactions, err := th.App.GetReactionsForPost(post.Id); err != nil || len(reactions) != 0 { 222 t.Fatal("should have not created a reaction") 223 } 224 }) 225 } 226 227 func TestGetReactions(t *testing.T) { 228 th := Setup().InitBasic() 229 defer th.TearDown() 230 Client := th.Client 231 userId := th.BasicUser.Id 232 user2Id := th.BasicUser2.Id 233 postId := th.BasicPost.Id 234 235 userReactions := []*model.Reaction{ 236 { 237 UserId: userId, 238 PostId: postId, 239 EmojiName: "smile", 240 }, 241 { 242 UserId: userId, 243 PostId: postId, 244 EmojiName: "happy", 245 }, 246 { 247 UserId: userId, 248 PostId: postId, 249 EmojiName: "sad", 250 }, 251 { 252 UserId: user2Id, 253 PostId: postId, 254 EmojiName: "smile", 255 }, 256 { 257 UserId: user2Id, 258 PostId: postId, 259 EmojiName: "sad", 260 }, 261 } 262 263 var reactions []*model.Reaction 264 265 for _, userReaction := range userReactions { 266 if result := <-th.App.Srv.Store.Reaction().Save(userReaction); result.Err != nil { 267 t.Fatal(result.Err) 268 } else { 269 reactions = append(reactions, result.Data.(*model.Reaction)) 270 } 271 } 272 273 t.Run("get-reactions", func(t *testing.T) { 274 rr, resp := Client.GetReactions(postId) 275 CheckNoError(t, resp) 276 277 assert.Len(t, rr, 5) 278 for _, r := range reactions { 279 assert.Contains(t, reactions, r) 280 } 281 }) 282 283 t.Run("get-reactions-of-invalid-post-id", func(t *testing.T) { 284 rr, resp := Client.GetReactions("junk") 285 CheckBadRequestStatus(t, resp) 286 287 assert.Empty(t, rr) 288 }) 289 290 t.Run("get-reactions-of-not-existing-post-id", func(t *testing.T) { 291 _, resp := Client.GetReactions(GenerateTestId()) 292 CheckForbiddenStatus(t, resp) 293 }) 294 295 t.Run("get-reactions-as-anonymous-user", func(t *testing.T) { 296 Client.Logout() 297 298 _, resp := Client.GetReactions(postId) 299 CheckUnauthorizedStatus(t, resp) 300 }) 301 302 t.Run("get-reactions-as-system-admin", func(t *testing.T) { 303 _, resp := th.SystemAdminClient.GetReactions(postId) 304 CheckNoError(t, resp) 305 }) 306 } 307 308 func TestDeleteReaction(t *testing.T) { 309 th := Setup().InitBasic() 310 defer th.TearDown() 311 Client := th.Client 312 userId := th.BasicUser.Id 313 user2Id := th.BasicUser2.Id 314 postId := th.BasicPost.Id 315 316 r1 := &model.Reaction{ 317 UserId: userId, 318 PostId: postId, 319 EmojiName: "smile", 320 } 321 322 r2 := &model.Reaction{ 323 UserId: userId, 324 PostId: postId, 325 EmojiName: "smile-", 326 } 327 328 r3 := &model.Reaction{ 329 UserId: userId, 330 PostId: postId, 331 EmojiName: "+1", 332 } 333 334 r4 := &model.Reaction{ 335 UserId: user2Id, 336 PostId: postId, 337 EmojiName: "smile_", 338 } 339 340 // Check the appropriate permissions are enforced. 341 defaultRolePermissions := th.SaveDefaultRolePermissions() 342 defer func() { 343 th.RestoreDefaultRolePermissions(defaultRolePermissions) 344 }() 345 346 t.Run("delete-reaction", func(t *testing.T) { 347 th.App.SaveReactionForPost(r1) 348 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 { 349 t.Fatal("didn't save reaction correctly") 350 } 351 352 ok, resp := Client.DeleteReaction(r1) 353 CheckNoError(t, resp) 354 355 if !ok { 356 t.Fatal("should have returned true") 357 } 358 359 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 0 { 360 t.Fatal("should have deleted reaction") 361 } 362 }) 363 364 t.Run("delete-reaction-when-post-has-multiple-reactions", func(t *testing.T) { 365 th.App.SaveReactionForPost(r1) 366 th.App.SaveReactionForPost(r2) 367 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { 368 t.Fatal("didn't save reactions correctly") 369 } 370 371 _, resp := Client.DeleteReaction(r2) 372 CheckNoError(t, resp) 373 374 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 || *reactions[0] != *r1 { 375 t.Fatal("should have deleted 1 reaction only") 376 } 377 }) 378 379 t.Run("delete-reaction-when-plus-one-reaction-name", func(t *testing.T) { 380 th.App.SaveReactionForPost(r3) 381 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { 382 t.Fatal("didn't save reactions correctly") 383 } 384 385 _, resp := Client.DeleteReaction(r3) 386 CheckNoError(t, resp) 387 388 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 || *reactions[0] != *r1 { 389 t.Fatal("should have deleted 1 reaction only") 390 } 391 }) 392 393 t.Run("delete-reaction-made-by-another-user", func(t *testing.T) { 394 th.LoginBasic2() 395 th.App.SaveReactionForPost(r4) 396 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { 397 t.Fatal("didn't save reaction correctly") 398 } 399 400 th.LoginBasic() 401 402 ok, resp := Client.DeleteReaction(r4) 403 CheckForbiddenStatus(t, resp) 404 405 if ok { 406 t.Fatal("should have returned false") 407 } 408 409 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { 410 t.Fatal("should have not deleted a reaction") 411 } 412 }) 413 414 t.Run("delete-reaction-from-not-existing-post-id", func(t *testing.T) { 415 r1.PostId = GenerateTestId() 416 _, resp := Client.DeleteReaction(r1) 417 CheckForbiddenStatus(t, resp) 418 }) 419 420 t.Run("delete-reaction-from-not-valid-post-id", func(t *testing.T) { 421 r1.PostId = "junk" 422 423 _, resp := Client.DeleteReaction(r1) 424 CheckBadRequestStatus(t, resp) 425 }) 426 427 t.Run("delete-reaction-from-not-existing-user-id", func(t *testing.T) { 428 r1.PostId = postId 429 r1.UserId = GenerateTestId() 430 431 _, resp := Client.DeleteReaction(r1) 432 CheckForbiddenStatus(t, resp) 433 }) 434 435 t.Run("delete-reaction-from-not-valid-user-id", func(t *testing.T) { 436 r1.UserId = "junk" 437 438 _, resp := Client.DeleteReaction(r1) 439 CheckBadRequestStatus(t, resp) 440 }) 441 442 t.Run("delete-reaction-with-empty-name", func(t *testing.T) { 443 r1.UserId = userId 444 r1.EmojiName = "" 445 446 _, resp := Client.DeleteReaction(r1) 447 CheckNotFoundStatus(t, resp) 448 }) 449 450 t.Run("delete-reaction-with-not-existing-name", func(t *testing.T) { 451 r1.EmojiName = strings.Repeat("a", 65) 452 453 _, resp := Client.DeleteReaction(r1) 454 CheckBadRequestStatus(t, resp) 455 }) 456 457 t.Run("delete-reaction-as-anonymous-user", func(t *testing.T) { 458 Client.Logout() 459 r1.EmojiName = "smile" 460 461 _, resp := Client.DeleteReaction(r1) 462 CheckUnauthorizedStatus(t, resp) 463 }) 464 465 t.Run("delete-reaction-as-system-admin", func(t *testing.T) { 466 _, resp := th.SystemAdminClient.DeleteReaction(r1) 467 CheckNoError(t, resp) 468 469 _, resp = th.SystemAdminClient.DeleteReaction(r4) 470 CheckNoError(t, resp) 471 472 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 0 { 473 t.Fatal("should have deleted both reactions") 474 } 475 }) 476 477 t.Run("unable-to-delete-reaction-without-permissions", func(t *testing.T) { 478 th.LoginBasic() 479 480 th.RemovePermissionFromRole(model.PERMISSION_REMOVE_REACTION.Id, model.CHANNEL_USER_ROLE_ID) 481 th.App.SaveReactionForPost(r1) 482 483 _, resp := Client.DeleteReaction(r1) 484 CheckForbiddenStatus(t, resp) 485 486 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 { 487 t.Fatal("should have not deleted a reactions") 488 } 489 th.AddPermissionToRole(model.PERMISSION_REMOVE_REACTION.Id, model.CHANNEL_USER_ROLE_ID) 490 }) 491 492 t.Run("unable-to-delete-others-reactions-without-permissions", func(t *testing.T) { 493 th.RemovePermissionFromRole(model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id, model.SYSTEM_ADMIN_ROLE_ID) 494 th.App.SaveReactionForPost(r1) 495 496 _, resp := th.SystemAdminClient.DeleteReaction(r1) 497 CheckForbiddenStatus(t, resp) 498 499 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 { 500 t.Fatal("should have not deleted a reactions") 501 } 502 th.AddPermissionToRole(model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id, model.SYSTEM_ADMIN_ROLE_ID) 503 }) 504 505 t.Run("unable-to-delete-reactions-in-read-only-town-square", func(t *testing.T) { 506 th.LoginBasic() 507 508 channel, err := th.App.GetChannelByName("town-square", th.BasicTeam.Id, true) 509 assert.Nil(t, err) 510 post := th.CreatePostWithClient(th.Client, channel) 511 512 th.App.SetLicense(model.NewTestLicense()) 513 514 reaction := &model.Reaction{ 515 UserId: userId, 516 PostId: post.Id, 517 EmojiName: "smile", 518 } 519 520 r1, resp := Client.SaveReaction(reaction) 521 CheckNoError(t, resp) 522 523 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 { 524 t.Fatal("should have created a reaction") 525 } 526 527 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = true }) 528 529 _, resp = th.SystemAdminClient.DeleteReaction(r1) 530 CheckForbiddenStatus(t, resp) 531 532 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 { 533 t.Fatal("should have not deleted a reaction") 534 } 535 536 th.App.RemoveLicense() 537 th.App.UpdateConfig(func(cfg *model.Config) { *cfg.TeamSettings.ExperimentalTownSquareIsReadOnly = false }) 538 }) 539 540 t.Run("unable-to-delete-reactions-in-an-archived-channel", func(t *testing.T) { 541 th.LoginBasic() 542 543 channel := th.CreatePublicChannel() 544 post := th.CreatePostWithClient(th.Client, channel) 545 546 reaction := &model.Reaction{ 547 UserId: userId, 548 PostId: post.Id, 549 EmojiName: "smile", 550 } 551 552 r1, resp := Client.SaveReaction(reaction) 553 CheckNoError(t, resp) 554 555 if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 { 556 t.Fatal("should have created a reaction") 557 } 558 559 err := th.App.DeleteChannel(channel, userId) 560 assert.Nil(t, err) 561 562 _, resp = Client.SaveReaction(r1) 563 CheckForbiddenStatus(t, resp) 564 565 if reactions, err := th.App.GetReactionsForPost(post.Id); err != nil || len(reactions) != 1 { 566 t.Fatal("should have not deleted a reaction") 567 } 568 }) 569 } 570 571 func TestGetBulkReactions(t *testing.T) { 572 th := Setup().InitBasic() 573 defer th.TearDown() 574 Client := th.Client 575 userId := th.BasicUser.Id 576 user2Id := th.BasicUser2.Id 577 post1 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} 578 post2 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} 579 post3 := &model.Post{UserId: userId, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} 580 581 post4 := &model.Post{UserId: user2Id, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} 582 post5 := &model.Post{UserId: user2Id, ChannelId: th.BasicChannel.Id, Message: "zz" + model.NewId() + "a"} 583 584 post1, _ = Client.CreatePost(post1) 585 post2, _ = Client.CreatePost(post2) 586 post3, _ = Client.CreatePost(post3) 587 post4, _ = Client.CreatePost(post4) 588 post5, _ = Client.CreatePost(post5) 589 590 expectedPostIdsReactionsMap := make(map[string][]*model.Reaction) 591 expectedPostIdsReactionsMap[post1.Id] = []*model.Reaction{} 592 expectedPostIdsReactionsMap[post2.Id] = []*model.Reaction{} 593 expectedPostIdsReactionsMap[post3.Id] = []*model.Reaction{} 594 expectedPostIdsReactionsMap[post5.Id] = []*model.Reaction{} 595 596 userReactions := []*model.Reaction{ 597 { 598 UserId: userId, 599 PostId: post1.Id, 600 EmojiName: "happy", 601 }, 602 { 603 UserId: userId, 604 PostId: post1.Id, 605 EmojiName: "sad", 606 }, 607 { 608 UserId: userId, 609 PostId: post2.Id, 610 EmojiName: "smile", 611 }, 612 { 613 UserId: user2Id, 614 PostId: post4.Id, 615 EmojiName: "smile", 616 }, 617 } 618 619 for _, userReaction := range userReactions { 620 reactions := expectedPostIdsReactionsMap[userReaction.PostId] 621 if result := <-th.App.Srv.Store.Reaction().Save(userReaction); result.Err != nil { 622 t.Fatal(result.Err) 623 } else { 624 reactions = append(reactions, result.Data.(*model.Reaction)) 625 626 } 627 expectedPostIdsReactionsMap[userReaction.PostId] = reactions 628 } 629 630 postIds := []string{post1.Id, post2.Id, post3.Id, post4.Id, post5.Id} 631 632 t.Run("get-reactions", func(t *testing.T) { 633 postIdsReactionsMap, resp := Client.GetBulkReactions(postIds) 634 CheckNoError(t, resp) 635 636 assert.ElementsMatch(t, expectedPostIdsReactionsMap[post1.Id], postIdsReactionsMap[post1.Id]) 637 assert.ElementsMatch(t, expectedPostIdsReactionsMap[post2.Id], postIdsReactionsMap[post2.Id]) 638 assert.ElementsMatch(t, expectedPostIdsReactionsMap[post3.Id], postIdsReactionsMap[post3.Id]) 639 assert.ElementsMatch(t, expectedPostIdsReactionsMap[post4.Id], postIdsReactionsMap[post4.Id]) 640 assert.ElementsMatch(t, expectedPostIdsReactionsMap[post5.Id], postIdsReactionsMap[post5.Id]) 641 assert.Equal(t, expectedPostIdsReactionsMap, postIdsReactionsMap) 642 643 }) 644 645 t.Run("get-reactions-as-anonymous-user", func(t *testing.T) { 646 Client.Logout() 647 648 _, resp := Client.GetBulkReactions(postIds) 649 CheckUnauthorizedStatus(t, resp) 650 }) 651 }