1// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2// See LICENSE.txt for license information. 3 4package app 5 6import ( 7 "context" 8 "fmt" 9 "net/http" 10 "os" 11 "sort" 12 "strings" 13 "sync" 14 "testing" 15 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/mock" 18 "github.com/stretchr/testify/require" 19 20 "github.com/mattermost/mattermost-server/v6/model" 21 "github.com/mattermost/mattermost-server/v6/services/users" 22 "github.com/mattermost/mattermost-server/v6/store/storetest/mocks" 23) 24 25func TestPermanentDeleteChannel(t *testing.T) { 26 th := Setup(t).InitBasic() 27 defer th.TearDown() 28 29 th.App.UpdateConfig(func(cfg *model.Config) { 30 *cfg.ServiceSettings.EnableIncomingWebhooks = true 31 *cfg.ServiceSettings.EnableOutgoingWebhooks = true 32 }) 33 34 channel, err := th.App.CreateChannel(th.Context, &model.Channel{DisplayName: "deletion-test", Name: "deletion-test", Type: model.ChannelTypeOpen, TeamId: th.BasicTeam.Id}, false) 35 require.NotNil(t, channel, "Channel shouldn't be nil") 36 require.Nil(t, err) 37 defer func() { 38 th.App.PermanentDeleteChannel(channel) 39 }() 40 41 incoming, err := th.App.CreateIncomingWebhookForChannel(th.BasicUser.Id, channel, &model.IncomingWebhook{ChannelId: channel.Id}) 42 require.NotNil(t, incoming, "incoming webhook should not be nil") 43 require.Nil(t, err, "Unable to create Incoming Webhook for Channel") 44 defer th.App.DeleteIncomingWebhook(incoming.Id) 45 46 incoming, err = th.App.GetIncomingWebhook(incoming.Id) 47 require.NotNil(t, incoming, "incoming webhook should not be nil") 48 require.Nil(t, err, "Unable to get new incoming webhook") 49 50 outgoing, err := th.App.CreateOutgoingWebhook(&model.OutgoingWebhook{ 51 ChannelId: channel.Id, 52 TeamId: channel.TeamId, 53 CreatorId: th.BasicUser.Id, 54 CallbackURLs: []string{"http://foo"}, 55 }) 56 require.Nil(t, err) 57 defer th.App.DeleteOutgoingWebhook(outgoing.Id) 58 59 outgoing, err = th.App.GetOutgoingWebhook(outgoing.Id) 60 require.NotNil(t, outgoing, "Outgoing webhook should not be nil") 61 require.Nil(t, err, "Unable to get new outgoing webhook") 62 63 err = th.App.PermanentDeleteChannel(channel) 64 require.Nil(t, err) 65 66 incoming, err = th.App.GetIncomingWebhook(incoming.Id) 67 require.Nil(t, incoming, "Incoming webhook should be nil") 68 require.NotNil(t, err, "Incoming webhook wasn't deleted") 69 70 outgoing, err = th.App.GetOutgoingWebhook(outgoing.Id) 71 require.Nil(t, outgoing, "Outgoing webhook should be nil") 72 require.NotNil(t, err, "Outgoing webhook wasn't deleted") 73} 74 75func TestRemoveAllDeactivatedMembersFromChannel(t *testing.T) { 76 th := Setup(t).InitBasic() 77 defer th.TearDown() 78 var err *model.AppError 79 80 team := th.CreateTeam() 81 channel := th.CreateChannel(team) 82 defer func() { 83 th.App.PermanentDeleteChannel(channel) 84 th.App.PermanentDeleteTeam(team) 85 }() 86 87 _, _, err = th.App.AddUserToTeam(th.Context, team.Id, th.BasicUser.Id, "") 88 require.Nil(t, err) 89 90 deacivatedUser := th.CreateUser() 91 _, _, err = th.App.AddUserToTeam(th.Context, team.Id, deacivatedUser.Id, "") 92 require.Nil(t, err) 93 _, err = th.App.AddUserToChannel(deacivatedUser, channel, false) 94 require.Nil(t, err) 95 channelMembers, err := th.App.GetChannelMembersPage(channel.Id, 0, 10000000) 96 require.Nil(t, err) 97 require.Len(t, channelMembers, 2) 98 _, err = th.App.UpdateActive(th.Context, deacivatedUser, false) 99 require.Nil(t, err) 100 101 err = th.App.RemoveAllDeactivatedMembersFromChannel(channel) 102 require.Nil(t, err) 103 104 channelMembers, err = th.App.GetChannelMembersPage(channel.Id, 0, 10000000) 105 require.Nil(t, err) 106 require.Len(t, channelMembers, 1) 107} 108 109func TestMoveChannel(t *testing.T) { 110 t.Run("should move channels between teams", func(t *testing.T) { 111 th := Setup(t).InitBasic() 112 defer th.TearDown() 113 var err *model.AppError 114 115 sourceTeam := th.CreateTeam() 116 targetTeam := th.CreateTeam() 117 channel1 := th.CreateChannel(sourceTeam) 118 defer func() { 119 th.App.PermanentDeleteChannel(channel1) 120 th.App.PermanentDeleteTeam(sourceTeam) 121 th.App.PermanentDeleteTeam(targetTeam) 122 }() 123 124 _, _, err = th.App.AddUserToTeam(th.Context, sourceTeam.Id, th.BasicUser.Id, "") 125 require.Nil(t, err) 126 127 _, _, err = th.App.AddUserToTeam(th.Context, sourceTeam.Id, th.BasicUser2.Id, "") 128 require.Nil(t, err) 129 130 _, _, err = th.App.AddUserToTeam(th.Context, targetTeam.Id, th.BasicUser.Id, "") 131 require.Nil(t, err) 132 133 _, err = th.App.AddUserToChannel(th.BasicUser, channel1, false) 134 require.Nil(t, err) 135 136 _, err = th.App.AddUserToChannel(th.BasicUser2, channel1, false) 137 require.Nil(t, err) 138 139 err = th.App.MoveChannel(th.Context, targetTeam, channel1, th.BasicUser) 140 require.NotNil(t, err, "Should have failed due to mismatched members.") 141 142 _, _, err = th.App.AddUserToTeam(th.Context, targetTeam.Id, th.BasicUser2.Id, "") 143 require.Nil(t, err) 144 145 err = th.App.MoveChannel(th.Context, targetTeam, channel1, th.BasicUser) 146 require.Nil(t, err) 147 148 // Test moving a channel with a deactivated user who isn't in the destination team. 149 // It should fail, unless removeDeactivatedMembers is true. 150 deacivatedUser := th.CreateUser() 151 channel2 := th.CreateChannel(sourceTeam) 152 defer th.App.PermanentDeleteChannel(channel2) 153 154 _, _, err = th.App.AddUserToTeam(th.Context, sourceTeam.Id, deacivatedUser.Id, "") 155 require.Nil(t, err) 156 _, err = th.App.AddUserToChannel(th.BasicUser, channel2, false) 157 require.Nil(t, err) 158 159 _, err = th.App.AddUserToChannel(deacivatedUser, channel2, false) 160 require.Nil(t, err) 161 162 _, err = th.App.UpdateActive(th.Context, deacivatedUser, false) 163 require.Nil(t, err) 164 165 err = th.App.MoveChannel(th.Context, targetTeam, channel2, th.BasicUser) 166 require.NotNil(t, err, "Should have failed due to mismatched deacivated member.") 167 168 // Test moving a channel with no members. 169 channel3 := &model.Channel{ 170 DisplayName: "dn_" + model.NewId(), 171 Name: "name_" + model.NewId(), 172 Type: model.ChannelTypeOpen, 173 TeamId: sourceTeam.Id, 174 CreatorId: th.BasicUser.Id, 175 } 176 177 channel3, err = th.App.CreateChannel(th.Context, channel3, false) 178 require.Nil(t, err) 179 defer th.App.PermanentDeleteChannel(channel3) 180 181 err = th.App.MoveChannel(th.Context, targetTeam, channel3, th.BasicUser) 182 assert.Nil(t, err) 183 }) 184 185 t.Run("should remove sidebar entries when moving channels from one team to another", func(t *testing.T) { 186 th := Setup(t).InitBasic() 187 defer th.TearDown() 188 189 sourceTeam := th.CreateTeam() 190 targetTeam := th.CreateTeam() 191 channel := th.CreateChannel(sourceTeam) 192 193 th.LinkUserToTeam(th.BasicUser, sourceTeam) 194 th.LinkUserToTeam(th.BasicUser, targetTeam) 195 th.AddUserToChannel(th.BasicUser, channel) 196 197 // Put the channel in a custom category so that it explicitly exists in SidebarChannels 198 category, err := th.App.CreateSidebarCategory(th.BasicUser.Id, sourceTeam.Id, &model.SidebarCategoryWithChannels{ 199 SidebarCategory: model.SidebarCategory{ 200 DisplayName: "new category", 201 }, 202 Channels: []string{channel.Id}, 203 }) 204 require.Nil(t, err) 205 require.Equal(t, []string{channel.Id}, category.Channels) 206 207 err = th.App.MoveChannel(th.Context, targetTeam, channel, th.BasicUser) 208 require.Nil(t, err) 209 210 moved, err := th.App.GetChannel(channel.Id) 211 require.Nil(t, err) 212 require.Equal(t, targetTeam.Id, moved.TeamId) 213 214 // The channel should no longer be on the old team 215 updatedCategory, err := th.App.GetSidebarCategory(category.Id) 216 require.Nil(t, err) 217 assert.Equal(t, []string{}, updatedCategory.Channels) 218 219 // And it should be on the new team instead 220 categories, err := th.App.GetSidebarCategories(th.BasicUser.Id, targetTeam.Id) 221 require.Nil(t, err) 222 require.Equal(t, model.SidebarCategoryChannels, categories.Categories[1].Type) 223 assert.Contains(t, categories.Categories[1].Channels, channel.Id) 224 }) 225} 226 227func TestRemoveUsersFromChannelNotMemberOfTeam(t *testing.T) { 228 th := Setup(t).InitBasic() 229 defer th.TearDown() 230 231 team := th.CreateTeam() 232 team2 := th.CreateTeam() 233 channel1 := th.CreateChannel(team) 234 defer func() { 235 th.App.PermanentDeleteChannel(channel1) 236 th.App.PermanentDeleteTeam(team) 237 th.App.PermanentDeleteTeam(team2) 238 }() 239 240 _, _, err := th.App.AddUserToTeam(th.Context, team.Id, th.BasicUser.Id, "") 241 require.Nil(t, err) 242 _, _, err = th.App.AddUserToTeam(th.Context, team2.Id, th.BasicUser.Id, "") 243 require.Nil(t, err) 244 _, _, err = th.App.AddUserToTeam(th.Context, team.Id, th.BasicUser2.Id, "") 245 require.Nil(t, err) 246 247 _, err = th.App.AddUserToChannel(th.BasicUser, channel1, false) 248 require.Nil(t, err) 249 _, err = th.App.AddUserToChannel(th.BasicUser2, channel1, false) 250 require.Nil(t, err) 251 252 err = th.App.RemoveUsersFromChannelNotMemberOfTeam(th.Context, th.SystemAdminUser, channel1, team2) 253 require.Nil(t, err) 254 255 channelMembers, err := th.App.GetChannelMembersPage(channel1.Id, 0, 10000000) 256 require.Nil(t, err) 257 require.Len(t, channelMembers, 1) 258 members := make([]model.ChannelMember, len(channelMembers)) 259 for i, m := range channelMembers { 260 members[i] = m 261 } 262 require.Equal(t, members[0].UserId, th.BasicUser.Id) 263} 264 265func TestJoinDefaultChannelsCreatesChannelMemberHistoryRecordTownSquare(t *testing.T) { 266 th := Setup(t).InitBasic() 267 defer th.TearDown() 268 269 // figure out the initial number of users in town square 270 channel, err := th.App.Srv().Store.Channel().GetByName(th.BasicTeam.Id, "town-square", true) 271 require.NoError(t, err) 272 townSquareChannelId := channel.Id 273 users, nErr := th.App.Srv().Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, townSquareChannelId) 274 require.NoError(t, nErr) 275 initialNumTownSquareUsers := len(users) 276 277 // create a new user that joins the default channels 278 user := th.CreateUser() 279 th.App.JoinDefaultChannels(th.Context, th.BasicTeam.Id, user, false, "") 280 281 // there should be a ChannelMemberHistory record for the user 282 histories, nErr := th.App.Srv().Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, townSquareChannelId) 283 require.NoError(t, nErr) 284 assert.Len(t, histories, initialNumTownSquareUsers+1) 285 286 found := false 287 for _, history := range histories { 288 if user.Id == history.UserId && townSquareChannelId == history.ChannelId { 289 found = true 290 break 291 } 292 } 293 assert.True(t, found) 294} 295 296func TestJoinDefaultChannelsCreatesChannelMemberHistoryRecordOffTopic(t *testing.T) { 297 th := Setup(t).InitBasic() 298 defer th.TearDown() 299 300 // figure out the initial number of users in off-topic 301 channel, err := th.App.Srv().Store.Channel().GetByName(th.BasicTeam.Id, "off-topic", true) 302 require.NoError(t, err) 303 offTopicChannelId := channel.Id 304 users, nErr := th.App.Srv().Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, offTopicChannelId) 305 require.NoError(t, nErr) 306 initialNumTownSquareUsers := len(users) 307 308 // create a new user that joins the default channels 309 user := th.CreateUser() 310 th.App.JoinDefaultChannels(th.Context, th.BasicTeam.Id, user, false, "") 311 312 // there should be a ChannelMemberHistory record for the user 313 histories, nErr := th.App.Srv().Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, offTopicChannelId) 314 require.NoError(t, nErr) 315 assert.Len(t, histories, initialNumTownSquareUsers+1) 316 317 found := false 318 for _, history := range histories { 319 if user.Id == history.UserId && offTopicChannelId == history.ChannelId { 320 found = true 321 break 322 } 323 } 324 assert.True(t, found) 325} 326 327func TestJoinDefaultChannelsExperimentalDefaultChannels(t *testing.T) { 328 th := Setup(t).InitBasic() 329 defer th.TearDown() 330 331 basicChannel2 := th.CreateChannel(th.BasicTeam) 332 defer th.App.PermanentDeleteChannel(basicChannel2) 333 defaultChannelList := []string{th.BasicChannel.Name, basicChannel2.Name, basicChannel2.Name} 334 th.App.Config().TeamSettings.ExperimentalDefaultChannels = defaultChannelList 335 336 user := th.CreateUser() 337 th.App.JoinDefaultChannels(th.Context, th.BasicTeam.Id, user, false, "") 338 339 for _, channelName := range defaultChannelList { 340 channel, err := th.App.GetChannelByName(channelName, th.BasicTeam.Id, false) 341 require.Nil(t, err, "Expected nil, didn't receive nil") 342 343 member, err := th.App.GetChannelMember(context.Background(), channel.Id, user.Id) 344 345 require.NotNil(t, member, "Expected member object, got nil") 346 require.Nil(t, err, "Expected nil object, didn't receive nil") 347 } 348} 349 350func TestCreateChannelPublicCreatesChannelMemberHistoryRecord(t *testing.T) { 351 th := Setup(t).InitBasic() 352 defer th.TearDown() 353 354 // creates a public channel and adds basic user to it 355 publicChannel := th.createChannel(th.BasicTeam, model.ChannelTypeOpen) 356 357 // there should be a ChannelMemberHistory record for the user 358 histories, err := th.App.Srv().Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, publicChannel.Id) 359 require.NoError(t, err) 360 assert.Len(t, histories, 1) 361 assert.Equal(t, th.BasicUser.Id, histories[0].UserId) 362 assert.Equal(t, publicChannel.Id, histories[0].ChannelId) 363} 364 365func TestCreateChannelPrivateCreatesChannelMemberHistoryRecord(t *testing.T) { 366 th := Setup(t).InitBasic() 367 defer th.TearDown() 368 369 // creates a private channel and adds basic user to it 370 privateChannel := th.createChannel(th.BasicTeam, model.ChannelTypePrivate) 371 372 // there should be a ChannelMemberHistory record for the user 373 histories, err := th.App.Srv().Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, privateChannel.Id) 374 require.NoError(t, err) 375 assert.Len(t, histories, 1) 376 assert.Equal(t, th.BasicUser.Id, histories[0].UserId) 377 assert.Equal(t, privateChannel.Id, histories[0].ChannelId) 378} 379func TestCreateChannelDisplayNameTrimsWhitespace(t *testing.T) { 380 th := Setup(t).InitBasic() 381 defer th.TearDown() 382 383 channel, err := th.App.CreateChannel(th.Context, &model.Channel{DisplayName: " Public 1 ", Name: "public1", Type: model.ChannelTypeOpen, TeamId: th.BasicTeam.Id}, false) 384 defer th.App.PermanentDeleteChannel(channel) 385 require.Nil(t, err) 386 require.Equal(t, channel.DisplayName, "Public 1") 387} 388 389func TestUpdateChannelPrivacy(t *testing.T) { 390 th := Setup(t).InitBasic() 391 defer th.TearDown() 392 393 privateChannel := th.createChannel(th.BasicTeam, model.ChannelTypePrivate) 394 privateChannel.Type = model.ChannelTypeOpen 395 396 publicChannel, err := th.App.UpdateChannelPrivacy(th.Context, privateChannel, th.BasicUser) 397 require.Nil(t, err, "Failed to update channel privacy.") 398 assert.Equal(t, publicChannel.Id, privateChannel.Id) 399 assert.Equal(t, publicChannel.Type, model.ChannelTypeOpen) 400} 401 402func TestCreateGroupChannelCreatesChannelMemberHistoryRecord(t *testing.T) { 403 th := Setup(t).InitBasic() 404 defer th.TearDown() 405 406 user1 := th.CreateUser() 407 user2 := th.CreateUser() 408 409 groupUserIds := make([]string, 0) 410 groupUserIds = append(groupUserIds, user1.Id) 411 groupUserIds = append(groupUserIds, user2.Id) 412 groupUserIds = append(groupUserIds, th.BasicUser.Id) 413 414 channel, err := th.App.CreateGroupChannel(groupUserIds, th.BasicUser.Id) 415 416 require.Nil(t, err, "Failed to create group channel.") 417 histories, nErr := th.App.Srv().Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, channel.Id) 418 require.NoError(t, nErr) 419 assert.Len(t, histories, 3) 420 421 channelMemberHistoryUserIds := make([]string, 0) 422 for _, history := range histories { 423 assert.Equal(t, channel.Id, history.ChannelId) 424 channelMemberHistoryUserIds = append(channelMemberHistoryUserIds, history.UserId) 425 } 426 427 sort.Strings(groupUserIds) 428 sort.Strings(channelMemberHistoryUserIds) 429 assert.Equal(t, groupUserIds, channelMemberHistoryUserIds) 430} 431 432func TestCreateDirectChannelCreatesChannelMemberHistoryRecord(t *testing.T) { 433 th := Setup(t) 434 defer th.TearDown() 435 436 user1 := th.CreateUser() 437 user2 := th.CreateUser() 438 439 channel, err := th.App.GetOrCreateDirectChannel(th.Context, user1.Id, user2.Id) 440 require.Nil(t, err, "Failed to create direct channel.") 441 442 histories, nErr := th.App.Srv().Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, channel.Id) 443 require.NoError(t, nErr) 444 assert.Len(t, histories, 2) 445 446 historyId0 := histories[0].UserId 447 historyId1 := histories[1].UserId 448 switch historyId0 { 449 case user1.Id: 450 assert.Equal(t, user2.Id, historyId1) 451 case user2.Id: 452 assert.Equal(t, user1.Id, historyId1) 453 default: 454 require.Fail(t, "Unexpected user id in ChannelMemberHistory table", historyId0) 455 } 456} 457 458func TestGetDirectChannelCreatesChannelMemberHistoryRecord(t *testing.T) { 459 th := Setup(t) 460 defer th.TearDown() 461 462 user1 := th.CreateUser() 463 user2 := th.CreateUser() 464 465 // this function call implicitly creates a direct channel between the two users if one doesn't already exist 466 channel, err := th.App.GetOrCreateDirectChannel(th.Context, user1.Id, user2.Id) 467 require.Nil(t, err, "Failed to create direct channel.") 468 469 // there should be a ChannelMemberHistory record for both users 470 histories, nErr := th.App.Srv().Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, channel.Id) 471 require.NoError(t, nErr) 472 assert.Len(t, histories, 2) 473 474 historyId0 := histories[0].UserId 475 historyId1 := histories[1].UserId 476 switch historyId0 { 477 case user1.Id: 478 assert.Equal(t, user2.Id, historyId1) 479 case user2.Id: 480 assert.Equal(t, user1.Id, historyId1) 481 default: 482 require.Fail(t, "Unexpected user id in ChannelMemberHistory table", historyId0) 483 } 484} 485 486func TestAddUserToChannelCreatesChannelMemberHistoryRecord(t *testing.T) { 487 th := Setup(t).InitBasic() 488 defer th.TearDown() 489 490 // create a user and add it to a channel 491 user := th.CreateUser() 492 _, err := th.App.AddTeamMember(th.Context, th.BasicTeam.Id, user.Id) 493 require.Nil(t, err, "Failed to add user to team.") 494 495 groupUserIds := make([]string, 0) 496 groupUserIds = append(groupUserIds, th.BasicUser.Id) 497 groupUserIds = append(groupUserIds, user.Id) 498 499 channel := th.createChannel(th.BasicTeam, model.ChannelTypeOpen) 500 501 _, err = th.App.AddUserToChannel(user, channel, false) 502 require.Nil(t, err, "Failed to add user to channel.") 503 504 // there should be a ChannelMemberHistory record for the user 505 histories, nErr := th.App.Srv().Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, channel.Id) 506 require.NoError(t, nErr) 507 assert.Len(t, histories, 2) 508 channelMemberHistoryUserIds := make([]string, 0) 509 for _, history := range histories { 510 assert.Equal(t, channel.Id, history.ChannelId) 511 channelMemberHistoryUserIds = append(channelMemberHistoryUserIds, history.UserId) 512 } 513 assert.Equal(t, groupUserIds, channelMemberHistoryUserIds) 514} 515 516func TestLeaveDefaultChannel(t *testing.T) { 517 th := Setup(t).InitBasic() 518 defer th.TearDown() 519 520 guest := th.CreateGuest() 521 th.LinkUserToTeam(guest, th.BasicTeam) 522 523 townSquare, err := th.App.GetChannelByName("town-square", th.BasicTeam.Id, false) 524 require.Nil(t, err) 525 th.AddUserToChannel(guest, townSquare) 526 th.AddUserToChannel(th.BasicUser, townSquare) 527 528 t.Run("User tries to leave the default channel", func(t *testing.T) { 529 err = th.App.LeaveChannel(th.Context, townSquare.Id, th.BasicUser.Id) 530 assert.NotNil(t, err, "It should fail to remove a regular user from the default channel") 531 assert.Equal(t, err.Id, "api.channel.remove.default.app_error") 532 _, err = th.App.GetChannelMember(context.Background(), townSquare.Id, th.BasicUser.Id) 533 assert.Nil(t, err) 534 }) 535 536 t.Run("Guest leaves the default channel", func(t *testing.T) { 537 err = th.App.LeaveChannel(th.Context, townSquare.Id, guest.Id) 538 assert.Nil(t, err, "It should allow to remove a guest user from the default channel") 539 _, err = th.App.GetChannelMember(context.Background(), townSquare.Id, guest.Id) 540 assert.NotNil(t, err) 541 }) 542} 543 544func TestLeaveLastChannel(t *testing.T) { 545 th := Setup(t).InitBasic() 546 defer th.TearDown() 547 548 guest := th.CreateGuest() 549 th.LinkUserToTeam(guest, th.BasicTeam) 550 551 townSquare, err := th.App.GetChannelByName("town-square", th.BasicTeam.Id, false) 552 require.Nil(t, err) 553 th.AddUserToChannel(guest, townSquare) 554 th.AddUserToChannel(guest, th.BasicChannel) 555 556 t.Run("Guest leaves not last channel", func(t *testing.T) { 557 err = th.App.LeaveChannel(th.Context, townSquare.Id, guest.Id) 558 require.Nil(t, err) 559 _, err = th.App.GetTeamMember(th.BasicTeam.Id, guest.Id) 560 assert.Nil(t, err, "It should maintain the team membership") 561 }) 562 563 t.Run("Guest leaves last channel", func(t *testing.T) { 564 err = th.App.LeaveChannel(th.Context, th.BasicChannel.Id, guest.Id) 565 assert.Nil(t, err, "It should allow to remove a guest user from the default channel") 566 _, err = th.App.GetChannelMember(context.Background(), th.BasicChannel.Id, guest.Id) 567 assert.NotNil(t, err) 568 _, err = th.App.GetTeamMember(th.BasicTeam.Id, guest.Id) 569 assert.Nil(t, err, "It should remove the team membership") 570 }) 571} 572 573func TestAddChannelMemberNoUserRequestor(t *testing.T) { 574 th := Setup(t).InitBasic() 575 defer th.TearDown() 576 577 // create a user and add it to a channel 578 user := th.CreateUser() 579 _, err := th.App.AddTeamMember(th.Context, th.BasicTeam.Id, user.Id) 580 require.Nil(t, err) 581 582 groupUserIds := make([]string, 0) 583 groupUserIds = append(groupUserIds, th.BasicUser.Id) 584 groupUserIds = append(groupUserIds, user.Id) 585 586 channel := th.createChannel(th.BasicTeam, model.ChannelTypeOpen) 587 588 _, err = th.App.AddChannelMember(th.Context, user.Id, channel, ChannelMemberOpts{}) 589 require.Nil(t, err, "Failed to add user to channel.") 590 591 // there should be a ChannelMemberHistory record for the user 592 histories, nErr := th.App.Srv().Store.ChannelMemberHistory().GetUsersInChannelDuring(model.GetMillis()-100, model.GetMillis()+100, channel.Id) 593 require.NoError(t, nErr) 594 assert.Len(t, histories, 2) 595 channelMemberHistoryUserIds := make([]string, 0) 596 for _, history := range histories { 597 assert.Equal(t, channel.Id, history.ChannelId) 598 channelMemberHistoryUserIds = append(channelMemberHistoryUserIds, history.UserId) 599 } 600 assert.Equal(t, groupUserIds, channelMemberHistoryUserIds) 601 602 postList, nErr := th.App.Srv().Store.Post().GetPosts(model.GetPostsOptions{ChannelId: channel.Id, Page: 0, PerPage: 1}, false) 603 require.NoError(t, nErr) 604 605 if assert.Len(t, postList.Order, 1) { 606 post := postList.Posts[postList.Order[0]] 607 608 assert.Equal(t, model.PostTypeJoinChannel, post.Type) 609 assert.Equal(t, user.Id, post.UserId) 610 assert.Equal(t, user.Username, post.GetProp("username")) 611 } 612} 613 614func TestAppUpdateChannelScheme(t *testing.T) { 615 th := Setup(t).InitBasic() 616 defer th.TearDown() 617 618 channel := th.BasicChannel 619 mockID := model.NewString("x") 620 channel.SchemeId = mockID 621 622 updatedChannel, err := th.App.UpdateChannelScheme(channel) 623 require.Nil(t, err) 624 625 if updatedChannel.SchemeId != mockID { 626 require.Fail(t, "Wrong Channel SchemeId") 627 } 628} 629 630func TestSetChannelsMuted(t *testing.T) { 631 t.Run("should mute and unmute the given channels", func(t *testing.T) { 632 th := Setup(t).InitBasic() 633 defer th.TearDown() 634 635 channel1 := th.BasicChannel 636 637 channel2 := th.CreateChannel(th.BasicTeam) 638 th.AddUserToChannel(th.BasicUser, channel2) 639 640 // Ensure that both channels start unmuted 641 member1, err := th.App.GetChannelMember(context.Background(), channel1.Id, th.BasicUser.Id) 642 require.Nil(t, err) 643 require.False(t, member1.IsChannelMuted()) 644 645 member2, err := th.App.GetChannelMember(context.Background(), channel2.Id, th.BasicUser.Id) 646 require.Nil(t, err) 647 require.False(t, member2.IsChannelMuted()) 648 649 // Mute both channels 650 updated, err := th.App.setChannelsMuted([]string{channel1.Id, channel2.Id}, th.BasicUser.Id, true) 651 require.Nil(t, err) 652 assert.True(t, updated[0].IsChannelMuted()) 653 assert.True(t, updated[1].IsChannelMuted()) 654 655 // Verify that the channels are muted in the database 656 member1, err = th.App.GetChannelMember(context.Background(), channel1.Id, th.BasicUser.Id) 657 require.Nil(t, err) 658 require.True(t, member1.IsChannelMuted()) 659 660 member2, err = th.App.GetChannelMember(context.Background(), channel2.Id, th.BasicUser.Id) 661 require.Nil(t, err) 662 require.True(t, member2.IsChannelMuted()) 663 664 // Unm both channels 665 updated, err = th.App.setChannelsMuted([]string{channel1.Id, channel2.Id}, th.BasicUser.Id, false) 666 require.Nil(t, err) 667 assert.False(t, updated[0].IsChannelMuted()) 668 assert.False(t, updated[1].IsChannelMuted()) 669 670 // Verify that the channels are muted in the database 671 member1, err = th.App.GetChannelMember(context.Background(), channel1.Id, th.BasicUser.Id) 672 require.Nil(t, err) 673 require.False(t, member1.IsChannelMuted()) 674 675 member2, err = th.App.GetChannelMember(context.Background(), channel2.Id, th.BasicUser.Id) 676 require.Nil(t, err) 677 require.False(t, member2.IsChannelMuted()) 678 }) 679} 680 681func TestFillInChannelProps(t *testing.T) { 682 th := Setup(t).InitBasic() 683 defer th.TearDown() 684 685 channelPublic1, err := th.App.CreateChannel(th.Context, &model.Channel{DisplayName: "Public 1", Name: "public1", Type: model.ChannelTypeOpen, TeamId: th.BasicTeam.Id}, false) 686 require.Nil(t, err) 687 defer th.App.PermanentDeleteChannel(channelPublic1) 688 689 channelPublic2, err := th.App.CreateChannel(th.Context, &model.Channel{DisplayName: "Public 2", Name: "public2", Type: model.ChannelTypeOpen, TeamId: th.BasicTeam.Id}, false) 690 require.Nil(t, err) 691 defer th.App.PermanentDeleteChannel(channelPublic2) 692 693 channelPrivate, err := th.App.CreateChannel(th.Context, &model.Channel{DisplayName: "Private", Name: "private", Type: model.ChannelTypePrivate, TeamId: th.BasicTeam.Id}, false) 694 require.Nil(t, err) 695 defer th.App.PermanentDeleteChannel(channelPrivate) 696 697 otherTeamId := model.NewId() 698 otherTeam := &model.Team{ 699 DisplayName: "dn_" + otherTeamId, 700 Name: "name" + otherTeamId, 701 Email: "success+" + otherTeamId + "@simulator.amazonses.com", 702 Type: model.TeamOpen, 703 } 704 otherTeam, err = th.App.CreateTeam(th.Context, otherTeam) 705 require.Nil(t, err) 706 defer th.App.PermanentDeleteTeam(otherTeam) 707 708 channelOtherTeam, err := th.App.CreateChannel(th.Context, &model.Channel{DisplayName: "Other Team Channel", Name: "other-team", Type: model.ChannelTypeOpen, TeamId: otherTeam.Id}, false) 709 require.Nil(t, err) 710 defer th.App.PermanentDeleteChannel(channelOtherTeam) 711 712 // Note that purpose is intentionally plaintext below. 713 714 t.Run("single channels", func(t *testing.T) { 715 testCases := []struct { 716 Description string 717 Channel *model.Channel 718 ExpectedChannelProps map[string]interface{} 719 }{ 720 { 721 "channel on basic team without references", 722 &model.Channel{ 723 TeamId: th.BasicTeam.Id, 724 Header: "No references", 725 Purpose: "No references", 726 }, 727 nil, 728 }, 729 { 730 "channel on basic team", 731 &model.Channel{ 732 TeamId: th.BasicTeam.Id, 733 Header: "~public1, ~private, ~other-team", 734 Purpose: "~public2, ~private, ~other-team", 735 }, 736 map[string]interface{}{ 737 "channel_mentions": map[string]interface{}{ 738 "public1": map[string]interface{}{ 739 "display_name": "Public 1", 740 }, 741 }, 742 }, 743 }, 744 { 745 "channel on other team", 746 &model.Channel{ 747 TeamId: otherTeam.Id, 748 Header: "~public1, ~private, ~other-team", 749 Purpose: "~public2, ~private, ~other-team", 750 }, 751 map[string]interface{}{ 752 "channel_mentions": map[string]interface{}{ 753 "other-team": map[string]interface{}{ 754 "display_name": "Other Team Channel", 755 }, 756 }, 757 }, 758 }, 759 } 760 761 for _, testCase := range testCases { 762 t.Run(testCase.Description, func(t *testing.T) { 763 err = th.App.FillInChannelProps(testCase.Channel) 764 require.Nil(t, err) 765 766 assert.Equal(t, testCase.ExpectedChannelProps, testCase.Channel.Props) 767 }) 768 } 769 }) 770 771 t.Run("multiple channels", func(t *testing.T) { 772 testCases := []struct { 773 Description string 774 Channels model.ChannelList 775 ExpectedChannelProps map[string]interface{} 776 }{ 777 { 778 "single channel on basic team", 779 model.ChannelList{ 780 { 781 Name: "test", 782 TeamId: th.BasicTeam.Id, 783 Header: "~public1, ~private, ~other-team", 784 Purpose: "~public2, ~private, ~other-team", 785 }, 786 }, 787 map[string]interface{}{ 788 "test": map[string]interface{}{ 789 "channel_mentions": map[string]interface{}{ 790 "public1": map[string]interface{}{ 791 "display_name": "Public 1", 792 }, 793 }, 794 }, 795 }, 796 }, 797 { 798 "multiple channels on basic team", 799 model.ChannelList{ 800 { 801 Name: "test", 802 TeamId: th.BasicTeam.Id, 803 Header: "~public1, ~private, ~other-team", 804 Purpose: "~public2, ~private, ~other-team", 805 }, 806 { 807 Name: "test2", 808 TeamId: th.BasicTeam.Id, 809 Header: "~private, ~other-team", 810 Purpose: "~public2, ~private, ~other-team", 811 }, 812 { 813 Name: "test3", 814 TeamId: th.BasicTeam.Id, 815 Header: "No references", 816 Purpose: "No references", 817 }, 818 }, 819 map[string]interface{}{ 820 "test": map[string]interface{}{ 821 "channel_mentions": map[string]interface{}{ 822 "public1": map[string]interface{}{ 823 "display_name": "Public 1", 824 }, 825 }, 826 }, 827 "test2": map[string]interface{}(nil), 828 "test3": map[string]interface{}(nil), 829 }, 830 }, 831 { 832 "multiple channels across teams", 833 model.ChannelList{ 834 { 835 Name: "test", 836 TeamId: th.BasicTeam.Id, 837 Header: "~public1, ~private, ~other-team", 838 Purpose: "~public2, ~private, ~other-team", 839 }, 840 { 841 Name: "test2", 842 TeamId: otherTeam.Id, 843 Header: "~private, ~other-team", 844 Purpose: "~public2, ~private, ~other-team", 845 }, 846 { 847 Name: "test3", 848 TeamId: th.BasicTeam.Id, 849 Header: "No references", 850 Purpose: "No references", 851 }, 852 }, 853 map[string]interface{}{ 854 "test": map[string]interface{}{ 855 "channel_mentions": map[string]interface{}{ 856 "public1": map[string]interface{}{ 857 "display_name": "Public 1", 858 }, 859 }, 860 }, 861 "test2": map[string]interface{}{ 862 "channel_mentions": map[string]interface{}{ 863 "other-team": map[string]interface{}{ 864 "display_name": "Other Team Channel", 865 }, 866 }, 867 }, 868 "test3": map[string]interface{}(nil), 869 }, 870 }, 871 } 872 873 for _, testCase := range testCases { 874 t.Run(testCase.Description, func(t *testing.T) { 875 err = th.App.FillInChannelsProps(testCase.Channels) 876 require.Nil(t, err) 877 878 for _, channel := range testCase.Channels { 879 assert.Equal(t, testCase.ExpectedChannelProps[channel.Name], channel.Props) 880 } 881 }) 882 } 883 }) 884} 885 886func TestRenameChannel(t *testing.T) { 887 th := Setup(t).InitBasic() 888 defer th.TearDown() 889 890 testCases := []struct { 891 Name string 892 Channel *model.Channel 893 ExpectError bool 894 ChannelName string 895 ExpectedName string 896 ExpectedDisplayName string 897 }{ 898 { 899 "Rename open channel", 900 th.createChannel(th.BasicTeam, model.ChannelTypeOpen), 901 false, 902 "newchannelname", 903 "newchannelname", 904 "New Display Name", 905 }, 906 { 907 "Fail on rename open channel with bad name", 908 th.createChannel(th.BasicTeam, model.ChannelTypeOpen), 909 true, 910 "6zii9a9g6pruzj451x3esok54h__wr4j4g8zqtnhmkw771pfpynqwo", 911 "", 912 "", 913 }, 914 { 915 "Success on rename open channel with consecutive underscores in name", 916 th.createChannel(th.BasicTeam, model.ChannelTypeOpen), 917 false, 918 "foo__bar", 919 "foo__bar", 920 "New Display Name", 921 }, 922 { 923 "Fail on rename direct message channel", 924 th.CreateDmChannel(th.BasicUser2), 925 true, 926 "newchannelname", 927 "", 928 "", 929 }, 930 { 931 "Fail on rename group message channel", 932 th.CreateGroupChannel(th.BasicUser2, th.CreateUser()), 933 true, 934 "newchannelname", 935 "", 936 "", 937 }, 938 } 939 940 for _, tc := range testCases { 941 t.Run(tc.Name, func(t *testing.T) { 942 channel, err := th.App.RenameChannel(tc.Channel, tc.ChannelName, "New Display Name") 943 if tc.ExpectError { 944 assert.NotNil(t, err) 945 } else { 946 assert.Equal(t, tc.ExpectedName, channel.Name) 947 assert.Equal(t, tc.ExpectedDisplayName, channel.DisplayName) 948 } 949 }) 950 } 951} 952 953func TestGetChannelMembersTimezones(t *testing.T) { 954 th := Setup(t).InitBasic() 955 defer th.TearDown() 956 957 _, err := th.App.AddChannelMember(th.Context, th.BasicUser2.Id, th.BasicChannel, ChannelMemberOpts{}) 958 require.Nil(t, err, "Failed to add user to channel.") 959 960 user := th.BasicUser 961 user.Timezone["useAutomaticTimezone"] = "false" 962 user.Timezone["manualTimezone"] = "XOXO/BLABLA" 963 th.App.UpdateUser(user, false) 964 965 user2 := th.BasicUser2 966 user2.Timezone["automaticTimezone"] = "NoWhere/Island" 967 th.App.UpdateUser(user2, false) 968 969 user3 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} 970 ruser, _ := th.App.CreateUser(th.Context, &user3) 971 th.App.AddUserToChannel(ruser, th.BasicChannel, false) 972 973 ruser.Timezone["automaticTimezone"] = "NoWhere/Island" 974 th.App.UpdateUser(ruser, false) 975 976 user4 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} 977 ruser, _ = th.App.CreateUser(th.Context, &user4) 978 th.App.AddUserToChannel(ruser, th.BasicChannel, false) 979 980 timezones, err := th.App.GetChannelMembersTimezones(th.BasicChannel.Id) 981 require.Nil(t, err, "Failed to get the timezones for a channel.") 982 983 assert.Equal(t, 2, len(timezones)) 984} 985 986func TestGetChannelsForUser(t *testing.T) { 987 th := Setup(t).InitBasic() 988 channel := &model.Channel{ 989 DisplayName: "Public", 990 Name: "public", 991 Type: model.ChannelTypeOpen, 992 CreatorId: th.BasicUser.Id, 993 TeamId: th.BasicTeam.Id, 994 } 995 th.App.CreateChannel(th.Context, channel, true) 996 defer th.App.PermanentDeleteChannel(channel) 997 defer th.TearDown() 998 999 channelList, err := th.App.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, false, 0) 1000 require.Nil(t, err) 1001 require.Len(t, channelList, 4) 1002 1003 th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id) 1004 1005 // Now we get all the non-archived channels for the user 1006 channelList, err = th.App.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, false, 0) 1007 require.Nil(t, err) 1008 require.Len(t, channelList, 3) 1009 1010 // Now we get all the channels, even though are archived, for the user 1011 channelList, err = th.App.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, true, 0) 1012 require.Nil(t, err) 1013 require.Len(t, channelList, 4) 1014} 1015 1016func TestGetPublicChannelsForTeam(t *testing.T) { 1017 th := Setup(t) 1018 team := th.CreateTeam() 1019 defer th.TearDown() 1020 1021 var expectedChannels []*model.Channel 1022 1023 townSquare, err := th.App.GetChannelByName("town-square", team.Id, false) 1024 require.Nil(t, err) 1025 require.NotNil(t, townSquare) 1026 expectedChannels = append(expectedChannels, townSquare) 1027 1028 offTopic, err := th.App.GetChannelByName("off-topic", team.Id, false) 1029 require.Nil(t, err) 1030 require.NotNil(t, offTopic) 1031 expectedChannels = append(expectedChannels, offTopic) 1032 1033 for i := 0; i < 8; i++ { 1034 channel := model.Channel{ 1035 DisplayName: fmt.Sprintf("Public %v", i), 1036 Name: fmt.Sprintf("public_%v", i), 1037 Type: model.ChannelTypeOpen, 1038 TeamId: team.Id, 1039 } 1040 var rchannel *model.Channel 1041 rchannel, err = th.App.CreateChannel(th.Context, &channel, false) 1042 require.Nil(t, err) 1043 require.NotNil(t, rchannel) 1044 defer th.App.PermanentDeleteChannel(rchannel) 1045 1046 // Store the user ids for comparison later 1047 expectedChannels = append(expectedChannels, rchannel) 1048 } 1049 1050 // Fetch public channels multipile times 1051 channelList, err := th.App.GetPublicChannelsForTeam(team.Id, 0, 5) 1052 require.Nil(t, err) 1053 channelList2, err := th.App.GetPublicChannelsForTeam(team.Id, 5, 5) 1054 require.Nil(t, err) 1055 1056 channels := append(channelList, channelList2...) 1057 assert.ElementsMatch(t, expectedChannels, channels) 1058} 1059 1060func TestGetPrivateChannelsForTeam(t *testing.T) { 1061 th := Setup(t) 1062 team := th.CreateTeam() 1063 defer th.TearDown() 1064 1065 var expectedChannels []*model.Channel 1066 for i := 0; i < 8; i++ { 1067 channel := model.Channel{ 1068 DisplayName: fmt.Sprintf("Private %v", i), 1069 Name: fmt.Sprintf("private_%v", i), 1070 Type: model.ChannelTypePrivate, 1071 TeamId: team.Id, 1072 } 1073 var rchannel *model.Channel 1074 rchannel, err := th.App.CreateChannel(th.Context, &channel, false) 1075 require.Nil(t, err) 1076 require.NotNil(t, rchannel) 1077 defer th.App.PermanentDeleteChannel(rchannel) 1078 1079 // Store the user ids for comparison later 1080 expectedChannels = append(expectedChannels, rchannel) 1081 } 1082 1083 // Fetch private channels multipile times 1084 channelList, err := th.App.GetPrivateChannelsForTeam(team.Id, 0, 5) 1085 require.Nil(t, err) 1086 channelList2, err := th.App.GetPrivateChannelsForTeam(team.Id, 5, 5) 1087 require.Nil(t, err) 1088 1089 channels := append(channelList, channelList2...) 1090 assert.ElementsMatch(t, expectedChannels, channels) 1091} 1092 1093func TestUpdateChannelMemberRolesChangingGuest(t *testing.T) { 1094 th := Setup(t).InitBasic() 1095 defer th.TearDown() 1096 1097 t.Run("from guest to user", func(t *testing.T) { 1098 user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} 1099 ruser, _ := th.App.CreateGuest(th.Context, &user) 1100 1101 _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") 1102 require.Nil(t, err) 1103 1104 _, err = th.App.AddUserToChannel(ruser, th.BasicChannel, false) 1105 require.Nil(t, err) 1106 1107 _, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_user") 1108 require.NotNil(t, err, "Should fail when try to modify the guest role") 1109 }) 1110 1111 t.Run("from user to guest", func(t *testing.T) { 1112 user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} 1113 ruser, _ := th.App.CreateUser(th.Context, &user) 1114 1115 _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") 1116 require.Nil(t, err) 1117 1118 _, err = th.App.AddUserToChannel(ruser, th.BasicChannel, false) 1119 require.Nil(t, err) 1120 1121 _, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_guest") 1122 require.NotNil(t, err, "Should fail when try to modify the guest role") 1123 }) 1124 1125 t.Run("from user to admin", func(t *testing.T) { 1126 user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} 1127 ruser, _ := th.App.CreateUser(th.Context, &user) 1128 1129 _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") 1130 require.Nil(t, err) 1131 1132 _, err = th.App.AddUserToChannel(ruser, th.BasicChannel, false) 1133 require.Nil(t, err) 1134 1135 _, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_user channel_admin") 1136 require.Nil(t, err, "Should work when you not modify guest role") 1137 }) 1138 1139 t.Run("from guest to guest plus custom", func(t *testing.T) { 1140 user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} 1141 ruser, _ := th.App.CreateGuest(th.Context, &user) 1142 1143 _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") 1144 require.Nil(t, err) 1145 1146 _, err = th.App.AddUserToChannel(ruser, th.BasicChannel, false) 1147 require.Nil(t, err) 1148 1149 _, err = th.App.CreateRole(&model.Role{Name: "custom", DisplayName: "custom", Description: "custom"}) 1150 require.Nil(t, err) 1151 1152 _, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_guest custom") 1153 require.Nil(t, err, "Should work when you not modify guest role") 1154 }) 1155 1156 t.Run("a guest cant have user role", func(t *testing.T) { 1157 user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} 1158 ruser, _ := th.App.CreateGuest(th.Context, &user) 1159 1160 _, _, err := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, ruser.Id, "") 1161 require.Nil(t, err) 1162 1163 _, err = th.App.AddUserToChannel(ruser, th.BasicChannel, false) 1164 require.Nil(t, err) 1165 1166 _, err = th.App.UpdateChannelMemberRoles(th.BasicChannel.Id, ruser.Id, "channel_guest channel_user") 1167 require.NotNil(t, err, "Should work when you not modify guest role") 1168 }) 1169} 1170 1171func TestDefaultChannelNames(t *testing.T) { 1172 th := Setup(t) 1173 defer th.TearDown() 1174 1175 actual := th.App.DefaultChannelNames() 1176 expect := []string{"town-square", "off-topic"} 1177 require.ElementsMatch(t, expect, actual) 1178 1179 th.App.UpdateConfig(func(cfg *model.Config) { 1180 cfg.TeamSettings.ExperimentalDefaultChannels = []string{"foo", "bar"} 1181 }) 1182 1183 actual = th.App.DefaultChannelNames() 1184 expect = []string{"town-square", "foo", "bar"} 1185 require.ElementsMatch(t, expect, actual) 1186} 1187 1188func TestSearchChannelsForUser(t *testing.T) { 1189 th := Setup(t).InitBasic() 1190 defer th.TearDown() 1191 1192 c1, err := th.App.CreateChannel(th.Context, &model.Channel{DisplayName: "test-dev-1", Name: "test-dev-1", Type: model.ChannelTypeOpen, TeamId: th.BasicTeam.Id}, false) 1193 require.Nil(t, err) 1194 1195 c2, err := th.App.CreateChannel(th.Context, &model.Channel{DisplayName: "test-dev-2", Name: "test-dev-2", Type: model.ChannelTypeOpen, TeamId: th.BasicTeam.Id}, false) 1196 require.Nil(t, err) 1197 1198 c3, err := th.App.CreateChannel(th.Context, &model.Channel{DisplayName: "dev-3", Name: "dev-3", Type: model.ChannelTypeOpen, TeamId: th.BasicTeam.Id}, false) 1199 require.Nil(t, err) 1200 1201 defer func() { 1202 th.App.PermanentDeleteChannel(c1) 1203 th.App.PermanentDeleteChannel(c2) 1204 th.App.PermanentDeleteChannel(c3) 1205 }() 1206 1207 // add user to test-dev-1 and dev3 1208 _, err = th.App.AddUserToChannel(th.BasicUser, c1, false) 1209 require.Nil(t, err) 1210 _, err = th.App.AddUserToChannel(th.BasicUser, c3, false) 1211 require.Nil(t, err) 1212 1213 searchAndCheck := func(t *testing.T, term string, expectedDisplayNames []string) { 1214 res, searchErr := th.App.SearchChannelsForUser(th.BasicUser.Id, th.BasicTeam.Id, term) 1215 require.Nil(t, searchErr) 1216 require.Len(t, res, len(expectedDisplayNames)) 1217 1218 resultDisplayNames := []string{} 1219 for _, c := range res { 1220 resultDisplayNames = append(resultDisplayNames, c.Name) 1221 } 1222 require.ElementsMatch(t, expectedDisplayNames, resultDisplayNames) 1223 } 1224 1225 t.Run("Search for test, only test-dev-1 should be returned", func(t *testing.T) { 1226 searchAndCheck(t, "test", []string{"test-dev-1"}) 1227 }) 1228 1229 t.Run("Search for dev, both test-dev-1 and dev-3 should be returned", func(t *testing.T) { 1230 searchAndCheck(t, "dev", []string{"test-dev-1", "dev-3"}) 1231 }) 1232 1233 t.Run("After adding user to test-dev-2, search for dev, the three channels should be returned", func(t *testing.T) { 1234 _, err = th.App.AddUserToChannel(th.BasicUser, c2, false) 1235 require.Nil(t, err) 1236 1237 searchAndCheck(t, "dev", []string{"test-dev-1", "test-dev-2", "dev-3"}) 1238 }) 1239} 1240 1241func TestMarkChannelAsUnreadFromPost(t *testing.T) { 1242 th := Setup(t).InitBasic() 1243 defer th.TearDown() 1244 1245 u1 := th.BasicUser 1246 u2 := th.BasicUser2 1247 c1 := th.BasicChannel 1248 pc1 := th.CreatePrivateChannel(th.BasicTeam) 1249 th.AddUserToChannel(u2, c1) 1250 th.AddUserToChannel(u1, pc1) 1251 th.AddUserToChannel(u2, pc1) 1252 1253 p1 := th.CreatePost(c1) 1254 p2 := th.CreatePost(c1) 1255 p3 := th.CreatePost(c1) 1256 1257 pp1 := th.CreatePost(pc1) 1258 require.NotNil(t, pp1) 1259 pp2 := th.CreatePost(pc1) 1260 1261 unread, err := th.App.GetChannelUnread(c1.Id, u1.Id) 1262 require.Nil(t, err) 1263 require.Equal(t, int64(4), unread.MsgCount) 1264 unread, err = th.App.GetChannelUnread(c1.Id, u2.Id) 1265 require.Nil(t, err) 1266 require.Equal(t, int64(4), unread.MsgCount) 1267 err = th.App.UpdateChannelLastViewedAt([]string{c1.Id, pc1.Id}, u1.Id) 1268 require.Nil(t, err) 1269 err = th.App.UpdateChannelLastViewedAt([]string{c1.Id, pc1.Id}, u2.Id) 1270 require.Nil(t, err) 1271 unread, err = th.App.GetChannelUnread(c1.Id, u2.Id) 1272 require.Nil(t, err) 1273 require.Equal(t, int64(0), unread.MsgCount) 1274 1275 t.Run("Unread but last one", func(t *testing.T) { 1276 response, err := th.App.MarkChannelAsUnreadFromPost(p2.Id, u1.Id, true, true) 1277 require.Nil(t, err) 1278 require.NotNil(t, response) 1279 assert.Equal(t, int64(2), response.MsgCount) 1280 unread, err := th.App.GetChannelUnread(c1.Id, u1.Id) 1281 require.Nil(t, err) 1282 assert.Equal(t, int64(2), unread.MsgCount) 1283 assert.Equal(t, p2.CreateAt-1, response.LastViewedAt) 1284 }) 1285 1286 t.Run("Unread last one", func(t *testing.T) { 1287 response, err := th.App.MarkChannelAsUnreadFromPost(p3.Id, u1.Id, true, true) 1288 require.Nil(t, err) 1289 require.NotNil(t, response) 1290 assert.Equal(t, int64(3), response.MsgCount) 1291 unread, err := th.App.GetChannelUnread(c1.Id, u1.Id) 1292 require.Nil(t, err) 1293 assert.Equal(t, int64(1), unread.MsgCount) 1294 assert.Equal(t, p3.CreateAt-1, response.LastViewedAt) 1295 }) 1296 1297 t.Run("Unread first one", func(t *testing.T) { 1298 response, err := th.App.MarkChannelAsUnreadFromPost(p1.Id, u1.Id, true, true) 1299 require.Nil(t, err) 1300 require.NotNil(t, response) 1301 assert.Equal(t, int64(1), response.MsgCount) 1302 unread, err := th.App.GetChannelUnread(c1.Id, u1.Id) 1303 require.Nil(t, err) 1304 assert.Equal(t, int64(3), unread.MsgCount) 1305 assert.Equal(t, p1.CreateAt-1, response.LastViewedAt) 1306 }) 1307 1308 t.Run("Other users are unaffected", func(t *testing.T) { 1309 unread, err := th.App.GetChannelUnread(c1.Id, u2.Id) 1310 require.Nil(t, err) 1311 assert.Equal(t, int64(0), unread.MsgCount) 1312 }) 1313 1314 t.Run("Unread on a private channel", func(t *testing.T) { 1315 response, err := th.App.MarkChannelAsUnreadFromPost(pp1.Id, u1.Id, true, true) 1316 require.Nil(t, err) 1317 require.NotNil(t, response) 1318 assert.Equal(t, int64(0), response.MsgCount) 1319 unread, err := th.App.GetChannelUnread(pc1.Id, u1.Id) 1320 require.Nil(t, err) 1321 assert.Equal(t, int64(2), unread.MsgCount) 1322 assert.Equal(t, pp1.CreateAt-1, response.LastViewedAt) 1323 1324 response, err = th.App.MarkChannelAsUnreadFromPost(pp2.Id, u1.Id, true, true) 1325 assert.Nil(t, err) 1326 assert.Equal(t, int64(1), response.MsgCount) 1327 unread, err = th.App.GetChannelUnread(pc1.Id, u1.Id) 1328 require.Nil(t, err) 1329 assert.Equal(t, int64(1), unread.MsgCount) 1330 assert.Equal(t, pp2.CreateAt-1, response.LastViewedAt) 1331 }) 1332 1333 t.Run("Unread with mentions", func(t *testing.T) { 1334 c2 := th.CreateChannel(th.BasicTeam) 1335 _, err := th.App.AddUserToChannel(u2, c2, false) 1336 require.Nil(t, err) 1337 1338 p4, err := th.App.CreatePost(th.Context, &model.Post{ 1339 UserId: u2.Id, 1340 ChannelId: c2.Id, 1341 Message: "@" + u1.Username, 1342 }, c2, false, true) 1343 require.Nil(t, err) 1344 th.CreatePost(c2) 1345 1346 th.App.CreatePost(th.Context, &model.Post{ 1347 UserId: u2.Id, 1348 ChannelId: c2.Id, 1349 RootId: p4.Id, 1350 Message: "@" + u1.Username, 1351 }, c2, false, true) 1352 1353 response, err := th.App.MarkChannelAsUnreadFromPost(p4.Id, u1.Id, true, true) 1354 assert.Nil(t, err) 1355 assert.Equal(t, int64(1), response.MsgCount) 1356 assert.Equal(t, int64(2), response.MentionCount) 1357 assert.Equal(t, int64(1), response.MentionCountRoot) 1358 1359 unread, err := th.App.GetChannelUnread(c2.Id, u1.Id) 1360 require.Nil(t, err) 1361 assert.Equal(t, int64(2), unread.MsgCount) 1362 assert.Equal(t, int64(2), unread.MentionCount) 1363 assert.Equal(t, int64(1), unread.MentionCountRoot) 1364 }) 1365 1366 t.Run("Unread on a DM channel", func(t *testing.T) { 1367 dc := th.CreateDmChannel(u2) 1368 1369 dm1 := th.CreatePost(dc) 1370 th.CreatePost(dc) 1371 th.CreatePost(dc) 1372 1373 _, err := th.App.CreatePost(th.Context, &model.Post{ChannelId: dc.Id, UserId: th.BasicUser.Id, Message: "testReply", RootId: dm1.Id}, dc, false, false) 1374 assert.Nil(t, err) 1375 1376 response, err := th.App.MarkChannelAsUnreadFromPost(dm1.Id, u2.Id, true, true) 1377 assert.Nil(t, err) 1378 assert.Equal(t, int64(0), response.MsgCount) 1379 assert.Equal(t, int64(4), response.MentionCount) 1380 assert.Equal(t, int64(3), response.MentionCountRoot) 1381 1382 unread, err := th.App.GetChannelUnread(dc.Id, u2.Id) 1383 require.Nil(t, err) 1384 assert.Equal(t, int64(4), unread.MsgCount) 1385 assert.Equal(t, int64(4), unread.MentionCount) 1386 assert.Equal(t, int64(3), unread.MentionCountRoot) 1387 }) 1388 1389 t.Run("Can't unread an imaginary post", func(t *testing.T) { 1390 response, err := th.App.MarkChannelAsUnreadFromPost("invalid4ofngungryquinj976y", u1.Id, true, true) 1391 assert.NotNil(t, err) 1392 assert.Nil(t, response) 1393 }) 1394} 1395 1396func TestAddUserToChannel(t *testing.T) { 1397 th := Setup(t).InitBasic() 1398 defer th.TearDown() 1399 1400 user1 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} 1401 ruser1, _ := th.App.CreateUser(th.Context, &user1) 1402 defer th.App.PermanentDeleteUser(th.Context, &user1) 1403 bot := th.CreateBot() 1404 botUser, _ := th.App.GetUser(bot.UserId) 1405 defer th.App.PermanentDeleteBot(botUser.Id) 1406 1407 th.App.AddTeamMember(th.Context, th.BasicTeam.Id, ruser1.Id) 1408 th.App.AddTeamMember(th.Context, th.BasicTeam.Id, bot.UserId) 1409 1410 group := th.CreateGroup() 1411 1412 _, err := th.App.UpsertGroupMember(group.Id, user1.Id) 1413 require.Nil(t, err) 1414 1415 gs, err := th.App.UpsertGroupSyncable(&model.GroupSyncable{ 1416 AutoAdd: true, 1417 SyncableId: th.BasicChannel.Id, 1418 Type: model.GroupSyncableTypeChannel, 1419 GroupId: group.Id, 1420 SchemeAdmin: false, 1421 }) 1422 require.Nil(t, err) 1423 1424 err = th.App.JoinChannel(th.Context, th.BasicChannel, ruser1.Id) 1425 require.Nil(t, err) 1426 1427 // verify user was added as a non-admin 1428 cm1, err := th.App.GetChannelMember(context.Background(), th.BasicChannel.Id, ruser1.Id) 1429 require.Nil(t, err) 1430 require.False(t, cm1.SchemeAdmin) 1431 1432 user2 := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} 1433 ruser2, _ := th.App.CreateUser(th.Context, &user2) 1434 defer th.App.PermanentDeleteUser(th.Context, &user2) 1435 th.App.AddTeamMember(th.Context, th.BasicTeam.Id, ruser2.Id) 1436 1437 _, err = th.App.UpsertGroupMember(group.Id, user2.Id) 1438 require.Nil(t, err) 1439 1440 gs.SchemeAdmin = true 1441 _, err = th.App.UpdateGroupSyncable(gs) 1442 require.Nil(t, err) 1443 1444 err = th.App.JoinChannel(th.Context, th.BasicChannel, ruser2.Id) 1445 require.Nil(t, err) 1446 1447 // Should allow a bot to be added to a public group synced channel 1448 _, err = th.App.AddUserToChannel(botUser, th.BasicChannel, false) 1449 require.Nil(t, err) 1450 1451 // verify user was added as an admin 1452 cm2, err := th.App.GetChannelMember(context.Background(), th.BasicChannel.Id, ruser2.Id) 1453 require.Nil(t, err) 1454 require.True(t, cm2.SchemeAdmin) 1455 1456 privateChannel := th.CreatePrivateChannel(th.BasicTeam) 1457 privateChannel.GroupConstrained = model.NewBool(true) 1458 _, err = th.App.UpdateChannel(privateChannel) 1459 require.Nil(t, err) 1460 1461 _, err = th.App.UpsertGroupSyncable(&model.GroupSyncable{ 1462 GroupId: group.Id, 1463 SyncableId: privateChannel.Id, 1464 Type: model.GroupSyncableTypeChannel, 1465 }) 1466 require.Nil(t, err) 1467 1468 // Should allow a group synced user to be added to a group synced private channel 1469 _, err = th.App.AddUserToChannel(ruser1, privateChannel, false) 1470 require.Nil(t, err) 1471 1472 // Should allow a bot to be added to a private group synced channel 1473 _, err = th.App.AddUserToChannel(botUser, privateChannel, false) 1474 require.Nil(t, err) 1475} 1476 1477func TestRemoveUserFromChannel(t *testing.T) { 1478 th := Setup(t).InitBasic() 1479 defer th.TearDown() 1480 1481 user := model.User{Email: strings.ToLower(model.NewId()) + "success+test@example.com", Nickname: "Darth Vader", Username: "vader" + model.NewId(), Password: "passwd1", AuthService: ""} 1482 ruser, _ := th.App.CreateUser(th.Context, &user) 1483 defer th.App.PermanentDeleteUser(th.Context, ruser) 1484 1485 bot := th.CreateBot() 1486 botUser, _ := th.App.GetUser(bot.UserId) 1487 defer th.App.PermanentDeleteBot(botUser.Id) 1488 1489 th.App.AddTeamMember(th.Context, th.BasicTeam.Id, ruser.Id) 1490 th.App.AddTeamMember(th.Context, th.BasicTeam.Id, bot.UserId) 1491 1492 privateChannel := th.CreatePrivateChannel(th.BasicTeam) 1493 1494 _, err := th.App.AddUserToChannel(ruser, privateChannel, false) 1495 require.Nil(t, err) 1496 _, err = th.App.AddUserToChannel(botUser, privateChannel, false) 1497 require.Nil(t, err) 1498 1499 group := th.CreateGroup() 1500 _, err = th.App.UpsertGroupMember(group.Id, ruser.Id) 1501 require.Nil(t, err) 1502 1503 _, err = th.App.UpsertGroupSyncable(&model.GroupSyncable{ 1504 GroupId: group.Id, 1505 SyncableId: privateChannel.Id, 1506 Type: model.GroupSyncableTypeChannel, 1507 }) 1508 require.Nil(t, err) 1509 1510 privateChannel.GroupConstrained = model.NewBool(true) 1511 _, err = th.App.UpdateChannel(privateChannel) 1512 require.Nil(t, err) 1513 1514 // Should not allow a group synced user to be removed from channel 1515 err = th.App.RemoveUserFromChannel(th.Context, ruser.Id, th.SystemAdminUser.Id, privateChannel) 1516 assert.Equal(t, err.Id, "api.channel.remove_members.denied") 1517 1518 // Should allow a user to remove themselves from group synced channel 1519 err = th.App.RemoveUserFromChannel(th.Context, ruser.Id, ruser.Id, privateChannel) 1520 require.Nil(t, err) 1521 1522 // Should allow a bot to be removed from a group synced channel 1523 err = th.App.RemoveUserFromChannel(th.Context, botUser.Id, th.SystemAdminUser.Id, privateChannel) 1524 require.Nil(t, err) 1525} 1526 1527func TestPatchChannelModerationsForChannel(t *testing.T) { 1528 th := Setup(t).InitBasic() 1529 defer th.TearDown() 1530 1531 th.App.SetPhase2PermissionsMigrationStatus(true) 1532 channel := th.BasicChannel 1533 1534 user := th.BasicUser 1535 th.AddUserToChannel(user, channel) 1536 1537 createPosts := model.ChannelModeratedPermissions[0] 1538 createReactions := model.ChannelModeratedPermissions[1] 1539 manageMembers := model.ChannelModeratedPermissions[2] 1540 channelMentions := model.ChannelModeratedPermissions[3] 1541 1542 nonChannelModeratedPermission := model.PermissionCreateBot.Id 1543 1544 testCases := []struct { 1545 Name string 1546 ChannelModerationsPatch []*model.ChannelModerationPatch 1547 PermissionsModeratedByPatch map[string]*model.ChannelModeratedRoles 1548 RevertChannelModerationsPatch []*model.ChannelModerationPatch 1549 HigherScopedMemberPermissions []string 1550 HigherScopedGuestPermissions []string 1551 ShouldError bool 1552 ShouldHaveNoChannelScheme bool 1553 }{ 1554 { 1555 Name: "Removing create posts from members role", 1556 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1557 { 1558 Name: &createPosts, 1559 Roles: &model.ChannelModeratedRolesPatch{Members: model.NewBool(false)}, 1560 }, 1561 }, 1562 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{ 1563 createPosts: { 1564 Members: &model.ChannelModeratedRole{Value: false, Enabled: true}, 1565 }, 1566 }, 1567 RevertChannelModerationsPatch: []*model.ChannelModerationPatch{ 1568 { 1569 Name: &createPosts, 1570 Roles: &model.ChannelModeratedRolesPatch{Members: model.NewBool(true)}, 1571 }, 1572 }, 1573 }, 1574 { 1575 Name: "Removing create reactions from members role", 1576 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1577 { 1578 Name: &createReactions, 1579 Roles: &model.ChannelModeratedRolesPatch{Members: model.NewBool(false)}, 1580 }, 1581 }, 1582 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{ 1583 createReactions: { 1584 Members: &model.ChannelModeratedRole{Value: false, Enabled: true}, 1585 }, 1586 }, 1587 RevertChannelModerationsPatch: []*model.ChannelModerationPatch{ 1588 { 1589 Name: &createReactions, 1590 Roles: &model.ChannelModeratedRolesPatch{Members: model.NewBool(true)}, 1591 }, 1592 }, 1593 }, 1594 { 1595 Name: "Removing channel mentions from members role", 1596 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1597 { 1598 Name: &channelMentions, 1599 Roles: &model.ChannelModeratedRolesPatch{Members: model.NewBool(false)}, 1600 }, 1601 }, 1602 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{ 1603 channelMentions: { 1604 Members: &model.ChannelModeratedRole{Value: false, Enabled: true}, 1605 }, 1606 }, 1607 RevertChannelModerationsPatch: []*model.ChannelModerationPatch{ 1608 { 1609 Name: &channelMentions, 1610 Roles: &model.ChannelModeratedRolesPatch{Members: model.NewBool(true)}, 1611 }, 1612 }, 1613 }, 1614 { 1615 Name: "Removing manage members from members role", 1616 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1617 { 1618 Name: &manageMembers, 1619 Roles: &model.ChannelModeratedRolesPatch{Members: model.NewBool(false)}, 1620 }, 1621 }, 1622 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{ 1623 manageMembers: { 1624 Members: &model.ChannelModeratedRole{Value: false, Enabled: true}, 1625 }, 1626 }, 1627 RevertChannelModerationsPatch: []*model.ChannelModerationPatch{ 1628 { 1629 Name: &manageMembers, 1630 Roles: &model.ChannelModeratedRolesPatch{Members: model.NewBool(true)}, 1631 }, 1632 }, 1633 }, 1634 { 1635 Name: "Removing create posts from guests role", 1636 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1637 { 1638 Name: &createPosts, 1639 Roles: &model.ChannelModeratedRolesPatch{Guests: model.NewBool(false)}, 1640 }, 1641 }, 1642 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{ 1643 createPosts: { 1644 Guests: &model.ChannelModeratedRole{Value: false, Enabled: true}, 1645 }, 1646 }, 1647 RevertChannelModerationsPatch: []*model.ChannelModerationPatch{ 1648 { 1649 Name: &createPosts, 1650 Roles: &model.ChannelModeratedRolesPatch{Guests: model.NewBool(true)}, 1651 }, 1652 }, 1653 }, 1654 { 1655 Name: "Removing create reactions from guests role", 1656 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1657 { 1658 Name: &createReactions, 1659 Roles: &model.ChannelModeratedRolesPatch{Guests: model.NewBool(false)}, 1660 }, 1661 }, 1662 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{ 1663 createReactions: { 1664 Guests: &model.ChannelModeratedRole{Value: false, Enabled: true}, 1665 }, 1666 }, 1667 RevertChannelModerationsPatch: []*model.ChannelModerationPatch{ 1668 { 1669 Name: &createReactions, 1670 Roles: &model.ChannelModeratedRolesPatch{Guests: model.NewBool(true)}, 1671 }, 1672 }, 1673 }, 1674 { 1675 Name: "Removing channel mentions from guests role", 1676 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1677 { 1678 Name: &channelMentions, 1679 Roles: &model.ChannelModeratedRolesPatch{Guests: model.NewBool(false)}, 1680 }, 1681 }, 1682 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{ 1683 channelMentions: { 1684 Guests: &model.ChannelModeratedRole{Value: false, Enabled: true}, 1685 }, 1686 }, 1687 RevertChannelModerationsPatch: []*model.ChannelModerationPatch{ 1688 { 1689 Name: &channelMentions, 1690 Roles: &model.ChannelModeratedRolesPatch{Guests: model.NewBool(true)}, 1691 }, 1692 }, 1693 }, 1694 { 1695 Name: "Removing manage members from guests role should not error", 1696 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1697 { 1698 Name: &manageMembers, 1699 Roles: &model.ChannelModeratedRolesPatch{Guests: model.NewBool(false)}, 1700 }, 1701 }, 1702 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{}, 1703 ShouldError: false, 1704 ShouldHaveNoChannelScheme: true, 1705 }, 1706 { 1707 Name: "Removing a permission that is not channel moderated should not error", 1708 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1709 { 1710 Name: &nonChannelModeratedPermission, 1711 Roles: &model.ChannelModeratedRolesPatch{ 1712 Members: model.NewBool(false), 1713 Guests: model.NewBool(false), 1714 }, 1715 }, 1716 }, 1717 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{}, 1718 ShouldError: false, 1719 ShouldHaveNoChannelScheme: true, 1720 }, 1721 { 1722 Name: "Error when adding a permission that is disabled in the parent member role", 1723 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1724 { 1725 Name: &createPosts, 1726 Roles: &model.ChannelModeratedRolesPatch{ 1727 Members: model.NewBool(true), 1728 Guests: model.NewBool(false), 1729 }, 1730 }, 1731 }, 1732 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{}, 1733 HigherScopedMemberPermissions: []string{}, 1734 ShouldError: true, 1735 }, 1736 { 1737 Name: "Error when adding a permission that is disabled in the parent guest role", 1738 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1739 { 1740 Name: &createPosts, 1741 Roles: &model.ChannelModeratedRolesPatch{ 1742 Members: model.NewBool(false), 1743 Guests: model.NewBool(true), 1744 }, 1745 }, 1746 }, 1747 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{}, 1748 HigherScopedGuestPermissions: []string{}, 1749 ShouldError: true, 1750 }, 1751 { 1752 Name: "Removing a permission from the member role that is disabled in the parent guest role", 1753 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1754 { 1755 Name: &createPosts, 1756 Roles: &model.ChannelModeratedRolesPatch{ 1757 Members: model.NewBool(false), 1758 }, 1759 }, 1760 }, 1761 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{ 1762 createPosts: { 1763 Members: &model.ChannelModeratedRole{Value: false, Enabled: true}, 1764 Guests: &model.ChannelModeratedRole{Value: false, Enabled: false}, 1765 }, 1766 createReactions: { 1767 Guests: &model.ChannelModeratedRole{Value: false, Enabled: false}, 1768 }, 1769 channelMentions: { 1770 Guests: &model.ChannelModeratedRole{Value: false, Enabled: false}, 1771 }, 1772 }, 1773 HigherScopedGuestPermissions: []string{}, 1774 ShouldError: false, 1775 }, 1776 { 1777 Name: "Channel should have no scheme when all moderated permissions are equivalent to higher scoped role", 1778 ChannelModerationsPatch: []*model.ChannelModerationPatch{ 1779 { 1780 Name: &createPosts, 1781 Roles: &model.ChannelModeratedRolesPatch{ 1782 Members: model.NewBool(true), 1783 Guests: model.NewBool(true), 1784 }, 1785 }, 1786 { 1787 Name: &createReactions, 1788 Roles: &model.ChannelModeratedRolesPatch{ 1789 Members: model.NewBool(true), 1790 Guests: model.NewBool(true), 1791 }, 1792 }, 1793 { 1794 Name: &channelMentions, 1795 Roles: &model.ChannelModeratedRolesPatch{ 1796 Members: model.NewBool(true), 1797 Guests: model.NewBool(true), 1798 }, 1799 }, 1800 { 1801 Name: &manageMembers, 1802 Roles: &model.ChannelModeratedRolesPatch{ 1803 Members: model.NewBool(true), 1804 }, 1805 }, 1806 }, 1807 PermissionsModeratedByPatch: map[string]*model.ChannelModeratedRoles{}, 1808 ShouldHaveNoChannelScheme: true, 1809 }, 1810 } 1811 1812 for _, tc := range testCases { 1813 t.Run(tc.Name, func(t *testing.T) { 1814 higherScopedPermissionsOverriden := tc.HigherScopedMemberPermissions != nil || tc.HigherScopedGuestPermissions != nil 1815 // If the test case restricts higher scoped permissions. 1816 if higherScopedPermissionsOverriden { 1817 higherScopedGuestRoleName, higherScopedMemberRoleName, _, _ := th.App.GetTeamSchemeChannelRoles(channel.TeamId) 1818 if tc.HigherScopedMemberPermissions != nil { 1819 higherScopedMemberRole, err := th.App.GetRoleByName(context.Background(), higherScopedMemberRoleName) 1820 require.Nil(t, err) 1821 originalPermissions := higherScopedMemberRole.Permissions 1822 1823 th.App.PatchRole(higherScopedMemberRole, &model.RolePatch{Permissions: &tc.HigherScopedMemberPermissions}) 1824 defer th.App.PatchRole(higherScopedMemberRole, &model.RolePatch{Permissions: &originalPermissions}) 1825 } 1826 1827 if tc.HigherScopedGuestPermissions != nil { 1828 higherScopedGuestRole, err := th.App.GetRoleByName(context.Background(), higherScopedGuestRoleName) 1829 require.Nil(t, err) 1830 originalPermissions := higherScopedGuestRole.Permissions 1831 1832 th.App.PatchRole(higherScopedGuestRole, &model.RolePatch{Permissions: &tc.HigherScopedGuestPermissions}) 1833 defer th.App.PatchRole(higherScopedGuestRole, &model.RolePatch{Permissions: &originalPermissions}) 1834 } 1835 } 1836 1837 moderations, appErr := th.App.PatchChannelModerationsForChannel(channel, tc.ChannelModerationsPatch) 1838 if tc.ShouldError { 1839 require.NotNil(t, appErr) 1840 return 1841 } 1842 require.Nil(t, appErr) 1843 1844 updatedChannel, _ := th.App.GetChannel(channel.Id) 1845 if tc.ShouldHaveNoChannelScheme { 1846 require.Nil(t, updatedChannel.SchemeId) 1847 } else { 1848 require.NotNil(t, updatedChannel.SchemeId) 1849 } 1850 1851 for _, moderation := range moderations { 1852 // If the permission is not found in the expected modified permissions table then require it to be true 1853 if permission, found := tc.PermissionsModeratedByPatch[moderation.Name]; found && permission.Members != nil { 1854 require.Equal(t, moderation.Roles.Members.Value, permission.Members.Value) 1855 require.Equal(t, moderation.Roles.Members.Enabled, permission.Members.Enabled) 1856 } else { 1857 require.Equal(t, moderation.Roles.Members.Value, true) 1858 require.Equal(t, moderation.Roles.Members.Enabled, true) 1859 } 1860 1861 if permission, found := tc.PermissionsModeratedByPatch[moderation.Name]; found && permission.Guests != nil { 1862 require.Equal(t, moderation.Roles.Guests.Value, permission.Guests.Value) 1863 require.Equal(t, moderation.Roles.Guests.Enabled, permission.Guests.Enabled) 1864 } else if moderation.Name == manageMembers { 1865 require.Empty(t, moderation.Roles.Guests) 1866 } else { 1867 require.Equal(t, moderation.Roles.Guests.Value, true) 1868 require.Equal(t, moderation.Roles.Guests.Enabled, true) 1869 } 1870 } 1871 1872 if tc.RevertChannelModerationsPatch != nil { 1873 th.App.PatchChannelModerationsForChannel(channel, tc.RevertChannelModerationsPatch) 1874 } 1875 }) 1876 } 1877 1878 t.Run("Handles concurrent patch requests gracefully", func(t *testing.T) { 1879 addCreatePosts := []*model.ChannelModerationPatch{ 1880 { 1881 Name: &createPosts, 1882 Roles: &model.ChannelModeratedRolesPatch{ 1883 Members: model.NewBool(false), 1884 Guests: model.NewBool(false), 1885 }, 1886 }, 1887 } 1888 removeCreatePosts := []*model.ChannelModerationPatch{ 1889 { 1890 Name: &createPosts, 1891 Roles: &model.ChannelModeratedRolesPatch{ 1892 Members: model.NewBool(false), 1893 Guests: model.NewBool(false), 1894 }, 1895 }, 1896 } 1897 1898 wg := sync.WaitGroup{} 1899 wg.Add(20) 1900 for i := 0; i < 10; i++ { 1901 go func() { 1902 th.App.PatchChannelModerationsForChannel(channel.DeepCopy(), addCreatePosts) 1903 th.App.PatchChannelModerationsForChannel(channel.DeepCopy(), removeCreatePosts) 1904 wg.Done() 1905 }() 1906 } 1907 for i := 0; i < 10; i++ { 1908 go func() { 1909 th.App.PatchChannelModerationsForChannel(channel.DeepCopy(), addCreatePosts) 1910 th.App.PatchChannelModerationsForChannel(channel.DeepCopy(), removeCreatePosts) 1911 wg.Done() 1912 }() 1913 } 1914 wg.Wait() 1915 1916 higherScopedGuestRoleName, higherScopedMemberRoleName, _, _ := th.App.GetTeamSchemeChannelRoles(channel.TeamId) 1917 higherScopedMemberRole, _ := th.App.GetRoleByName(context.Background(), higherScopedMemberRoleName) 1918 higherScopedGuestRole, _ := th.App.GetRoleByName(context.Background(), higherScopedGuestRoleName) 1919 assert.Contains(t, higherScopedMemberRole.Permissions, createPosts) 1920 assert.Contains(t, higherScopedGuestRole.Permissions, createPosts) 1921 }) 1922 1923 t.Run("Updates the authorization to create post", func(t *testing.T) { 1924 addCreatePosts := []*model.ChannelModerationPatch{ 1925 { 1926 Name: &createPosts, 1927 Roles: &model.ChannelModeratedRolesPatch{ 1928 Members: model.NewBool(true), 1929 }, 1930 }, 1931 } 1932 removeCreatePosts := []*model.ChannelModerationPatch{ 1933 { 1934 Name: &createPosts, 1935 Roles: &model.ChannelModeratedRolesPatch{ 1936 Members: model.NewBool(false), 1937 }, 1938 }, 1939 } 1940 1941 mockSession := model.Session{UserId: user.Id} 1942 1943 _, err := th.App.PatchChannelModerationsForChannel(channel.DeepCopy(), addCreatePosts) 1944 require.Nil(t, err) 1945 require.True(t, th.App.SessionHasPermissionToChannel(mockSession, channel.Id, model.PermissionCreatePost)) 1946 1947 _, err = th.App.PatchChannelModerationsForChannel(channel.DeepCopy(), removeCreatePosts) 1948 require.Nil(t, err) 1949 require.False(t, th.App.SessionHasPermissionToChannel(mockSession, channel.Id, model.PermissionCreatePost)) 1950 }) 1951} 1952 1953// TestMarkChannelsAsViewedPanic verifies that returning an error from a.GetUser 1954// does not cause a panic. 1955func TestMarkChannelsAsViewedPanic(t *testing.T) { 1956 th := SetupWithStoreMock(t) 1957 defer th.TearDown() 1958 1959 mockStore := th.App.Srv().Store.(*mocks.Store) 1960 mockUserStore := mocks.UserStore{} 1961 mockUserStore.On("Get", context.Background(), "userID").Return(nil, model.NewAppError("SqlUserStore.Get", "app.user.get.app_error", nil, "user_id=userID", http.StatusInternalServerError)) 1962 mockChannelStore := mocks.ChannelStore{} 1963 mockChannelStore.On("Get", "channelID", true).Return(&model.Channel{}, nil) 1964 mockChannelStore.On("GetMember", context.Background(), "channelID", "userID").Return(&model.ChannelMember{ 1965 NotifyProps: model.StringMap{ 1966 model.PushNotifyProp: model.ChannelNotifyDefault, 1967 }}, nil) 1968 times := map[string]int64{ 1969 "userID": 1, 1970 } 1971 mockChannelStore.On("UpdateLastViewedAt", []string{"channelID"}, "userID", false).Return(times, nil) 1972 mockSessionStore := mocks.SessionStore{} 1973 mockOAuthStore := mocks.OAuthStore{} 1974 var err error 1975 th.App.srv.userService, err = users.New(users.ServiceConfig{ 1976 UserStore: &mockUserStore, 1977 SessionStore: &mockSessionStore, 1978 OAuthStore: &mockOAuthStore, 1979 ConfigFn: th.App.srv.Config, 1980 LicenseFn: th.App.srv.License, 1981 }) 1982 require.NoError(t, err) 1983 mockPreferenceStore := mocks.PreferenceStore{} 1984 mockPreferenceStore.On("Get", mock.AnythingOfType("string"), mock.AnythingOfType("string"), mock.AnythingOfType("string")).Return(&model.Preference{Value: "test"}, nil) 1985 mockThreadStore := mocks.ThreadStore{} 1986 mockThreadStore.On("MarkAllAsReadInChannels", "userID", []string{"channelID"}).Return(nil) 1987 mockStore.On("Channel").Return(&mockChannelStore) 1988 mockStore.On("Preference").Return(&mockPreferenceStore) 1989 mockStore.On("Thread").Return(&mockThreadStore) 1990 1991 _, appErr := th.App.MarkChannelsAsViewed([]string{"channelID"}, "userID", th.Context.Session().Id, false) 1992 require.Nil(t, appErr) 1993} 1994 1995func TestClearChannelMembersCache(t *testing.T) { 1996 th := SetupWithStoreMock(t) 1997 defer th.TearDown() 1998 1999 mockStore := th.App.Srv().Store.(*mocks.Store) 2000 mockChannelStore := mocks.ChannelStore{} 2001 cms := model.ChannelMembers{} 2002 for i := 0; i < 200; i++ { 2003 cms = append(cms, model.ChannelMember{ 2004 ChannelId: "1", 2005 }) 2006 } 2007 mockChannelStore.On("GetMembers", "channelID", 0, 100).Return(cms, nil) 2008 mockChannelStore.On("GetMembers", "channelID", 100, 100).Return(model.ChannelMembers{ 2009 model.ChannelMember{ 2010 ChannelId: "1", 2011 }}, nil) 2012 mockStore.On("Channel").Return(&mockChannelStore) 2013 2014 th.App.ClearChannelMembersCache("channelID") 2015} 2016 2017func TestGetMemberCountsByGroup(t *testing.T) { 2018 th := SetupWithStoreMock(t) 2019 defer th.TearDown() 2020 2021 mockStore := th.App.Srv().Store.(*mocks.Store) 2022 mockChannelStore := mocks.ChannelStore{} 2023 cmc := []*model.ChannelMemberCountByGroup{} 2024 for i := 0; i < 5; i++ { 2025 cmc = append(cmc, &model.ChannelMemberCountByGroup{ 2026 GroupId: model.NewId(), 2027 ChannelMemberCount: int64(i), 2028 ChannelMemberTimezonesCount: int64(i), 2029 }) 2030 } 2031 mockChannelStore.On("GetMemberCountsByGroup", context.Background(), "channelID", true).Return(cmc, nil) 2032 mockStore.On("Channel").Return(&mockChannelStore) 2033 resp, err := th.App.GetMemberCountsByGroup(context.Background(), "channelID", true) 2034 require.Nil(t, err) 2035 require.ElementsMatch(t, cmc, resp) 2036} 2037 2038func TestViewChannelCollapsedThreadsTurnedOff(t *testing.T) { 2039 th := Setup(t).InitBasic() 2040 defer th.TearDown() 2041 2042 u1 := th.BasicUser 2043 u2 := th.BasicUser2 2044 c1 := th.BasicChannel 2045 th.AddUserToChannel(u2, c1) 2046 2047 // Enable CRT 2048 os.Setenv("MM_FEATUREFLAGS_COLLAPSEDTHREADS", "true") 2049 defer os.Unsetenv("MM_FEATUREFLAGS_COLLAPSEDTHREADS") 2050 th.App.UpdateConfig(func(cfg *model.Config) { 2051 *cfg.ServiceSettings.ThreadAutoFollow = true 2052 *cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn 2053 }) 2054 2055 // Turn off CRT for user 2056 preference := model.Preference{ 2057 UserId: u1.Id, 2058 Category: model.PreferenceCategoryDisplaySettings, 2059 Name: model.PreferenceNameCollapsedThreadsEnabled, 2060 Value: "off", 2061 } 2062 var preferences model.Preferences 2063 preferences = append(preferences, preference) 2064 err := th.App.Srv().Store.Preference().Save(preferences) 2065 require.NoError(t, err) 2066 2067 // mention the user in a root post 2068 post1 := &model.Post{ 2069 ChannelId: c1.Id, 2070 Message: "root post @" + u1.Username, 2071 UserId: u2.Id, 2072 } 2073 rpost1, appErr := th.App.CreatePost(th.Context, post1, c1, false, true) 2074 require.Nil(t, appErr) 2075 2076 // mention the user in a reply post 2077 post2 := &model.Post{ 2078 ChannelId: c1.Id, 2079 Message: "reply post @" + u1.Username, 2080 UserId: u2.Id, 2081 RootId: rpost1.Id, 2082 } 2083 _, appErr = th.App.CreatePost(th.Context, post2, c1, false, true) 2084 require.Nil(t, appErr) 2085 2086 // Check we have unread mention in the thread 2087 threads, appErr := th.App.GetThreadsForUser(u1.Id, c1.TeamId, model.GetUserThreadsOpts{}) 2088 require.Nil(t, appErr) 2089 found := false 2090 for _, thread := range threads.Threads { 2091 if thread.PostId == rpost1.Id { 2092 require.EqualValues(t, int64(1), thread.UnreadMentions) 2093 found = true 2094 break 2095 } 2096 } 2097 require.Truef(t, found, "did not find created thread in user's threads") 2098 2099 // Mark channel as read from a client that supports CRT 2100 _, appErr = th.App.MarkChannelsAsViewed([]string{c1.Id}, u1.Id, th.Context.Session().Id, true) 2101 require.Nil(t, appErr) 2102 2103 // Thread should be marked as read because CRT has been turned off by user 2104 threads, appErr = th.App.GetThreadsForUser(u1.Id, c1.TeamId, model.GetUserThreadsOpts{}) 2105 require.Nil(t, appErr) 2106 found = false 2107 for _, thread := range threads.Threads { 2108 if thread.PostId == rpost1.Id { 2109 require.Zero(t, thread.UnreadMentions) 2110 found = true 2111 break 2112 } 2113 } 2114 require.Truef(t, found, "did not find created thread in user's threads") 2115} 2116 2117func TestMarkChannelAsUnreadFromPostCollapsedThreadsTurnedOff(t *testing.T) { 2118 // Enable CRT 2119 os.Setenv("MM_FEATUREFLAGS_COLLAPSEDTHREADS", "true") 2120 defer os.Unsetenv("MM_FEATUREFLAGS_COLLAPSEDTHREADS") 2121 2122 th := Setup(t).InitBasic() 2123 defer th.TearDown() 2124 th.App.UpdateConfig(func(cfg *model.Config) { 2125 *cfg.ServiceSettings.ThreadAutoFollow = true 2126 *cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn 2127 }) 2128 2129 th.AddUserToChannel(th.BasicUser2, th.BasicChannel) 2130 2131 // Turn off CRT for user 2132 preference := model.Preference{ 2133 UserId: th.BasicUser.Id, 2134 Category: model.PreferenceCategoryDisplaySettings, 2135 Name: model.PreferenceNameCollapsedThreadsEnabled, 2136 Value: "off", 2137 } 2138 var preferences model.Preferences 2139 preferences = append(preferences, preference) 2140 err := th.App.Srv().Store.Preference().Save(preferences) 2141 require.NoError(t, err) 2142 2143 // user2: first root mention @user1 2144 // - user1: hello 2145 // - user2: mention @u1 2146 // - user1: another repoy 2147 // - user2: another mention @u1 2148 // user1: a root post 2149 // user2: Another root mention @u1 2150 user1Mention := " @" + th.BasicUser.Username 2151 rootPost1, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "first root mention" + user1Mention}, th.BasicChannel, false, false) 2152 require.Nil(t, appErr) 2153 _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hello"}, th.BasicChannel, false, false) 2154 require.Nil(t, appErr) 2155 replyPost1, appErr := th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "mention" + user1Mention}, th.BasicChannel, false, false) 2156 require.Nil(t, appErr) 2157 _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "another reply"}, th.BasicChannel, false, false) 2158 require.Nil(t, appErr) 2159 _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost1.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "another mention" + user1Mention}, th.BasicChannel, false, false) 2160 require.Nil(t, appErr) 2161 _, appErr = th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "a root post"}, th.BasicChannel, false, false) 2162 require.Nil(t, appErr) 2163 _, appErr = th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "another root mention" + user1Mention}, th.BasicChannel, false, false) 2164 require.Nil(t, appErr) 2165 2166 t.Run("Mark reply post as unread", func(t *testing.T) { 2167 _, err := th.App.MarkChannelAsUnreadFromPost(replyPost1.Id, th.BasicUser.Id, true, true) 2168 require.Nil(t, err) 2169 // Get channel unreads 2170 // Easier to reason with ChannelUnread now, than channelUnreadAt from the previous call 2171 channelUnread, err := th.App.GetChannelUnread(th.BasicChannel.Id, th.BasicUser.Id) 2172 require.Nil(t, err) 2173 2174 require.Equal(t, int64(3), channelUnread.MentionCount) 2175 // MentionCountRoot should be zero for a user that has CRT turned off 2176 require.Equal(t, int64(0), channelUnread.MentionCountRoot) 2177 2178 require.Equal(t, int64(5), channelUnread.MsgCount) 2179 // MentionCountRoot should be zero for a user that has CRT turned off 2180 require.Equal(t, channelUnread.MsgCountRoot, int64(0)) 2181 2182 threadMembership, err := th.App.GetThreadMembershipForUser(th.BasicUser.Id, rootPost1.Id) 2183 require.Nil(t, err) 2184 thread, err := th.App.GetThreadForUser(th.BasicTeam.Id, threadMembership, false) 2185 require.Nil(t, err) 2186 require.Equal(t, int64(2), thread.UnreadMentions) 2187 require.Equal(t, int64(3), thread.UnreadReplies) 2188 }) 2189 2190 t.Run("Mark root post as unread", func(t *testing.T) { 2191 _, err := th.App.MarkChannelAsUnreadFromPost(rootPost1.Id, th.BasicUser.Id, true, true) 2192 require.Nil(t, err) 2193 // Get channel unreads 2194 // Easier to reason with ChannelUnread now, than channelUnreadAt from the previous call 2195 channelUnread, err := th.App.GetChannelUnread(th.BasicChannel.Id, th.BasicUser.Id) 2196 require.Nil(t, err) 2197 2198 require.Equal(t, int64(4), channelUnread.MentionCount) 2199 require.Equal(t, int64(2), channelUnread.MentionCountRoot) 2200 2201 require.Equal(t, int64(7), channelUnread.MsgCount) 2202 require.Equal(t, int64(3), channelUnread.MsgCountRoot) 2203 }) 2204} 2205 2206func TestMarkUnreadWithThreads(t *testing.T) { 2207 os.Setenv("MM_FEATUREFLAGS_COLLAPSEDTHREADS", "true") 2208 defer os.Unsetenv("MM_FEATUREFLAGS_COLLAPSEDTHREADS") 2209 th := Setup(t).InitBasic() 2210 defer th.TearDown() 2211 th.App.UpdateConfig(func(cfg *model.Config) { 2212 *cfg.ServiceSettings.ThreadAutoFollow = true 2213 *cfg.ServiceSettings.CollapsedThreads = model.CollapsedThreadsDefaultOn 2214 }) 2215 2216 t.Run("Follow threads only if specified", func(t *testing.T) { 2217 rootPost, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, false, false) 2218 require.Nil(t, appErr) 2219 replyPost, appErr := th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, false, false) 2220 require.Nil(t, appErr) 2221 threads, appErr := th.App.GetThreadsForUser(th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{}) 2222 require.Nil(t, appErr) 2223 require.Zero(t, threads.Total) 2224 2225 _, appErr = th.App.MarkChannelAsUnreadFromPost(replyPost.Id, th.BasicUser.Id, true, true) 2226 require.Nil(t, appErr) 2227 2228 threads, appErr = th.App.GetThreadsForUser(th.BasicUser.Id, th.BasicTeam.Id, model.GetUserThreadsOpts{}) 2229 require.Nil(t, appErr) 2230 require.NotZero(t, threads.Total) 2231 2232 threadMembership, appErr := th.App.GetThreadMembershipForUser(th.BasicUser.Id, replyPost.RootId) 2233 require.Nil(t, appErr) 2234 require.NotNil(t, threadMembership) 2235 assert.True(t, threadMembership.Following) 2236 2237 // Create a new thread 2238 rootPost, appErr = th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi2"}, th.BasicChannel, false, false) 2239 require.Nil(t, appErr) 2240 replyPost, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi2"}, th.BasicChannel, false, false) 2241 require.Nil(t, appErr) 2242 2243 _, appErr = th.App.MarkChannelAsUnreadFromPost(replyPost.Id, th.BasicUser.Id, true, false) 2244 require.Nil(t, appErr) 2245 2246 threadMembership, appErr = th.App.GetThreadMembershipForUser(th.BasicUser.Id, replyPost.RootId) 2247 require.Nil(t, appErr) 2248 require.NotNil(t, threadMembership) 2249 assert.False(t, threadMembership.Following) 2250 }) 2251 2252 t.Run("Set unread mentions correctly", func(t *testing.T) { 2253 t.Run("Never followed root post with no replies or mentions", func(t *testing.T) { 2254 rootPost, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, false, false) 2255 require.Nil(t, appErr) 2256 _, appErr = th.App.MarkChannelAsUnreadFromPost(rootPost.Id, th.BasicUser.Id, true, true) 2257 require.Nil(t, appErr) 2258 2259 threadMembership, appErr := th.App.GetThreadMembershipForUser(th.BasicUser.Id, rootPost.Id) 2260 require.Nil(t, appErr) 2261 require.NotNil(t, threadMembership) 2262 assert.Zero(t, threadMembership.UnreadMentions) 2263 }) 2264 2265 t.Run("Never followed root post with replies and no mentions", func(t *testing.T) { 2266 rootPost, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, false, false) 2267 require.Nil(t, appErr) 2268 _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, false, false) 2269 require.Nil(t, appErr) 2270 _, appErr = th.App.MarkChannelAsUnreadFromPost(rootPost.Id, th.BasicUser.Id, true, true) 2271 require.Nil(t, appErr) 2272 2273 threadMembership, appErr := th.App.GetThreadMembershipForUser(th.BasicUser.Id, rootPost.Id) 2274 require.Nil(t, appErr) 2275 require.NotNil(t, threadMembership) 2276 assert.Zero(t, threadMembership.UnreadMentions) 2277 }) 2278 2279 t.Run("Never followed root post with replies and mentions", func(t *testing.T) { 2280 rootPost, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, false, false) 2281 require.Nil(t, appErr) 2282 _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi @" + th.BasicUser.Username}, th.BasicChannel, false, false) 2283 require.Nil(t, appErr) 2284 _, appErr = th.App.MarkChannelAsUnreadFromPost(rootPost.Id, th.BasicUser.Id, true, true) 2285 require.Nil(t, appErr) 2286 2287 threadMembership, appErr := th.App.GetThreadMembershipForUser(th.BasicUser.Id, rootPost.Id) 2288 require.Nil(t, appErr) 2289 require.NotNil(t, threadMembership) 2290 assert.Equal(t, int64(1), threadMembership.UnreadMentions) 2291 }) 2292 2293 t.Run("Previously followed root post with no replies or mentions", func(t *testing.T) { 2294 rootPost, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, false, false) 2295 require.Nil(t, appErr) 2296 appErr = th.App.UpdateThreadFollowForUser(th.BasicUser.Id, th.BasicTeam.Id, rootPost.Id, true) 2297 require.Nil(t, appErr) 2298 appErr = th.App.UpdateThreadFollowForUser(th.BasicUser.Id, th.BasicTeam.Id, rootPost.Id, false) 2299 require.Nil(t, appErr) 2300 2301 _, appErr = th.App.MarkChannelAsUnreadFromPost(rootPost.Id, th.BasicUser.Id, true, true) 2302 require.Nil(t, appErr) 2303 2304 threadMembership, appErr := th.App.GetThreadMembershipForUser(th.BasicUser.Id, rootPost.Id) 2305 require.Nil(t, appErr) 2306 require.NotNil(t, threadMembership) 2307 assert.Zero(t, threadMembership.UnreadMentions) 2308 }) 2309 2310 t.Run("Previously followed root post with replies and no mentions", func(t *testing.T) { 2311 rootPost, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, false, false) 2312 require.Nil(t, appErr) 2313 _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, false, false) 2314 require.Nil(t, appErr) 2315 appErr = th.App.UpdateThreadFollowForUser(th.BasicUser.Id, th.BasicTeam.Id, rootPost.Id, true) 2316 require.Nil(t, appErr) 2317 appErr = th.App.UpdateThreadFollowForUser(th.BasicUser.Id, th.BasicTeam.Id, rootPost.Id, false) 2318 require.Nil(t, appErr) 2319 2320 _, appErr = th.App.MarkChannelAsUnreadFromPost(rootPost.Id, th.BasicUser.Id, true, true) 2321 require.Nil(t, appErr) 2322 2323 threadMembership, appErr := th.App.GetThreadMembershipForUser(th.BasicUser.Id, rootPost.Id) 2324 require.Nil(t, appErr) 2325 require.NotNil(t, threadMembership) 2326 assert.Zero(t, threadMembership.UnreadMentions) 2327 }) 2328 2329 t.Run("Previously followed root post with replies and mentions", func(t *testing.T) { 2330 rootPost, appErr := th.App.CreatePost(th.Context, &model.Post{UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi"}, th.BasicChannel, false, false) 2331 require.Nil(t, appErr) 2332 _, appErr = th.App.CreatePost(th.Context, &model.Post{RootId: rootPost.Id, UserId: th.BasicUser2.Id, CreateAt: model.GetMillis(), ChannelId: th.BasicChannel.Id, Message: "hi @" + th.BasicUser.Username}, th.BasicChannel, false, false) 2333 require.Nil(t, appErr) 2334 appErr = th.App.UpdateThreadFollowForUser(th.BasicUser.Id, th.BasicTeam.Id, rootPost.Id, true) 2335 require.Nil(t, appErr) 2336 appErr = th.App.UpdateThreadFollowForUser(th.BasicUser.Id, th.BasicTeam.Id, rootPost.Id, false) 2337 require.Nil(t, appErr) 2338 2339 _, appErr = th.App.MarkChannelAsUnreadFromPost(rootPost.Id, th.BasicUser.Id, true, true) 2340 require.Nil(t, appErr) 2341 2342 threadMembership, appErr := th.App.GetThreadMembershipForUser(th.BasicUser.Id, rootPost.Id) 2343 require.Nil(t, appErr) 2344 require.NotNil(t, threadMembership) 2345 assert.Equal(t, int64(1), threadMembership.UnreadMentions) 2346 }) 2347 }) 2348} 2349