github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/store/sqlstore/channel_store.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package sqlstore 5 6 import ( 7 "database/sql" 8 "fmt" 9 "sort" 10 "strconv" 11 "strings" 12 "time" 13 14 sq "github.com/Masterminds/squirrel" 15 "github.com/mattermost/gorp" 16 "github.com/pkg/errors" 17 18 "github.com/mattermost/mattermost-server/v5/einterfaces" 19 "github.com/mattermost/mattermost-server/v5/mlog" 20 "github.com/mattermost/mattermost-server/v5/model" 21 "github.com/mattermost/mattermost-server/v5/services/cache" 22 "github.com/mattermost/mattermost-server/v5/store" 23 ) 24 25 const ( 26 AllChannelMembersForUserCacheSize = model.SESSION_CACHE_SIZE 27 AllChannelMembersForUserCacheDuration = 15 * time.Minute // 15 mins 28 29 AllChannelMembersNotifyPropsForChannelCacheSize = model.SESSION_CACHE_SIZE 30 AllChannelMembersNotifyPropsForChannelCacheDuration = 30 * time.Minute // 30 mins 31 32 ChannelCacheDuration = 15 * time.Minute // 15 mins 33 ) 34 35 type SqlChannelStore struct { 36 *SqlStore 37 metrics einterfaces.MetricsInterface 38 } 39 40 type channelMember struct { 41 ChannelId string 42 UserId string 43 Roles string 44 LastViewedAt int64 45 MsgCount int64 46 MentionCount int64 47 NotifyProps model.StringMap 48 LastUpdateAt int64 49 SchemeUser sql.NullBool 50 SchemeAdmin sql.NullBool 51 SchemeGuest sql.NullBool 52 } 53 54 func NewChannelMemberFromModel(cm *model.ChannelMember) *channelMember { 55 return &channelMember{ 56 ChannelId: cm.ChannelId, 57 UserId: cm.UserId, 58 Roles: cm.ExplicitRoles, 59 LastViewedAt: cm.LastViewedAt, 60 MsgCount: cm.MsgCount, 61 MentionCount: cm.MentionCount, 62 NotifyProps: cm.NotifyProps, 63 LastUpdateAt: cm.LastUpdateAt, 64 SchemeGuest: sql.NullBool{Valid: true, Bool: cm.SchemeGuest}, 65 SchemeUser: sql.NullBool{Valid: true, Bool: cm.SchemeUser}, 66 SchemeAdmin: sql.NullBool{Valid: true, Bool: cm.SchemeAdmin}, 67 } 68 } 69 70 type channelMemberWithSchemeRoles struct { 71 ChannelId string 72 UserId string 73 Roles string 74 LastViewedAt int64 75 MsgCount int64 76 MentionCount int64 77 NotifyProps model.StringMap 78 LastUpdateAt int64 79 SchemeGuest sql.NullBool 80 SchemeUser sql.NullBool 81 SchemeAdmin sql.NullBool 82 TeamSchemeDefaultGuestRole sql.NullString 83 TeamSchemeDefaultUserRole sql.NullString 84 TeamSchemeDefaultAdminRole sql.NullString 85 ChannelSchemeDefaultGuestRole sql.NullString 86 ChannelSchemeDefaultUserRole sql.NullString 87 ChannelSchemeDefaultAdminRole sql.NullString 88 } 89 90 func channelMemberSliceColumns() []string { 91 return []string{"ChannelId", "UserId", "Roles", "LastViewedAt", "MsgCount", "MentionCount", "NotifyProps", "LastUpdateAt", "SchemeUser", "SchemeAdmin", "SchemeGuest"} 92 } 93 94 func channelMemberToSlice(member *model.ChannelMember) []interface{} { 95 resultSlice := []interface{}{} 96 resultSlice = append(resultSlice, member.ChannelId) 97 resultSlice = append(resultSlice, member.UserId) 98 resultSlice = append(resultSlice, member.ExplicitRoles) 99 resultSlice = append(resultSlice, member.LastViewedAt) 100 resultSlice = append(resultSlice, member.MsgCount) 101 resultSlice = append(resultSlice, member.MentionCount) 102 resultSlice = append(resultSlice, model.MapToJson(member.NotifyProps)) 103 resultSlice = append(resultSlice, member.LastUpdateAt) 104 resultSlice = append(resultSlice, member.SchemeUser) 105 resultSlice = append(resultSlice, member.SchemeAdmin) 106 resultSlice = append(resultSlice, member.SchemeGuest) 107 return resultSlice 108 } 109 110 type channelMemberWithSchemeRolesList []channelMemberWithSchemeRoles 111 112 func getChannelRoles(schemeGuest, schemeUser, schemeAdmin bool, defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole, defaultChannelGuestRole, defaultChannelUserRole, defaultChannelAdminRole string, 113 roles []string) rolesInfo { 114 result := rolesInfo{ 115 roles: []string{}, 116 explicitRoles: []string{}, 117 schemeGuest: schemeGuest, 118 schemeUser: schemeUser, 119 schemeAdmin: schemeAdmin, 120 } 121 122 // Identify any scheme derived roles that are in "Roles" field due to not yet being migrated, and exclude 123 // them from ExplicitRoles field. 124 for _, role := range roles { 125 switch role { 126 case model.CHANNEL_GUEST_ROLE_ID: 127 result.schemeGuest = true 128 case model.CHANNEL_USER_ROLE_ID: 129 result.schemeUser = true 130 case model.CHANNEL_ADMIN_ROLE_ID: 131 result.schemeAdmin = true 132 default: 133 result.explicitRoles = append(result.explicitRoles, role) 134 result.roles = append(result.roles, role) 135 } 136 } 137 138 // Add any scheme derived roles that are not in the Roles field due to being Implicit from the Scheme, and add 139 // them to the Roles field for backwards compatibility reasons. 140 var schemeImpliedRoles []string 141 if result.schemeGuest { 142 if defaultChannelGuestRole != "" { 143 schemeImpliedRoles = append(schemeImpliedRoles, defaultChannelGuestRole) 144 } else if defaultTeamGuestRole != "" { 145 schemeImpliedRoles = append(schemeImpliedRoles, defaultTeamGuestRole) 146 } else { 147 schemeImpliedRoles = append(schemeImpliedRoles, model.CHANNEL_GUEST_ROLE_ID) 148 } 149 } 150 if result.schemeUser { 151 if defaultChannelUserRole != "" { 152 schemeImpliedRoles = append(schemeImpliedRoles, defaultChannelUserRole) 153 } else if defaultTeamUserRole != "" { 154 schemeImpliedRoles = append(schemeImpliedRoles, defaultTeamUserRole) 155 } else { 156 schemeImpliedRoles = append(schemeImpliedRoles, model.CHANNEL_USER_ROLE_ID) 157 } 158 } 159 if result.schemeAdmin { 160 if defaultChannelAdminRole != "" { 161 schemeImpliedRoles = append(schemeImpliedRoles, defaultChannelAdminRole) 162 } else if defaultTeamAdminRole != "" { 163 schemeImpliedRoles = append(schemeImpliedRoles, defaultTeamAdminRole) 164 } else { 165 schemeImpliedRoles = append(schemeImpliedRoles, model.CHANNEL_ADMIN_ROLE_ID) 166 } 167 } 168 for _, impliedRole := range schemeImpliedRoles { 169 alreadyThere := false 170 for _, role := range result.roles { 171 if role == impliedRole { 172 alreadyThere = true 173 break 174 } 175 } 176 if !alreadyThere { 177 result.roles = append(result.roles, impliedRole) 178 } 179 } 180 return result 181 } 182 183 func (db channelMemberWithSchemeRoles) ToModel() *model.ChannelMember { 184 // Identify any system-wide scheme derived roles that are in "Roles" field due to not yet being migrated, 185 // and exclude them from ExplicitRoles field. 186 schemeGuest := db.SchemeGuest.Valid && db.SchemeGuest.Bool 187 schemeUser := db.SchemeUser.Valid && db.SchemeUser.Bool 188 schemeAdmin := db.SchemeAdmin.Valid && db.SchemeAdmin.Bool 189 190 defaultTeamGuestRole := "" 191 if db.TeamSchemeDefaultGuestRole.Valid { 192 defaultTeamGuestRole = db.TeamSchemeDefaultGuestRole.String 193 } 194 195 defaultTeamUserRole := "" 196 if db.TeamSchemeDefaultUserRole.Valid { 197 defaultTeamUserRole = db.TeamSchemeDefaultUserRole.String 198 } 199 200 defaultTeamAdminRole := "" 201 if db.TeamSchemeDefaultAdminRole.Valid { 202 defaultTeamAdminRole = db.TeamSchemeDefaultAdminRole.String 203 } 204 205 defaultChannelGuestRole := "" 206 if db.ChannelSchemeDefaultGuestRole.Valid { 207 defaultChannelGuestRole = db.ChannelSchemeDefaultGuestRole.String 208 } 209 210 defaultChannelUserRole := "" 211 if db.ChannelSchemeDefaultUserRole.Valid { 212 defaultChannelUserRole = db.ChannelSchemeDefaultUserRole.String 213 } 214 215 defaultChannelAdminRole := "" 216 if db.ChannelSchemeDefaultAdminRole.Valid { 217 defaultChannelAdminRole = db.ChannelSchemeDefaultAdminRole.String 218 } 219 220 rolesResult := getChannelRoles( 221 schemeGuest, schemeUser, schemeAdmin, 222 defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole, 223 defaultChannelGuestRole, defaultChannelUserRole, defaultChannelAdminRole, 224 strings.Fields(db.Roles), 225 ) 226 return &model.ChannelMember{ 227 ChannelId: db.ChannelId, 228 UserId: db.UserId, 229 Roles: strings.Join(rolesResult.roles, " "), 230 LastViewedAt: db.LastViewedAt, 231 MsgCount: db.MsgCount, 232 MentionCount: db.MentionCount, 233 NotifyProps: db.NotifyProps, 234 LastUpdateAt: db.LastUpdateAt, 235 SchemeAdmin: rolesResult.schemeAdmin, 236 SchemeUser: rolesResult.schemeUser, 237 SchemeGuest: rolesResult.schemeGuest, 238 ExplicitRoles: strings.Join(rolesResult.explicitRoles, " "), 239 } 240 } 241 242 func (db channelMemberWithSchemeRolesList) ToModel() *model.ChannelMembers { 243 cms := model.ChannelMembers{} 244 245 for _, cm := range db { 246 cms = append(cms, *cm.ToModel()) 247 } 248 249 return &cms 250 } 251 252 type allChannelMember struct { 253 ChannelId string 254 Roles string 255 SchemeGuest sql.NullBool 256 SchemeUser sql.NullBool 257 SchemeAdmin sql.NullBool 258 TeamSchemeDefaultGuestRole sql.NullString 259 TeamSchemeDefaultUserRole sql.NullString 260 TeamSchemeDefaultAdminRole sql.NullString 261 ChannelSchemeDefaultGuestRole sql.NullString 262 ChannelSchemeDefaultUserRole sql.NullString 263 ChannelSchemeDefaultAdminRole sql.NullString 264 } 265 266 type allChannelMembers []allChannelMember 267 268 func (db allChannelMember) Process() (string, string) { 269 roles := strings.Fields(db.Roles) 270 271 // Add any scheme derived roles that are not in the Roles field due to being Implicit from the Scheme, and add 272 // them to the Roles field for backwards compatibility reasons. 273 var schemeImpliedRoles []string 274 if db.SchemeGuest.Valid && db.SchemeGuest.Bool { 275 if db.ChannelSchemeDefaultGuestRole.Valid && db.ChannelSchemeDefaultGuestRole.String != "" { 276 schemeImpliedRoles = append(schemeImpliedRoles, db.ChannelSchemeDefaultGuestRole.String) 277 } else if db.TeamSchemeDefaultGuestRole.Valid && db.TeamSchemeDefaultGuestRole.String != "" { 278 schemeImpliedRoles = append(schemeImpliedRoles, db.TeamSchemeDefaultGuestRole.String) 279 } else { 280 schemeImpliedRoles = append(schemeImpliedRoles, model.CHANNEL_GUEST_ROLE_ID) 281 } 282 } 283 if db.SchemeUser.Valid && db.SchemeUser.Bool { 284 if db.ChannelSchemeDefaultUserRole.Valid && db.ChannelSchemeDefaultUserRole.String != "" { 285 schemeImpliedRoles = append(schemeImpliedRoles, db.ChannelSchemeDefaultUserRole.String) 286 } else if db.TeamSchemeDefaultUserRole.Valid && db.TeamSchemeDefaultUserRole.String != "" { 287 schemeImpliedRoles = append(schemeImpliedRoles, db.TeamSchemeDefaultUserRole.String) 288 } else { 289 schemeImpliedRoles = append(schemeImpliedRoles, model.CHANNEL_USER_ROLE_ID) 290 } 291 } 292 if db.SchemeAdmin.Valid && db.SchemeAdmin.Bool { 293 if db.ChannelSchemeDefaultAdminRole.Valid && db.ChannelSchemeDefaultAdminRole.String != "" { 294 schemeImpliedRoles = append(schemeImpliedRoles, db.ChannelSchemeDefaultAdminRole.String) 295 } else if db.TeamSchemeDefaultAdminRole.Valid && db.TeamSchemeDefaultAdminRole.String != "" { 296 schemeImpliedRoles = append(schemeImpliedRoles, db.TeamSchemeDefaultAdminRole.String) 297 } else { 298 schemeImpliedRoles = append(schemeImpliedRoles, model.CHANNEL_ADMIN_ROLE_ID) 299 } 300 } 301 for _, impliedRole := range schemeImpliedRoles { 302 alreadyThere := false 303 for _, role := range roles { 304 if role == impliedRole { 305 alreadyThere = true 306 } 307 } 308 if !alreadyThere { 309 roles = append(roles, impliedRole) 310 } 311 } 312 313 return db.ChannelId, strings.Join(roles, " ") 314 } 315 316 func (db allChannelMembers) ToMapStringString() map[string]string { 317 result := make(map[string]string) 318 319 for _, item := range db { 320 key, value := item.Process() 321 result[key] = value 322 } 323 324 return result 325 } 326 327 // publicChannel is a subset of the metadata corresponding to public channels only. 328 type publicChannel struct { 329 Id string `json:"id"` 330 DeleteAt int64 `json:"delete_at"` 331 TeamId string `json:"team_id"` 332 DisplayName string `json:"display_name"` 333 Name string `json:"name"` 334 Header string `json:"header"` 335 Purpose string `json:"purpose"` 336 } 337 338 var allChannelMembersForUserCache = cache.NewLRU(cache.LRUOptions{ 339 Size: AllChannelMembersForUserCacheSize, 340 }) 341 var allChannelMembersNotifyPropsForChannelCache = cache.NewLRU(cache.LRUOptions{ 342 Size: AllChannelMembersNotifyPropsForChannelCacheSize, 343 }) 344 var channelByNameCache = cache.NewLRU(cache.LRUOptions{ 345 Size: model.CHANNEL_CACHE_SIZE, 346 }) 347 348 func (s SqlChannelStore) ClearCaches() { 349 allChannelMembersForUserCache.Purge() 350 allChannelMembersNotifyPropsForChannelCache.Purge() 351 channelByNameCache.Purge() 352 353 if s.metrics != nil { 354 s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members for User - Purge") 355 s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members Notify Props for Channel - Purge") 356 s.metrics.IncrementMemCacheInvalidationCounter("Channel By Name - Purge") 357 } 358 } 359 360 func newSqlChannelStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) store.ChannelStore { 361 s := &SqlChannelStore{ 362 SqlStore: sqlStore, 363 metrics: metrics, 364 } 365 366 for _, db := range sqlStore.GetAllConns() { 367 table := db.AddTableWithName(model.Channel{}, "Channels").SetKeys(false, "Id") 368 table.ColMap("Id").SetMaxSize(26) 369 table.ColMap("TeamId").SetMaxSize(26) 370 table.ColMap("Type").SetMaxSize(1) 371 table.ColMap("DisplayName").SetMaxSize(64) 372 table.ColMap("Name").SetMaxSize(64) 373 table.SetUniqueTogether("Name", "TeamId") 374 table.ColMap("Header").SetMaxSize(1024) 375 table.ColMap("Purpose").SetMaxSize(250) 376 table.ColMap("CreatorId").SetMaxSize(26) 377 table.ColMap("SchemeId").SetMaxSize(26) 378 379 tablem := db.AddTableWithName(channelMember{}, "ChannelMembers").SetKeys(false, "ChannelId", "UserId") 380 tablem.ColMap("ChannelId").SetMaxSize(26) 381 tablem.ColMap("UserId").SetMaxSize(26) 382 tablem.ColMap("Roles").SetMaxSize(64) 383 tablem.ColMap("NotifyProps").SetMaxSize(2000) 384 385 tablePublicChannels := db.AddTableWithName(publicChannel{}, "PublicChannels").SetKeys(false, "Id") 386 tablePublicChannels.ColMap("Id").SetMaxSize(26) 387 tablePublicChannels.ColMap("TeamId").SetMaxSize(26) 388 tablePublicChannels.ColMap("DisplayName").SetMaxSize(64) 389 tablePublicChannels.ColMap("Name").SetMaxSize(64) 390 tablePublicChannels.SetUniqueTogether("Name", "TeamId") 391 tablePublicChannels.ColMap("Header").SetMaxSize(1024) 392 tablePublicChannels.ColMap("Purpose").SetMaxSize(250) 393 394 tableSidebarCategories := db.AddTableWithName(model.SidebarCategory{}, "SidebarCategories").SetKeys(false, "Id") 395 tableSidebarCategories.ColMap("Id").SetMaxSize(128) 396 tableSidebarCategories.ColMap("UserId").SetMaxSize(26) 397 tableSidebarCategories.ColMap("TeamId").SetMaxSize(26) 398 tableSidebarCategories.ColMap("Sorting").SetMaxSize(64) 399 tableSidebarCategories.ColMap("Type").SetMaxSize(64) 400 tableSidebarCategories.ColMap("DisplayName").SetMaxSize(64) 401 402 tableSidebarChannels := db.AddTableWithName(model.SidebarChannel{}, "SidebarChannels").SetKeys(false, "ChannelId", "UserId", "CategoryId") 403 tableSidebarChannels.ColMap("ChannelId").SetMaxSize(26) 404 tableSidebarChannels.ColMap("UserId").SetMaxSize(26) 405 tableSidebarChannels.ColMap("CategoryId").SetMaxSize(128) 406 } 407 408 return s 409 } 410 411 func (s SqlChannelStore) createIndexesIfNotExists() { 412 s.CreateIndexIfNotExists("idx_channels_team_id", "Channels", "TeamId") 413 s.CreateIndexIfNotExists("idx_channels_name", "Channels", "Name") 414 s.CreateIndexIfNotExists("idx_channels_update_at", "Channels", "UpdateAt") 415 s.CreateIndexIfNotExists("idx_channels_create_at", "Channels", "CreateAt") 416 s.CreateIndexIfNotExists("idx_channels_delete_at", "Channels", "DeleteAt") 417 418 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 419 s.CreateIndexIfNotExists("idx_channels_name_lower", "Channels", "lower(Name)") 420 s.CreateIndexIfNotExists("idx_channels_displayname_lower", "Channels", "lower(DisplayName)") 421 } 422 423 s.CreateIndexIfNotExists("idx_channelmembers_channel_id", "ChannelMembers", "ChannelId") 424 s.CreateIndexIfNotExists("idx_channelmembers_user_id", "ChannelMembers", "UserId") 425 426 s.CreateFullTextIndexIfNotExists("idx_channel_search_txt", "Channels", "Name, DisplayName, Purpose") 427 428 s.CreateIndexIfNotExists("idx_publicchannels_team_id", "PublicChannels", "TeamId") 429 s.CreateIndexIfNotExists("idx_publicchannels_name", "PublicChannels", "Name") 430 s.CreateIndexIfNotExists("idx_publicchannels_delete_at", "PublicChannels", "DeleteAt") 431 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 432 s.CreateIndexIfNotExists("idx_publicchannels_name_lower", "PublicChannels", "lower(Name)") 433 s.CreateIndexIfNotExists("idx_publicchannels_displayname_lower", "PublicChannels", "lower(DisplayName)") 434 } 435 s.CreateFullTextIndexIfNotExists("idx_publicchannels_search_txt", "PublicChannels", "Name, DisplayName, Purpose") 436 s.CreateIndexIfNotExists("idx_channels_scheme_id", "Channels", "SchemeId") 437 } 438 439 // MigratePublicChannels initializes the PublicChannels table with data created before this version 440 // of the Mattermost server kept it up-to-date. 441 func (s SqlChannelStore) MigratePublicChannels() error { 442 if _, err := s.GetMaster().Exec(` 443 INSERT INTO PublicChannels 444 (Id, DeleteAt, TeamId, DisplayName, Name, Header, Purpose) 445 SELECT 446 c.Id, c.DeleteAt, c.TeamId, c.DisplayName, c.Name, c.Header, c.Purpose 447 FROM 448 Channels c 449 LEFT JOIN 450 PublicChannels pc ON (pc.Id = c.Id) 451 WHERE 452 c.Type = 'O' 453 AND pc.Id IS NULL 454 `); err != nil { 455 return err 456 } 457 458 return nil 459 } 460 461 func (s SqlChannelStore) upsertPublicChannelT(transaction *gorp.Transaction, channel *model.Channel) error { 462 publicChannel := &publicChannel{ 463 Id: channel.Id, 464 DeleteAt: channel.DeleteAt, 465 TeamId: channel.TeamId, 466 DisplayName: channel.DisplayName, 467 Name: channel.Name, 468 Header: channel.Header, 469 Purpose: channel.Purpose, 470 } 471 472 if channel.Type != model.CHANNEL_OPEN { 473 if _, err := transaction.Delete(publicChannel); err != nil { 474 return errors.Wrap(err, "failed to delete public channel") 475 } 476 477 return nil 478 } 479 480 if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 481 // Leverage native upsert for MySQL, since RowsAffected returns 0 if the row exists 482 // but no changes were made, breaking the update-then-insert paradigm below when 483 // the row already exists. (Postgres 9.4 doesn't support native upsert.) 484 if _, err := transaction.Exec(` 485 INSERT INTO 486 PublicChannels(Id, DeleteAt, TeamId, DisplayName, Name, Header, Purpose) 487 VALUES 488 (:Id, :DeleteAt, :TeamId, :DisplayName, :Name, :Header, :Purpose) 489 ON DUPLICATE KEY UPDATE 490 DeleteAt = :DeleteAt, 491 TeamId = :TeamId, 492 DisplayName = :DisplayName, 493 Name = :Name, 494 Header = :Header, 495 Purpose = :Purpose; 496 `, map[string]interface{}{ 497 "Id": publicChannel.Id, 498 "DeleteAt": publicChannel.DeleteAt, 499 "TeamId": publicChannel.TeamId, 500 "DisplayName": publicChannel.DisplayName, 501 "Name": publicChannel.Name, 502 "Header": publicChannel.Header, 503 "Purpose": publicChannel.Purpose, 504 }); err != nil { 505 return errors.Wrap(err, "failed to insert public channel") 506 } 507 } else { 508 count, err := transaction.Update(publicChannel) 509 if err != nil { 510 return errors.Wrap(err, "failed to update public channel") 511 } 512 if count > 0 { 513 return nil 514 } 515 516 if err := transaction.Insert(publicChannel); err != nil { 517 return errors.Wrap(err, "failed to insert public channel") 518 } 519 } 520 521 return nil 522 } 523 524 // Save writes the (non-direct) channel channel to the database. 525 func (s SqlChannelStore) Save(channel *model.Channel, maxChannelsPerTeam int64) (*model.Channel, error) { 526 if channel.DeleteAt != 0 { 527 return nil, store.NewErrInvalidInput("Channel", "DeleteAt", channel.DeleteAt) 528 } 529 530 if channel.Type == model.CHANNEL_DIRECT { 531 return nil, store.NewErrInvalidInput("Channel", "Type", channel.Type) 532 } 533 534 var newChannel *model.Channel 535 transaction, err := s.GetMaster().Begin() 536 if err != nil { 537 return nil, errors.Wrap(err, "begin_transaction") 538 } 539 defer finalizeTransaction(transaction) 540 541 newChannel, err = s.saveChannelT(transaction, channel, maxChannelsPerTeam) 542 if err != nil { 543 return newChannel, err 544 } 545 546 // Additionally propagate the write to the PublicChannels table. 547 if err = s.upsertPublicChannelT(transaction, newChannel); err != nil { 548 return nil, errors.Wrap(err, "upsert_public_channel") 549 } 550 551 if err = transaction.Commit(); err != nil { 552 return nil, errors.Wrap(err, "commit_transaction") 553 } 554 // There are cases when in case of conflict, the original channel value is returned. 555 // So we return both and let the caller do the checks. 556 return newChannel, err 557 } 558 559 func (s SqlChannelStore) CreateDirectChannel(user *model.User, otherUser *model.User) (*model.Channel, error) { 560 channel := new(model.Channel) 561 562 channel.DisplayName = "" 563 channel.Name = model.GetDMNameFromIds(otherUser.Id, user.Id) 564 565 channel.Header = "" 566 channel.Type = model.CHANNEL_DIRECT 567 568 cm1 := &model.ChannelMember{ 569 UserId: user.Id, 570 NotifyProps: model.GetDefaultChannelNotifyProps(), 571 SchemeGuest: user.IsGuest(), 572 SchemeUser: !user.IsGuest(), 573 } 574 cm2 := &model.ChannelMember{ 575 UserId: otherUser.Id, 576 NotifyProps: model.GetDefaultChannelNotifyProps(), 577 SchemeGuest: otherUser.IsGuest(), 578 SchemeUser: !otherUser.IsGuest(), 579 } 580 581 return s.SaveDirectChannel(channel, cm1, cm2) 582 } 583 584 func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1 *model.ChannelMember, member2 *model.ChannelMember) (*model.Channel, error) { 585 if directchannel.DeleteAt != 0 { 586 return nil, store.NewErrInvalidInput("Channel", "DeleteAt", directchannel.DeleteAt) 587 } 588 589 if directchannel.Type != model.CHANNEL_DIRECT { 590 return nil, store.NewErrInvalidInput("Channel", "Type", directchannel.Type) 591 } 592 593 transaction, err := s.GetMaster().Begin() 594 if err != nil { 595 return nil, errors.Wrap(err, "begin_transaction") 596 } 597 defer finalizeTransaction(transaction) 598 599 directchannel.TeamId = "" 600 newChannel, err := s.saveChannelT(transaction, directchannel, 0) 601 if err != nil { 602 return newChannel, err 603 } 604 605 // Members need new channel ID 606 member1.ChannelId = newChannel.Id 607 member2.ChannelId = newChannel.Id 608 609 if member1.UserId != member2.UserId { 610 _, err = s.saveMultipleMembers([]*model.ChannelMember{member1, member2}) 611 } else { 612 _, err = s.saveMemberT(member2) 613 } 614 if err != nil { 615 return nil, err 616 } 617 618 if err := transaction.Commit(); err != nil { 619 return nil, errors.Wrap(err, "commit_transaction") 620 } 621 622 return newChannel, nil 623 624 } 625 626 func (s SqlChannelStore) saveChannelT(transaction *gorp.Transaction, channel *model.Channel, maxChannelsPerTeam int64) (*model.Channel, error) { 627 if channel.Id != "" { 628 return nil, store.NewErrInvalidInput("Channel", "Id", channel.Id) 629 } 630 631 channel.PreSave() 632 if err := channel.IsValid(); err != nil { // TODO: this needs to return plain error in v6. 633 return nil, err // we just pass through the error as-is for now. 634 } 635 636 if channel.Type != model.CHANNEL_DIRECT && channel.Type != model.CHANNEL_GROUP && maxChannelsPerTeam >= 0 { 637 if count, err := transaction.SelectInt("SELECT COUNT(0) FROM Channels WHERE TeamId = :TeamId AND DeleteAt = 0 AND (Type = 'O' OR Type = 'P')", map[string]interface{}{"TeamId": channel.TeamId}); err != nil { 638 return nil, errors.Wrapf(err, "save_channel_count: teamId=%s", channel.TeamId) 639 } else if count >= maxChannelsPerTeam { 640 return nil, store.NewErrLimitExceeded("channels_per_team", int(count), "teamId="+channel.TeamId) 641 } 642 } 643 644 if err := transaction.Insert(channel); err != nil { 645 if IsUniqueConstraintError(err, []string{"Name", "channels_name_teamid_key"}) { 646 dupChannel := model.Channel{} 647 s.GetMaster().SelectOne(&dupChannel, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name = :Name", map[string]interface{}{"TeamId": channel.TeamId, "Name": channel.Name}) 648 return &dupChannel, store.NewErrConflict("Channel", err, "id="+channel.Id) 649 } 650 return nil, errors.Wrapf(err, "save_channel: id=%s", channel.Id) 651 } 652 return channel, nil 653 } 654 655 // Update writes the updated channel to the database. 656 func (s SqlChannelStore) Update(channel *model.Channel) (*model.Channel, error) { 657 transaction, err := s.GetMaster().Begin() 658 if err != nil { 659 return nil, errors.Wrap(err, "begin_transaction") 660 } 661 defer finalizeTransaction(transaction) 662 663 updatedChannel, err := s.updateChannelT(transaction, channel) 664 if err != nil { 665 return nil, err 666 } 667 668 // Additionally propagate the write to the PublicChannels table. 669 if err := s.upsertPublicChannelT(transaction, updatedChannel); err != nil { 670 return nil, errors.Wrap(err, "upsertPublicChannelT: failed to upsert channel") 671 } 672 673 if err := transaction.Commit(); err != nil { 674 return nil, errors.Wrap(err, "commit_transaction") 675 } 676 return updatedChannel, nil 677 } 678 679 func (s SqlChannelStore) updateChannelT(transaction *gorp.Transaction, channel *model.Channel) (*model.Channel, error) { 680 channel.PreUpdate() 681 682 if channel.DeleteAt != 0 { 683 return nil, store.NewErrInvalidInput("Channel", "DeleteAt", channel.DeleteAt) 684 } 685 686 if err := channel.IsValid(); err != nil { 687 return nil, err 688 } 689 690 count, err := transaction.Update(channel) 691 if err != nil { 692 if IsUniqueConstraintError(err, []string{"Name", "channels_name_teamid_key"}) { 693 dupChannel := model.Channel{} 694 s.GetReplica().SelectOne(&dupChannel, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name= :Name AND DeleteAt > 0", map[string]interface{}{"TeamId": channel.TeamId, "Name": channel.Name}) 695 if dupChannel.DeleteAt > 0 { 696 return nil, store.NewErrInvalidInput("Channel", "Id", channel.Id) 697 } 698 return nil, store.NewErrInvalidInput("Channel", "Id", channel.Id) 699 } 700 return nil, errors.Wrapf(err, "failed to update channel with id=%s", channel.Id) 701 } 702 703 if count > 1 { 704 return nil, fmt.Errorf("the expected number of channels to be updated is <=1 but was %d", count) 705 } 706 707 return channel, nil 708 } 709 710 func (s SqlChannelStore) GetChannelUnread(channelId, userId string) (*model.ChannelUnread, error) { 711 var unreadChannel model.ChannelUnread 712 err := s.GetReplica().SelectOne(&unreadChannel, 713 `SELECT 714 Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps 715 FROM 716 Channels, ChannelMembers 717 WHERE 718 Id = ChannelId 719 AND Id = :ChannelId 720 AND UserId = :UserId 721 AND DeleteAt = 0`, 722 map[string]interface{}{"ChannelId": channelId, "UserId": userId}) 723 724 if err != nil { 725 if err == sql.ErrNoRows { 726 return nil, store.NewErrNotFound("Channel", fmt.Sprintf("channelId=%s,userId=%s", channelId, userId)) 727 } 728 return nil, errors.Wrapf(err, "failed to get Channel with channelId=%s and userId=%s", channelId, userId) 729 } 730 return &unreadChannel, nil 731 } 732 733 //nolint:unparam 734 func (s SqlChannelStore) InvalidateChannel(id string) { 735 } 736 737 func (s SqlChannelStore) InvalidateChannelByName(teamId, name string) { 738 channelByNameCache.Remove(teamId + name) 739 if s.metrics != nil { 740 s.metrics.IncrementMemCacheInvalidationCounter("Channel by Name - Remove by TeamId and Name") 741 } 742 } 743 744 //nolint:unparam 745 func (s SqlChannelStore) Get(id string, allowFromCache bool) (*model.Channel, error) { 746 return s.get(id, false) 747 } 748 749 func (s SqlChannelStore) GetPinnedPosts(channelId string) (*model.PostList, error) { 750 pl := model.NewPostList() 751 752 var posts []*model.Post 753 if _, err := s.GetReplica().Select(&posts, "SELECT *, (SELECT count(Posts.Id) FROM Posts WHERE Posts.RootId = (CASE WHEN p.RootId = '' THEN p.Id ELSE p.RootId END) AND Posts.DeleteAt = 0) as ReplyCount FROM Posts p WHERE IsPinned = true AND ChannelId = :ChannelId AND DeleteAt = 0 ORDER BY CreateAt ASC", map[string]interface{}{"ChannelId": channelId}); err != nil { 754 return nil, errors.Wrap(err, "failed to find Posts") 755 } 756 for _, post := range posts { 757 pl.AddPost(post) 758 pl.AddOrder(post.Id) 759 } 760 return pl, nil 761 } 762 763 func (s SqlChannelStore) GetFromMaster(id string) (*model.Channel, error) { 764 return s.get(id, true) 765 } 766 767 func (s SqlChannelStore) get(id string, master bool) (*model.Channel, error) { 768 var db *gorp.DbMap 769 770 if master { 771 db = s.GetMaster() 772 } else { 773 db = s.GetReplica() 774 } 775 776 obj, err := db.Get(model.Channel{}, id) 777 if err != nil { 778 return nil, errors.Wrapf(err, "failed to find channel with id = %s", id) 779 } 780 781 if obj == nil { 782 return nil, store.NewErrNotFound("Channel", id) 783 } 784 785 ch := obj.(*model.Channel) 786 return ch, nil 787 } 788 789 // Delete records the given deleted timestamp to the channel in question. 790 func (s SqlChannelStore) Delete(channelId string, time int64) error { 791 return s.SetDeleteAt(channelId, time, time) 792 } 793 794 // Restore reverts a previous deleted timestamp from the channel in question. 795 func (s SqlChannelStore) Restore(channelId string, time int64) error { 796 return s.SetDeleteAt(channelId, 0, time) 797 } 798 799 // SetDeleteAt records the given deleted and updated timestamp to the channel in question. 800 func (s SqlChannelStore) SetDeleteAt(channelId string, deleteAt, updateAt int64) error { 801 defer s.InvalidateChannel(channelId) 802 803 transaction, err := s.GetMaster().Begin() 804 if err != nil { 805 return errors.Wrap(err, "SetDeleteAt: begin_transaction") 806 } 807 defer finalizeTransaction(transaction) 808 809 err = s.setDeleteAtT(transaction, channelId, deleteAt, updateAt) 810 if err != nil { 811 return errors.Wrap(err, "setDeleteAtT") 812 } 813 814 // Additionally propagate the write to the PublicChannels table. 815 if _, err := transaction.Exec(` 816 UPDATE 817 PublicChannels 818 SET 819 DeleteAt = :DeleteAt 820 WHERE 821 Id = :ChannelId 822 `, map[string]interface{}{ 823 "DeleteAt": deleteAt, 824 "ChannelId": channelId, 825 }); err != nil { 826 return errors.Wrapf(err, "failed to delete public channels with id=%s", channelId) 827 } 828 829 if err := transaction.Commit(); err != nil { 830 return errors.Wrapf(err, "SetDeleteAt: commit_transaction") 831 } 832 833 return nil 834 } 835 836 func (s SqlChannelStore) setDeleteAtT(transaction *gorp.Transaction, channelId string, deleteAt, updateAt int64) error { 837 _, err := transaction.Exec("Update Channels SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :ChannelId", map[string]interface{}{"DeleteAt": deleteAt, "UpdateAt": updateAt, "ChannelId": channelId}) 838 if err != nil { 839 return errors.Wrapf(err, "failed to delete channel with id=%s", channelId) 840 } 841 842 return nil 843 } 844 845 // PermanentDeleteByTeam removes all channels for the given team from the database. 846 func (s SqlChannelStore) PermanentDeleteByTeam(teamId string) error { 847 transaction, err := s.GetMaster().Begin() 848 if err != nil { 849 return errors.Wrap(err, "PermanentDeleteByTeam: begin_transaction") 850 } 851 defer finalizeTransaction(transaction) 852 853 if err := s.permanentDeleteByTeamtT(transaction, teamId); err != nil { 854 return errors.Wrap(err, "permanentDeleteByTeamtT") 855 } 856 857 // Additionally propagate the deletions to the PublicChannels table. 858 if _, err := transaction.Exec(` 859 DELETE FROM 860 PublicChannels 861 WHERE 862 TeamId = :TeamId 863 `, map[string]interface{}{ 864 "TeamId": teamId, 865 }); err != nil { 866 return errors.Wrapf(err, "failed to delete public channels by team with teamId=%s", teamId) 867 } 868 869 if err := transaction.Commit(); err != nil { 870 return errors.Wrap(err, "PermanentDeleteByTeam: commit_transaction") 871 } 872 873 return nil 874 } 875 876 func (s SqlChannelStore) permanentDeleteByTeamtT(transaction *gorp.Transaction, teamId string) error { 877 if _, err := transaction.Exec("DELETE FROM Channels WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil { 878 return errors.Wrapf(err, "failed to delete channel by team with teamId=%s", teamId) 879 } 880 881 return nil 882 } 883 884 // PermanentDelete removes the given channel from the database. 885 func (s SqlChannelStore) PermanentDelete(channelId string) error { 886 transaction, err := s.GetMaster().Begin() 887 if err != nil { 888 return errors.Wrap(err, "PermanentDelete: begin_transaction") 889 } 890 defer finalizeTransaction(transaction) 891 892 if err := s.permanentDeleteT(transaction, channelId); err != nil { 893 return errors.Wrap(err, "permanentDeleteT") 894 } 895 896 // Additionally propagate the deletion to the PublicChannels table. 897 if _, err := transaction.Exec(` 898 DELETE FROM 899 PublicChannels 900 WHERE 901 Id = :ChannelId 902 `, map[string]interface{}{ 903 "ChannelId": channelId, 904 }); err != nil { 905 return errors.Wrapf(err, "failed to delete public channels with id=%s", channelId) 906 } 907 908 if err := transaction.Commit(); err != nil { 909 return errors.Wrap(err, "PermanentDelete: commit_transaction") 910 } 911 912 return nil 913 } 914 915 func (s SqlChannelStore) permanentDeleteT(transaction *gorp.Transaction, channelId string) error { 916 if _, err := transaction.Exec("DELETE FROM Channels WHERE Id = :ChannelId", map[string]interface{}{"ChannelId": channelId}); err != nil { 917 return errors.Wrapf(err, "failed to delete channel with id=%s", channelId) 918 } 919 920 return nil 921 } 922 923 func (s SqlChannelStore) PermanentDeleteMembersByChannel(channelId string) error { 924 _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId}) 925 if err != nil { 926 return errors.Wrapf(err, "failed to delete Channel with channelId=%s", channelId) 927 } 928 929 return nil 930 } 931 932 func (s SqlChannelStore) GetChannels(teamId string, userId string, includeDeleted bool, lastDeleteAt int) (*model.ChannelList, error) { 933 query := s.getQueryBuilder(). 934 Select("Channels.*"). 935 From("Channels, ChannelMembers"). 936 Where( 937 sq.And{ 938 sq.Expr("Id = ChannelId"), 939 sq.Eq{"UserId": userId}, 940 sq.Or{ 941 sq.Eq{"TeamId": teamId}, 942 sq.Eq{"TeamId": ""}, 943 }, 944 }, 945 ). 946 OrderBy("DisplayName") 947 948 if includeDeleted { 949 if lastDeleteAt != 0 { 950 // We filter by non-archived, and archived >= a timestamp. 951 query = query.Where(sq.Or{ 952 sq.Eq{"DeleteAt": 0}, 953 sq.GtOrEq{"DeleteAt": lastDeleteAt}, 954 }) 955 } 956 // If lastDeleteAt is not set, we include everything. That means no filter is needed. 957 } else { 958 // Don't include archived channels. 959 query = query.Where(sq.Eq{"DeleteAt": 0}) 960 } 961 962 channels := &model.ChannelList{} 963 sql, args, err := query.ToSql() 964 if err != nil { 965 return nil, errors.Wrapf(err, "getchannels_tosql") 966 } 967 968 _, err = s.GetReplica().Select(channels, sql, args...) 969 if err != nil { 970 return nil, errors.Wrapf(err, "failed to get channels with TeamId=%s and UserId=%s", teamId, userId) 971 } 972 973 if len(*channels) == 0 { 974 return nil, store.NewErrNotFound("Channel", "userId="+userId) 975 } 976 977 return channels, nil 978 } 979 980 func (s SqlChannelStore) GetAllChannels(offset, limit int, opts store.ChannelSearchOpts) (*model.ChannelListWithTeamData, error) { 981 query := s.getAllChannelsQuery(opts, false) 982 983 query = query.OrderBy("c.DisplayName, Teams.DisplayName").Limit(uint64(limit)).Offset(uint64(offset)) 984 985 queryString, args, err := query.ToSql() 986 if err != nil { 987 return nil, errors.Wrap(err, "failed to create query") 988 } 989 990 data := &model.ChannelListWithTeamData{} 991 _, err = s.GetReplica().Select(data, queryString, args...) 992 993 if err != nil { 994 return nil, errors.Wrap(err, "failed to get all channels") 995 } 996 997 return data, nil 998 } 999 1000 func (s SqlChannelStore) GetAllChannelsCount(opts store.ChannelSearchOpts) (int64, error) { 1001 query := s.getAllChannelsQuery(opts, true) 1002 1003 queryString, args, err := query.ToSql() 1004 if err != nil { 1005 return 0, errors.Wrap(err, "failed to create query") 1006 } 1007 1008 count, err := s.GetReplica().SelectInt(queryString, args...) 1009 if err != nil { 1010 return 0, errors.Wrap(err, "failed to count all channels") 1011 } 1012 1013 return count, nil 1014 } 1015 1016 func (s SqlChannelStore) getAllChannelsQuery(opts store.ChannelSearchOpts, forCount bool) sq.SelectBuilder { 1017 var selectStr string 1018 if forCount { 1019 selectStr = "count(c.Id)" 1020 } else { 1021 selectStr = "c.*, Teams.DisplayName AS TeamDisplayName, Teams.Name AS TeamName, Teams.UpdateAt AS TeamUpdateAt" 1022 } 1023 1024 query := s.getQueryBuilder(). 1025 Select(selectStr). 1026 From("Channels AS c"). 1027 Where(sq.Eq{"c.Type": []string{model.CHANNEL_PRIVATE, model.CHANNEL_OPEN}}) 1028 1029 if !forCount { 1030 query = query.Join("Teams ON Teams.Id = c.TeamId") 1031 } 1032 1033 if !opts.IncludeDeleted { 1034 query = query.Where(sq.Eq{"c.DeleteAt": int(0)}) 1035 } 1036 1037 if opts.NotAssociatedToGroup != "" { 1038 query = query.Where("c.Id NOT IN (SELECT ChannelId FROM GroupChannels WHERE GroupChannels.GroupId = ? AND GroupChannels.DeleteAt = 0)", opts.NotAssociatedToGroup) 1039 } 1040 1041 if len(opts.ExcludeChannelNames) > 0 { 1042 query = query.Where(sq.NotEq{"c.Name": opts.ExcludeChannelNames}) 1043 } 1044 1045 return query 1046 } 1047 1048 func (s SqlChannelStore) GetMoreChannels(teamId string, userId string, offset int, limit int) (*model.ChannelList, error) { 1049 channels := &model.ChannelList{} 1050 _, err := s.GetReplica().Select(channels, ` 1051 SELECT 1052 Channels.* 1053 FROM 1054 Channels 1055 JOIN 1056 PublicChannels c ON (c.Id = Channels.Id) 1057 WHERE 1058 c.TeamId = :TeamId 1059 AND c.DeleteAt = 0 1060 AND c.Id NOT IN ( 1061 SELECT 1062 c.Id 1063 FROM 1064 PublicChannels c 1065 JOIN 1066 ChannelMembers cm ON (cm.ChannelId = c.Id) 1067 WHERE 1068 c.TeamId = :TeamId 1069 AND cm.UserId = :UserId 1070 AND c.DeleteAt = 0 1071 ) 1072 ORDER BY 1073 c.DisplayName 1074 LIMIT :Limit 1075 OFFSET :Offset 1076 `, map[string]interface{}{ 1077 "TeamId": teamId, 1078 "UserId": userId, 1079 "Limit": limit, 1080 "Offset": offset, 1081 }) 1082 1083 if err != nil { 1084 return nil, errors.Wrapf(err, "failed getting channels with teamId=%s and userId=%s", teamId, userId) 1085 } 1086 1087 return channels, nil 1088 } 1089 1090 func (s SqlChannelStore) GetPrivateChannelsForTeam(teamId string, offset int, limit int) (*model.ChannelList, error) { 1091 channels := &model.ChannelList{} 1092 1093 builder := s.getQueryBuilder(). 1094 Select("*"). 1095 From("Channels"). 1096 Where(sq.Eq{"Type": model.CHANNEL_PRIVATE, "TeamId": teamId, "DeleteAt": 0}). 1097 OrderBy("DisplayName"). 1098 Limit(uint64(limit)). 1099 Offset(uint64(offset)) 1100 1101 query, args, err := builder.ToSql() 1102 if err != nil { 1103 return nil, errors.Wrap(err, "channels_tosql") 1104 } 1105 1106 _, err = s.GetReplica().Select(channels, query, args...) 1107 if err != nil { 1108 return nil, errors.Wrapf(err, "failed to find chaneld with teamId=%s", teamId) 1109 } 1110 return channels, nil 1111 } 1112 1113 func (s SqlChannelStore) GetPublicChannelsForTeam(teamId string, offset int, limit int) (*model.ChannelList, error) { 1114 channels := &model.ChannelList{} 1115 _, err := s.GetReplica().Select(channels, ` 1116 SELECT 1117 Channels.* 1118 FROM 1119 Channels 1120 JOIN 1121 PublicChannels pc ON (pc.Id = Channels.Id) 1122 WHERE 1123 pc.TeamId = :TeamId 1124 AND pc.DeleteAt = 0 1125 ORDER BY pc.DisplayName 1126 LIMIT :Limit 1127 OFFSET :Offset 1128 `, map[string]interface{}{ 1129 "TeamId": teamId, 1130 "Limit": limit, 1131 "Offset": offset, 1132 }) 1133 1134 if err != nil { 1135 return nil, errors.Wrapf(err, "failed to find chaneld with teamId=%s", teamId) 1136 } 1137 1138 return channels, nil 1139 } 1140 1141 func (s SqlChannelStore) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) (*model.ChannelList, error) { 1142 props := make(map[string]interface{}) 1143 props["teamId"] = teamId 1144 1145 idQuery := "" 1146 1147 for index, channelId := range channelIds { 1148 if idQuery != "" { 1149 idQuery += ", " 1150 } 1151 1152 props["channelId"+strconv.Itoa(index)] = channelId 1153 idQuery += ":channelId" + strconv.Itoa(index) 1154 } 1155 1156 data := &model.ChannelList{} 1157 _, err := s.GetReplica().Select(data, ` 1158 SELECT 1159 Channels.* 1160 FROM 1161 Channels 1162 JOIN 1163 PublicChannels pc ON (pc.Id = Channels.Id) 1164 WHERE 1165 pc.TeamId = :teamId 1166 AND pc.DeleteAt = 0 1167 AND pc.Id IN (`+idQuery+`) 1168 ORDER BY pc.DisplayName 1169 `, props) 1170 1171 if err != nil { 1172 return nil, errors.Wrap(err, "failed to find Channels") 1173 } 1174 1175 if len(*data) == 0 { 1176 return nil, store.NewErrNotFound("Channel", fmt.Sprintf("teamId=%s, channelIds=%v", teamId, channelIds)) 1177 } 1178 1179 return data, nil 1180 } 1181 1182 type channelIdWithCountAndUpdateAt struct { 1183 Id string 1184 TotalMsgCount int64 1185 UpdateAt int64 1186 } 1187 1188 func (s SqlChannelStore) GetChannelCounts(teamId string, userId string) (*model.ChannelCounts, error) { 1189 var data []channelIdWithCountAndUpdateAt 1190 _, err := s.GetReplica().Select(&data, "SELECT Id, TotalMsgCount, UpdateAt FROM Channels WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) AND (TeamId = :TeamId OR TeamId = '') AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId}) 1191 1192 if err != nil { 1193 return nil, errors.Wrapf(err, "failed to get channels count with teamId=%s and userId=%s", teamId, userId) 1194 } 1195 1196 counts := &model.ChannelCounts{Counts: make(map[string]int64), UpdateTimes: make(map[string]int64)} 1197 for i := range data { 1198 v := data[i] 1199 counts.Counts[v.Id] = v.TotalMsgCount 1200 counts.UpdateTimes[v.Id] = v.UpdateAt 1201 } 1202 1203 return counts, nil 1204 } 1205 1206 func (s SqlChannelStore) GetTeamChannels(teamId string) (*model.ChannelList, error) { 1207 data := &model.ChannelList{} 1208 _, err := s.GetReplica().Select(data, "SELECT * FROM Channels WHERE TeamId = :TeamId And Type != 'D' ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId}) 1209 1210 if err != nil { 1211 return nil, errors.Wrapf(err, "failed to find Channels with teamId=%s", teamId) 1212 } 1213 1214 if len(*data) == 0 { 1215 return nil, store.NewErrNotFound("Channel", fmt.Sprintf("teamId=%s", teamId)) 1216 } 1217 1218 return data, nil 1219 } 1220 1221 func (s SqlChannelStore) GetByName(teamId string, name string, allowFromCache bool) (*model.Channel, error) { 1222 return s.getByName(teamId, name, false, allowFromCache) 1223 } 1224 1225 func (s SqlChannelStore) GetByNames(teamId string, names []string, allowFromCache bool) ([]*model.Channel, error) { 1226 var channels []*model.Channel 1227 1228 if allowFromCache { 1229 var misses []string 1230 visited := make(map[string]struct{}) 1231 for _, name := range names { 1232 if _, ok := visited[name]; ok { 1233 continue 1234 } 1235 visited[name] = struct{}{} 1236 var cacheItem *model.Channel 1237 if err := channelByNameCache.Get(teamId+name, &cacheItem); err == nil { 1238 channels = append(channels, cacheItem) 1239 } else { 1240 misses = append(misses, name) 1241 } 1242 } 1243 names = misses 1244 } 1245 1246 if len(names) > 0 { 1247 props := map[string]interface{}{} 1248 var namePlaceholders []string 1249 for _, name := range names { 1250 key := fmt.Sprintf("Name%v", len(namePlaceholders)) 1251 props[key] = name 1252 namePlaceholders = append(namePlaceholders, ":"+key) 1253 } 1254 1255 var query string 1256 if teamId == "" { 1257 query = `SELECT * FROM Channels WHERE Name IN (` + strings.Join(namePlaceholders, ", ") + `) AND DeleteAt = 0` 1258 } else { 1259 props["TeamId"] = teamId 1260 query = `SELECT * FROM Channels WHERE Name IN (` + strings.Join(namePlaceholders, ", ") + `) AND TeamId = :TeamId AND DeleteAt = 0` 1261 } 1262 1263 var dbChannels []*model.Channel 1264 if _, err := s.GetReplica().Select(&dbChannels, query, props); err != nil && err != sql.ErrNoRows { 1265 msg := fmt.Sprintf("failed to get channels with names=%v", names) 1266 if teamId != "" { 1267 msg += fmt.Sprintf("teamId=%s", teamId) 1268 } 1269 return nil, errors.Wrap(err, msg) 1270 } 1271 for _, channel := range dbChannels { 1272 channelByNameCache.SetWithExpiry(teamId+channel.Name, channel, ChannelCacheDuration) 1273 channels = append(channels, channel) 1274 } 1275 // Not all channels are in cache. Increment aggregate miss counter. 1276 if s.metrics != nil { 1277 s.metrics.IncrementMemCacheMissCounter("Channel By Name - Aggregate") 1278 } 1279 } else { 1280 // All of the channel names are in cache. Increment aggregate hit counter. 1281 if s.metrics != nil { 1282 s.metrics.IncrementMemCacheHitCounter("Channel By Name - Aggregate") 1283 } 1284 } 1285 1286 return channels, nil 1287 } 1288 1289 func (s SqlChannelStore) GetByNameIncludeDeleted(teamId string, name string, allowFromCache bool) (*model.Channel, error) { 1290 return s.getByName(teamId, name, true, allowFromCache) 1291 } 1292 1293 func (s SqlChannelStore) getByName(teamId string, name string, includeDeleted bool, allowFromCache bool) (*model.Channel, error) { 1294 var query string 1295 if includeDeleted { 1296 query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name" 1297 } else { 1298 query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name AND DeleteAt = 0" 1299 } 1300 channel := model.Channel{} 1301 1302 if allowFromCache { 1303 var cacheItem *model.Channel 1304 if err := channelByNameCache.Get(teamId+name, &cacheItem); err == nil { 1305 if s.metrics != nil { 1306 s.metrics.IncrementMemCacheHitCounter("Channel By Name") 1307 } 1308 return cacheItem, nil 1309 } 1310 if s.metrics != nil { 1311 s.metrics.IncrementMemCacheMissCounter("Channel By Name") 1312 } 1313 } 1314 1315 if err := s.GetReplica().SelectOne(&channel, query, map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil { 1316 if err == sql.ErrNoRows { 1317 return nil, store.NewErrNotFound("Channel", fmt.Sprintf("TeamId=%s&Name=%s", teamId, name)) 1318 } 1319 return nil, errors.Wrapf(err, "failed to find channel with TeamId=%s and Name=%s", teamId, name) 1320 } 1321 1322 channelByNameCache.SetWithExpiry(teamId+name, &channel, ChannelCacheDuration) 1323 return &channel, nil 1324 } 1325 1326 func (s SqlChannelStore) GetDeletedByName(teamId string, name string) (*model.Channel, error) { 1327 channel := model.Channel{} 1328 1329 if err := s.GetReplica().SelectOne(&channel, "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name AND DeleteAt != 0", map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil { 1330 if err == sql.ErrNoRows { 1331 return nil, store.NewErrNotFound("Channel", fmt.Sprintf("name=%s", name)) 1332 } 1333 return nil, errors.Wrapf(err, "failed to get channel by teamId=%s and name=%s", teamId, name) 1334 } 1335 1336 return &channel, nil 1337 } 1338 1339 func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int, userId string) (*model.ChannelList, error) { 1340 channels := &model.ChannelList{} 1341 1342 query := ` 1343 SELECT * FROM Channels 1344 WHERE (TeamId = :TeamId OR TeamId = '') 1345 AND DeleteAt != 0 1346 AND Type != 'P' 1347 UNION 1348 SELECT * FROM Channels 1349 WHERE (TeamId = :TeamId OR TeamId = '') 1350 AND DeleteAt != 0 1351 AND Type = 'P' 1352 AND Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) 1353 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset 1354 ` 1355 1356 if _, err := s.GetReplica().Select(channels, query, map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset, "UserId": userId}); err != nil { 1357 if err == sql.ErrNoRows { 1358 return nil, store.NewErrNotFound("Channel", fmt.Sprintf("TeamId=%s,UserId=%s", teamId, userId)) 1359 } 1360 return nil, errors.Wrapf(err, "failed to get deleted channels with TeamId=%s and UserId=%s", teamId, userId) 1361 } 1362 1363 return channels, nil 1364 } 1365 1366 var ChannelMembersWithSchemeSelectQuery = ` 1367 SELECT 1368 ChannelMembers.*, 1369 TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole, 1370 TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole, 1371 TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole, 1372 ChannelScheme.DefaultChannelGuestRole ChannelSchemeDefaultGuestRole, 1373 ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole, 1374 ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole 1375 FROM 1376 ChannelMembers 1377 INNER JOIN 1378 Channels ON ChannelMembers.ChannelId = Channels.Id 1379 LEFT JOIN 1380 Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id 1381 LEFT JOIN 1382 Teams ON Channels.TeamId = Teams.Id 1383 LEFT JOIN 1384 Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id 1385 ` 1386 1387 func (s SqlChannelStore) SaveMultipleMembers(members []*model.ChannelMember) ([]*model.ChannelMember, error) { 1388 for _, member := range members { 1389 defer s.InvalidateAllChannelMembersForUser(member.UserId) 1390 } 1391 1392 transaction, err := s.GetMaster().Begin() 1393 if err != nil { 1394 return nil, errors.Wrap(err, "begin_transaction") 1395 } 1396 defer finalizeTransaction(transaction) 1397 1398 newMembers, err := s.saveMultipleMembers(members) 1399 if err != nil { 1400 return nil, err 1401 } 1402 1403 if err := transaction.Commit(); err != nil { 1404 return nil, errors.Wrap(err, "commit_transaction") 1405 } 1406 1407 return newMembers, nil 1408 } 1409 1410 func (s SqlChannelStore) SaveMember(member *model.ChannelMember) (*model.ChannelMember, error) { 1411 newMembers, err := s.SaveMultipleMembers([]*model.ChannelMember{member}) 1412 if err != nil { 1413 return nil, err 1414 } 1415 return newMembers[0], nil 1416 } 1417 1418 func (s SqlChannelStore) saveMultipleMembers(members []*model.ChannelMember) ([]*model.ChannelMember, error) { 1419 newChannelMembers := map[string]int{} 1420 users := map[string]bool{} 1421 for _, member := range members { 1422 if val, ok := newChannelMembers[member.ChannelId]; val < 1 || !ok { 1423 newChannelMembers[member.ChannelId] = 1 1424 } else { 1425 newChannelMembers[member.ChannelId]++ 1426 } 1427 users[member.UserId] = true 1428 1429 member.PreSave() 1430 if err := member.IsValid(); err != nil { // TODO: this needs to return plain error in v6. 1431 return nil, err 1432 } 1433 } 1434 1435 channels := []string{} 1436 for channel := range newChannelMembers { 1437 channels = append(channels, channel) 1438 } 1439 1440 defaultChannelRolesByChannel := map[string]struct { 1441 Id string 1442 Guest sql.NullString 1443 User sql.NullString 1444 Admin sql.NullString 1445 }{} 1446 1447 channelRolesQuery := s.getQueryBuilder(). 1448 Select( 1449 "Channels.Id as Id", 1450 "ChannelScheme.DefaultChannelGuestRole as Guest", 1451 "ChannelScheme.DefaultChannelUserRole as User", 1452 "ChannelScheme.DefaultChannelAdminRole as Admin", 1453 ). 1454 From("Channels"). 1455 LeftJoin("Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id"). 1456 Where(sq.Eq{"Channels.Id": channels}) 1457 1458 channelRolesSql, channelRolesArgs, err := channelRolesQuery.ToSql() 1459 if err != nil { 1460 return nil, errors.Wrap(err, "channel_roles_tosql") 1461 } 1462 1463 var defaultChannelsRoles []struct { 1464 Id string 1465 Guest sql.NullString 1466 User sql.NullString 1467 Admin sql.NullString 1468 } 1469 _, err = s.GetMaster().Select(&defaultChannelsRoles, channelRolesSql, channelRolesArgs...) 1470 if err != nil { 1471 return nil, errors.Wrap(err, "default_channel_roles_select") 1472 } 1473 1474 for _, defaultRoles := range defaultChannelsRoles { 1475 defaultChannelRolesByChannel[defaultRoles.Id] = defaultRoles 1476 } 1477 1478 defaultTeamRolesByChannel := map[string]struct { 1479 Id string 1480 Guest sql.NullString 1481 User sql.NullString 1482 Admin sql.NullString 1483 }{} 1484 1485 teamRolesQuery := s.getQueryBuilder(). 1486 Select( 1487 "Channels.Id as Id", 1488 "TeamScheme.DefaultChannelGuestRole as Guest", 1489 "TeamScheme.DefaultChannelUserRole as User", 1490 "TeamScheme.DefaultChannelAdminRole as Admin", 1491 ). 1492 From("Channels"). 1493 LeftJoin("Teams ON Teams.Id = Channels.TeamId"). 1494 LeftJoin("Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id"). 1495 Where(sq.Eq{"Channels.Id": channels}) 1496 1497 teamRolesSql, teamRolesArgs, err := teamRolesQuery.ToSql() 1498 if err != nil { 1499 return nil, errors.Wrap(err, "team_roles_tosql") 1500 } 1501 1502 var defaultTeamsRoles []struct { 1503 Id string 1504 Guest sql.NullString 1505 User sql.NullString 1506 Admin sql.NullString 1507 } 1508 _, err = s.GetMaster().Select(&defaultTeamsRoles, teamRolesSql, teamRolesArgs...) 1509 if err != nil { 1510 return nil, errors.Wrap(err, "default_team_roles_select") 1511 } 1512 1513 for _, defaultRoles := range defaultTeamsRoles { 1514 defaultTeamRolesByChannel[defaultRoles.Id] = defaultRoles 1515 } 1516 1517 query := s.getQueryBuilder().Insert("ChannelMembers").Columns(channelMemberSliceColumns()...) 1518 for _, member := range members { 1519 query = query.Values(channelMemberToSlice(member)...) 1520 } 1521 1522 sql, args, err := query.ToSql() 1523 if err != nil { 1524 return nil, errors.Wrap(err, "channel_members_tosql") 1525 } 1526 1527 if _, err := s.GetMaster().Exec(sql, args...); err != nil { 1528 if IsUniqueConstraintError(err, []string{"ChannelId", "channelmembers_pkey", "PRIMARY"}) { 1529 return nil, store.NewErrConflict("ChannelMembers", err, "") 1530 } 1531 return nil, errors.Wrap(err, "channel_members_save") 1532 } 1533 1534 newMembers := []*model.ChannelMember{} 1535 for _, member := range members { 1536 defaultTeamGuestRole := defaultTeamRolesByChannel[member.ChannelId].Guest.String 1537 defaultTeamUserRole := defaultTeamRolesByChannel[member.ChannelId].User.String 1538 defaultTeamAdminRole := defaultTeamRolesByChannel[member.ChannelId].Admin.String 1539 defaultChannelGuestRole := defaultChannelRolesByChannel[member.ChannelId].Guest.String 1540 defaultChannelUserRole := defaultChannelRolesByChannel[member.ChannelId].User.String 1541 defaultChannelAdminRole := defaultChannelRolesByChannel[member.ChannelId].Admin.String 1542 rolesResult := getChannelRoles( 1543 member.SchemeGuest, member.SchemeUser, member.SchemeAdmin, 1544 defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole, 1545 defaultChannelGuestRole, defaultChannelUserRole, defaultChannelAdminRole, 1546 strings.Fields(member.ExplicitRoles), 1547 ) 1548 newMember := *member 1549 newMember.SchemeGuest = rolesResult.schemeGuest 1550 newMember.SchemeUser = rolesResult.schemeUser 1551 newMember.SchemeAdmin = rolesResult.schemeAdmin 1552 newMember.Roles = strings.Join(rolesResult.roles, " ") 1553 newMember.ExplicitRoles = strings.Join(rolesResult.explicitRoles, " ") 1554 newMembers = append(newMembers, &newMember) 1555 } 1556 return newMembers, nil 1557 } 1558 1559 func (s SqlChannelStore) saveMemberT(member *model.ChannelMember) (*model.ChannelMember, error) { 1560 members, err := s.saveMultipleMembers([]*model.ChannelMember{member}) 1561 if err != nil { 1562 return nil, err 1563 } 1564 return members[0], nil 1565 } 1566 1567 func (s SqlChannelStore) UpdateMultipleMembers(members []*model.ChannelMember) ([]*model.ChannelMember, error) { 1568 for _, member := range members { 1569 member.PreUpdate() 1570 1571 if err := member.IsValid(); err != nil { 1572 return nil, err 1573 } 1574 } 1575 1576 var transaction *gorp.Transaction 1577 var err error 1578 1579 if transaction, err = s.GetMaster().Begin(); err != nil { 1580 return nil, errors.Wrap(err, "begin_transaction") 1581 } 1582 defer finalizeTransaction(transaction) 1583 1584 updatedMembers := []*model.ChannelMember{} 1585 for _, member := range members { 1586 if _, err := transaction.Update(NewChannelMemberFromModel(member)); err != nil { 1587 return nil, errors.Wrap(err, "failed to update ChannelMember") 1588 } 1589 1590 // TODO: Get this out of the transaction when is possible 1591 var dbMember channelMemberWithSchemeRoles 1592 if err := transaction.SelectOne(&dbMember, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId", map[string]interface{}{"ChannelId": member.ChannelId, "UserId": member.UserId}); err != nil { 1593 if err == sql.ErrNoRows { 1594 return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", member.ChannelId, member.UserId)) 1595 } 1596 return nil, errors.Wrapf(err, "failed to get ChannelMember with channelId=%s and userId=%s", member.ChannelId, member.UserId) 1597 } 1598 updatedMembers = append(updatedMembers, dbMember.ToModel()) 1599 } 1600 1601 if err := transaction.Commit(); err != nil { 1602 return nil, errors.Wrap(err, "commit_transaction") 1603 } 1604 return updatedMembers, nil 1605 } 1606 1607 func (s SqlChannelStore) UpdateMember(member *model.ChannelMember) (*model.ChannelMember, error) { 1608 updatedMembers, err := s.UpdateMultipleMembers([]*model.ChannelMember{member}) 1609 if err != nil { 1610 return nil, err 1611 } 1612 return updatedMembers[0], nil 1613 } 1614 1615 func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) (*model.ChannelMembers, error) { 1616 var dbMembers channelMemberWithSchemeRolesList 1617 _, err := s.GetReplica().Select(&dbMembers, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelId = :ChannelId LIMIT :Limit OFFSET :Offset", map[string]interface{}{"ChannelId": channelId, "Limit": limit, "Offset": offset}) 1618 if err != nil { 1619 return nil, errors.Wrapf(err, "failed to get ChannelMembers with channelId=%s", channelId) 1620 } 1621 1622 return dbMembers.ToModel(), nil 1623 } 1624 1625 func (s SqlChannelStore) GetChannelMembersTimezones(channelId string) ([]model.StringMap, error) { 1626 var dbMembersTimezone []model.StringMap 1627 _, err := s.GetReplica().Select(&dbMembersTimezone, ` 1628 SELECT 1629 Users.Timezone 1630 FROM 1631 ChannelMembers 1632 LEFT JOIN 1633 Users ON ChannelMembers.UserId = Id 1634 WHERE ChannelId = :ChannelId 1635 `, map[string]interface{}{"ChannelId": channelId}) 1636 1637 if err != nil { 1638 return nil, errors.Wrapf(err, "failed to find user timezones for users in channels with channelId=%s", channelId) 1639 } 1640 1641 return dbMembersTimezone, nil 1642 } 1643 1644 func (s SqlChannelStore) GetMember(channelId string, userId string) (*model.ChannelMember, error) { 1645 var dbMember channelMemberWithSchemeRoles 1646 1647 if err := s.GetReplica().SelectOne(&dbMember, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil { 1648 if err == sql.ErrNoRows { 1649 return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", channelId, userId)) 1650 } 1651 return nil, errors.Wrapf(err, "failed to get ChannelMember with channelId=%s and userId=%s", channelId, userId) 1652 } 1653 1654 return dbMember.ToModel(), nil 1655 } 1656 1657 func (s SqlChannelStore) InvalidateAllChannelMembersForUser(userId string) { 1658 allChannelMembersForUserCache.Remove(userId) 1659 allChannelMembersForUserCache.Remove(userId + "_deleted") 1660 if s.metrics != nil { 1661 s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members for User - Remove by UserId") 1662 } 1663 } 1664 1665 func (s SqlChannelStore) IsUserInChannelUseCache(userId string, channelId string) bool { 1666 var ids map[string]string 1667 if err := allChannelMembersForUserCache.Get(userId, &ids); err == nil { 1668 if s.metrics != nil { 1669 s.metrics.IncrementMemCacheHitCounter("All Channel Members for User") 1670 } 1671 if _, ok := ids[channelId]; ok { 1672 return true 1673 } 1674 return false 1675 } 1676 1677 if s.metrics != nil { 1678 s.metrics.IncrementMemCacheMissCounter("All Channel Members for User") 1679 } 1680 1681 ids, err := s.GetAllChannelMembersForUser(userId, true, false) 1682 if err != nil { 1683 mlog.Error("Error getting all channel members for user", mlog.Err(err)) 1684 return false 1685 } 1686 1687 if _, ok := ids[channelId]; ok { 1688 return true 1689 } 1690 1691 return false 1692 } 1693 1694 func (s SqlChannelStore) GetMemberForPost(postId string, userId string) (*model.ChannelMember, error) { 1695 var dbMember channelMemberWithSchemeRoles 1696 query := ` 1697 SELECT 1698 ChannelMembers.*, 1699 TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole, 1700 TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole, 1701 TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole, 1702 ChannelScheme.DefaultChannelGuestRole ChannelSchemeDefaultGuestRole, 1703 ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole, 1704 ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole 1705 FROM 1706 ChannelMembers 1707 INNER JOIN 1708 Posts ON ChannelMembers.ChannelId = Posts.ChannelId 1709 INNER JOIN 1710 Channels ON ChannelMembers.ChannelId = Channels.Id 1711 LEFT JOIN 1712 Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id 1713 LEFT JOIN 1714 Teams ON Channels.TeamId = Teams.Id 1715 LEFT JOIN 1716 Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id 1717 WHERE 1718 ChannelMembers.UserId = :UserId 1719 AND 1720 Posts.Id = :PostId` 1721 if err := s.GetReplica().SelectOne(&dbMember, query, map[string]interface{}{"UserId": userId, "PostId": postId}); err != nil { 1722 return nil, errors.Wrapf(err, "failed to get ChannelMember with postId=%s and userId=%s", postId, userId) 1723 } 1724 return dbMember.ToModel(), nil 1725 } 1726 1727 func (s SqlChannelStore) GetAllChannelMembersForUser(userId string, allowFromCache bool, includeDeleted bool) (map[string]string, error) { 1728 cache_key := userId 1729 if includeDeleted { 1730 cache_key += "_deleted" 1731 } 1732 if allowFromCache { 1733 var ids map[string]string 1734 if err := allChannelMembersForUserCache.Get(cache_key, &ids); err == nil { 1735 if s.metrics != nil { 1736 s.metrics.IncrementMemCacheHitCounter("All Channel Members for User") 1737 } 1738 return ids, nil 1739 } 1740 } 1741 1742 if s.metrics != nil { 1743 s.metrics.IncrementMemCacheMissCounter("All Channel Members for User") 1744 } 1745 1746 query := s.getQueryBuilder(). 1747 Select(` 1748 ChannelMembers.ChannelId, ChannelMembers.Roles, ChannelMembers.SchemeGuest, 1749 ChannelMembers.SchemeUser, ChannelMembers.SchemeAdmin, 1750 TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole, 1751 TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole, 1752 TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole, 1753 ChannelScheme.DefaultChannelGuestRole ChannelSchemeDefaultGuestRole, 1754 ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole, 1755 ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole 1756 `). 1757 From("ChannelMembers"). 1758 Join("Channels ON ChannelMembers.ChannelId = Channels.Id"). 1759 LeftJoin("Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id"). 1760 LeftJoin("Teams ON Channels.TeamId = Teams.Id"). 1761 LeftJoin("Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id"). 1762 Where(sq.Eq{"ChannelMembers.UserId": userId}) 1763 if !includeDeleted { 1764 query = query.Where(sq.Eq{"Channels.DeleteAt": 0}) 1765 } 1766 queryString, args, err := query.ToSql() 1767 if err != nil { 1768 return nil, errors.Wrap(err, "channel_tosql") 1769 } 1770 1771 rows, err := s.GetReplica().Db.Query(queryString, args...) 1772 if err != nil { 1773 return nil, errors.Wrap(err, "failed to find ChannelMembers, TeamScheme and ChannelScheme data") 1774 } 1775 1776 var data allChannelMembers 1777 defer rows.Close() 1778 for rows.Next() { 1779 var cm allChannelMember 1780 err = rows.Scan( 1781 &cm.ChannelId, &cm.Roles, &cm.SchemeGuest, &cm.SchemeUser, 1782 &cm.SchemeAdmin, &cm.TeamSchemeDefaultGuestRole, &cm.TeamSchemeDefaultUserRole, 1783 &cm.TeamSchemeDefaultAdminRole, &cm.ChannelSchemeDefaultGuestRole, 1784 &cm.ChannelSchemeDefaultUserRole, &cm.ChannelSchemeDefaultAdminRole, 1785 ) 1786 if err != nil { 1787 return nil, errors.Wrap(err, "unable to scan columns") 1788 } 1789 data = append(data, cm) 1790 } 1791 if err = rows.Err(); err != nil { 1792 return nil, errors.Wrap(err, "error while iterating over rows") 1793 } 1794 ids := data.ToMapStringString() 1795 1796 if allowFromCache { 1797 allChannelMembersForUserCache.SetWithExpiry(cache_key, ids, AllChannelMembersForUserCacheDuration) 1798 } 1799 return ids, nil 1800 } 1801 1802 func (s SqlChannelStore) InvalidateCacheForChannelMembersNotifyProps(channelId string) { 1803 allChannelMembersNotifyPropsForChannelCache.Remove(channelId) 1804 if s.metrics != nil { 1805 s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members Notify Props for Channel - Remove by ChannelId") 1806 } 1807 } 1808 1809 type allChannelMemberNotifyProps struct { 1810 UserId string 1811 NotifyProps model.StringMap 1812 } 1813 1814 func (s SqlChannelStore) GetAllChannelMembersNotifyPropsForChannel(channelId string, allowFromCache bool) (map[string]model.StringMap, error) { 1815 if allowFromCache { 1816 var cacheItem map[string]model.StringMap 1817 if err := allChannelMembersNotifyPropsForChannelCache.Get(channelId, &cacheItem); err == nil { 1818 if s.metrics != nil { 1819 s.metrics.IncrementMemCacheHitCounter("All Channel Members Notify Props for Channel") 1820 } 1821 return cacheItem, nil 1822 } 1823 } 1824 1825 if s.metrics != nil { 1826 s.metrics.IncrementMemCacheMissCounter("All Channel Members Notify Props for Channel") 1827 } 1828 1829 var data []allChannelMemberNotifyProps 1830 _, err := s.GetReplica().Select(&data, ` 1831 SELECT UserId, NotifyProps 1832 FROM ChannelMembers 1833 WHERE ChannelId = :ChannelId`, map[string]interface{}{"ChannelId": channelId}) 1834 1835 if err != nil { 1836 return nil, errors.Wrapf(err, "failed to find data from ChannelMembers with channelId=%s", channelId) 1837 } 1838 1839 props := make(map[string]model.StringMap) 1840 for i := range data { 1841 props[data[i].UserId] = data[i].NotifyProps 1842 } 1843 1844 allChannelMembersNotifyPropsForChannelCache.SetWithExpiry(channelId, props, AllChannelMembersNotifyPropsForChannelCacheDuration) 1845 1846 return props, nil 1847 } 1848 1849 //nolint:unparam 1850 func (s SqlChannelStore) InvalidateMemberCount(channelId string) { 1851 } 1852 1853 func (s SqlChannelStore) GetMemberCountFromCache(channelId string) int64 { 1854 count, _ := s.GetMemberCount(channelId, true) 1855 return count 1856 } 1857 1858 //nolint:unparam 1859 func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) (int64, error) { 1860 count, err := s.GetReplica().SelectInt(` 1861 SELECT 1862 count(*) 1863 FROM 1864 ChannelMembers, 1865 Users 1866 WHERE 1867 ChannelMembers.UserId = Users.Id 1868 AND ChannelMembers.ChannelId = :ChannelId 1869 AND Users.DeleteAt = 0`, map[string]interface{}{"ChannelId": channelId}) 1870 if err != nil { 1871 return 0, errors.Wrapf(err, "failed to count ChanenelMembers with channelId=%s", channelId) 1872 } 1873 1874 return count, nil 1875 } 1876 1877 // GetMemberCountsByGroup returns a slice of ChannelMemberCountByGroup for a given channel 1878 // which contains the number of channel members for each group and optionally the number of unique timezones present for each group in the channel 1879 func (s SqlChannelStore) GetMemberCountsByGroup(channelID string, includeTimezones bool) ([]*model.ChannelMemberCountByGroup, error) { 1880 selectStr := "GroupMembers.GroupId, COUNT(ChannelMembers.UserId) AS ChannelMemberCount" 1881 1882 if includeTimezones { 1883 // Length of default timezone (len {"automaticTimezone":"","manualTimezone":"","useAutomaticTimezone":"true"}) 1884 defaultTimezoneLength := `74` 1885 1886 // Beginning and end of the value for the automatic and manual timezones respectively 1887 autoTimezone := `LOCATE(':', Users.Timezone) + 2` 1888 autoTimezoneEnd := `LOCATE(',', Users.Timezone) - LOCATE(':', Users.Timezone) - 3` 1889 manualTimezone := `LOCATE(',', Users.Timezone) + 19` 1890 manualTimezoneEnd := `LOCATE('useAutomaticTimezone', Users.Timezone) - 22 - LOCATE(',', Users.Timezone)` 1891 1892 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 1893 autoTimezone = `POSITION(':' IN Users.Timezone) + 2` 1894 autoTimezoneEnd = `POSITION(',' IN Users.Timezone) - POSITION(':' IN Users.Timezone) - 3` 1895 manualTimezone = `POSITION(',' IN Users.Timezone) + 19` 1896 manualTimezoneEnd = `POSITION('useAutomaticTimezone' IN Users.Timezone) - 22 - POSITION(',' IN Users.Timezone)` 1897 } 1898 1899 selectStr = ` 1900 GroupMembers.GroupId, 1901 COUNT(ChannelMembers.UserId) AS ChannelMemberCount, 1902 COUNT(DISTINCT 1903 ( 1904 CASE WHEN Timezone like '%"useAutomaticTimezone":"true"}' AND LENGTH(Timezone) > ` + defaultTimezoneLength + ` 1905 THEN 1906 SUBSTRING( 1907 Timezone 1908 FROM ` + autoTimezone + ` 1909 FOR ` + autoTimezoneEnd + ` 1910 ) 1911 WHEN Timezone like '%"useAutomaticTimezone":"false"}' AND LENGTH(Timezone) > ` + defaultTimezoneLength + ` 1912 THEN 1913 SUBSTRING( 1914 Timezone 1915 FROM ` + manualTimezone + ` 1916 FOR ` + manualTimezoneEnd + ` 1917 ) 1918 END 1919 ) 1920 ) AS ChannelMemberTimezonesCount 1921 ` 1922 } 1923 1924 query := s.getQueryBuilder(). 1925 Select(selectStr). 1926 From("ChannelMembers"). 1927 Join("GroupMembers ON GroupMembers.UserId = ChannelMembers.UserId") 1928 1929 if includeTimezones { 1930 query = query.Join("Users ON Users.Id = GroupMembers.UserId") 1931 } 1932 1933 query = query.Where(sq.Eq{"ChannelMembers.ChannelId": channelID}).GroupBy("GroupMembers.GroupId") 1934 1935 queryString, args, err := query.ToSql() 1936 if err != nil { 1937 return nil, errors.Wrap(err, "channel_tosql") 1938 } 1939 var data []*model.ChannelMemberCountByGroup 1940 if _, err = s.GetReplica().Select(&data, queryString, args...); err != nil { 1941 return nil, errors.Wrapf(err, "failed to count ChannelMembers with channelId=%s", channelID) 1942 } 1943 1944 return data, nil 1945 } 1946 1947 //nolint:unparam 1948 func (s SqlChannelStore) InvalidatePinnedPostCount(channelId string) { 1949 } 1950 1951 //nolint:unparam 1952 func (s SqlChannelStore) GetPinnedPostCount(channelId string, allowFromCache bool) (int64, error) { 1953 count, err := s.GetReplica().SelectInt(` 1954 SELECT count(*) 1955 FROM Posts 1956 WHERE 1957 IsPinned = true 1958 AND ChannelId = :ChannelId 1959 AND DeleteAt = 0`, map[string]interface{}{"ChannelId": channelId}) 1960 1961 if err != nil { 1962 return 0, errors.Wrapf(err, "failed to count pinned Posts with channelId=%s", channelId) 1963 } 1964 1965 return count, nil 1966 } 1967 1968 //nolint:unparam 1969 func (s SqlChannelStore) InvalidateGuestCount(channelId string) { 1970 } 1971 1972 //nolint:unparam 1973 func (s SqlChannelStore) GetGuestCount(channelId string, allowFromCache bool) (int64, error) { 1974 count, err := s.GetReplica().SelectInt(` 1975 SELECT 1976 count(*) 1977 FROM 1978 ChannelMembers, 1979 Users 1980 WHERE 1981 ChannelMembers.UserId = Users.Id 1982 AND ChannelMembers.ChannelId = :ChannelId 1983 AND ChannelMembers.SchemeGuest = TRUE 1984 AND Users.DeleteAt = 0`, map[string]interface{}{"ChannelId": channelId}) 1985 if err != nil { 1986 return 0, errors.Wrapf(err, "failed to count Guests with channelId=%s", channelId) 1987 } 1988 return count, nil 1989 } 1990 1991 func (s SqlChannelStore) RemoveMembers(channelId string, userIds []string) error { 1992 builder := s.getQueryBuilder(). 1993 Delete("ChannelMembers"). 1994 Where(sq.Eq{"ChannelId": channelId}). 1995 Where(sq.Eq{"UserId": userIds}) 1996 query, args, err := builder.ToSql() 1997 if err != nil { 1998 return errors.Wrap(err, "channel_tosql") 1999 } 2000 _, err = s.GetMaster().Exec(query, args...) 2001 if err != nil { 2002 return errors.Wrap(err, "failed to delete ChannelMembers") 2003 } 2004 2005 // cleanup sidebarchannels table if the user is no longer a member of that channel 2006 query, args, err = s.getQueryBuilder(). 2007 Delete("SidebarChannels"). 2008 Where(sq.And{ 2009 sq.Eq{"ChannelId": channelId}, 2010 sq.Eq{"UserId": userIds}, 2011 }).ToSql() 2012 if err != nil { 2013 return errors.Wrap(err, "channel_tosql") 2014 } 2015 _, err = s.GetMaster().Exec(query, args...) 2016 if err != nil { 2017 return errors.Wrap(err, "failed to delete SidebarChannels") 2018 } 2019 return nil 2020 } 2021 2022 func (s SqlChannelStore) RemoveMember(channelId string, userId string) error { 2023 return s.RemoveMembers(channelId, []string{userId}) 2024 } 2025 2026 func (s SqlChannelStore) RemoveAllDeactivatedMembers(channelId string) error { 2027 query := ` 2028 DELETE 2029 FROM 2030 ChannelMembers 2031 WHERE 2032 UserId IN ( 2033 SELECT 2034 Id 2035 FROM 2036 Users 2037 WHERE 2038 Users.DeleteAt != 0 2039 ) 2040 AND 2041 ChannelMembers.ChannelId = :ChannelId 2042 ` 2043 2044 _, err := s.GetMaster().Exec(query, map[string]interface{}{"ChannelId": channelId}) 2045 if err != nil { 2046 return errors.Wrapf(err, "failed to delete ChannelMembers with channelId=%s", channelId) 2047 } 2048 return nil 2049 } 2050 2051 func (s SqlChannelStore) PermanentDeleteMembersByUser(userId string) error { 2052 if _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil { 2053 return errors.Wrapf(err, "failed to permanent delete ChannelMembers with userId=%s", userId) 2054 } 2055 return nil 2056 } 2057 2058 func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string, updateThreads bool) (map[string]int64, error) { 2059 var threadsToUpdate []string 2060 now := model.GetMillis() 2061 if updateThreads { 2062 var err error 2063 threadsToUpdate, err = s.Thread().CollectThreadsWithNewerReplies(userId, channelIds, now) 2064 if err != nil { 2065 return nil, err 2066 } 2067 } 2068 2069 keys, props := MapStringsToQueryParams(channelIds, "Channel") 2070 props["UserId"] = userId 2071 2072 var lastPostAtTimes []struct { 2073 Id string 2074 LastPostAt int64 2075 TotalMsgCount int64 2076 } 2077 2078 query := `SELECT Id, LastPostAt, TotalMsgCount FROM Channels WHERE Id IN ` + keys 2079 // TODO: use a CTE for mysql too when version 8 becomes the minimum supported version. 2080 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 2081 query = `WITH c AS ( ` + query + `), 2082 updated AS ( 2083 UPDATE 2084 ChannelMembers cm 2085 SET 2086 MentionCount = 0, 2087 MsgCount = greatest(cm.MsgCount, c.TotalMsgCount), 2088 LastViewedAt = greatest(cm.LastViewedAt, c.LastPostAt), 2089 LastUpdateAt = greatest(cm.LastViewedAt, c.LastPostAt) 2090 FROM c 2091 WHERE cm.UserId = :UserId 2092 AND c.Id=cm.ChannelId 2093 ) 2094 SELECT Id, LastPostAt FROM c` 2095 } 2096 2097 _, err := s.GetMaster().Select(&lastPostAtTimes, query, props) 2098 if err != nil { 2099 return nil, errors.Wrapf(err, "failed to find ChannelMembers data with userId=%s and channelId in %v", userId, channelIds) 2100 } 2101 2102 if len(lastPostAtTimes) == 0 { 2103 return nil, store.NewErrInvalidInput("Channel", "Id", fmt.Sprintf("%v", channelIds)) 2104 } 2105 2106 times := map[string]int64{} 2107 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 2108 for _, t := range lastPostAtTimes { 2109 times[t.Id] = t.LastPostAt 2110 } 2111 if updateThreads { 2112 s.Thread().UpdateUnreadsByChannel(userId, threadsToUpdate, now, true) 2113 } 2114 return times, nil 2115 } 2116 2117 msgCountQuery := "" 2118 lastViewedQuery := "" 2119 2120 for index, t := range lastPostAtTimes { 2121 times[t.Id] = t.LastPostAt 2122 2123 props["msgCount"+strconv.Itoa(index)] = t.TotalMsgCount 2124 msgCountQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(MsgCount, :msgCount%d) ", index, index) 2125 2126 props["lastViewed"+strconv.Itoa(index)] = t.LastPostAt 2127 lastViewedQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(LastViewedAt, :lastViewed%d) ", index, index) 2128 2129 props["channelId"+strconv.Itoa(index)] = t.Id 2130 } 2131 2132 updateQuery := `UPDATE 2133 ChannelMembers 2134 SET 2135 MentionCount = 0, 2136 MsgCount = CASE ChannelId ` + msgCountQuery + ` END, 2137 LastViewedAt = CASE ChannelId ` + lastViewedQuery + ` END, 2138 LastUpdateAt = LastViewedAt 2139 WHERE 2140 UserId = :UserId 2141 AND ChannelId IN ` + keys 2142 2143 if _, err := s.GetMaster().Exec(updateQuery, props); err != nil { 2144 return nil, errors.Wrapf(err, "failed to update ChannelMembers with userId=%s and channelId in %v", userId, channelIds) 2145 } 2146 2147 if updateThreads { 2148 s.Thread().UpdateUnreadsByChannel(userId, threadsToUpdate, now, true) 2149 } 2150 return times, nil 2151 } 2152 2153 // CountPostsAfter returns the number of posts in the given channel created after but not including the given timestamp. If given a non-empty user ID, only counts posts made by that user. 2154 func (s SqlChannelStore) CountPostsAfter(channelId string, timestamp int64, userId string) (int, error) { 2155 joinLeavePostTypes, params := MapStringsToQueryParams([]string{ 2156 // These types correspond to the ones checked by Post.IsJoinLeaveMessage 2157 model.POST_JOIN_LEAVE, 2158 model.POST_ADD_REMOVE, 2159 model.POST_JOIN_CHANNEL, 2160 model.POST_LEAVE_CHANNEL, 2161 model.POST_JOIN_TEAM, 2162 model.POST_LEAVE_TEAM, 2163 model.POST_ADD_TO_CHANNEL, 2164 model.POST_REMOVE_FROM_CHANNEL, 2165 model.POST_ADD_TO_TEAM, 2166 model.POST_REMOVE_FROM_TEAM, 2167 }, "PostType") 2168 2169 query := ` 2170 SELECT count(*) 2171 FROM Posts 2172 WHERE 2173 ChannelId = :ChannelId 2174 AND CreateAt > :CreateAt 2175 AND Type NOT IN ` + joinLeavePostTypes + ` 2176 AND DeleteAt = 0 2177 ` 2178 2179 params["ChannelId"] = channelId 2180 params["CreateAt"] = timestamp 2181 2182 if userId != "" { 2183 query += " AND UserId = :UserId" 2184 params["UserId"] = userId 2185 } 2186 2187 unread, err := s.GetReplica().SelectInt(query, params) 2188 if err != nil { 2189 return 0, errors.Wrap(err, "failed to count Posts") 2190 } 2191 return int(unread), nil 2192 } 2193 2194 // UpdateLastViewedAtPost updates a ChannelMember as if the user last read the channel at the time of the given post. 2195 // If the provided mentionCount is -1, the given post and all posts after it are considered to be mentions. Returns 2196 // an updated model.ChannelUnreadAt that can be returned to the client. 2197 func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, updateThreads bool) (*model.ChannelUnreadAt, error) { 2198 var threadsToUpdate []string 2199 unreadDate := unreadPost.CreateAt - 1 2200 if updateThreads { 2201 var err error 2202 threadsToUpdate, err = s.Thread().CollectThreadsWithNewerReplies(userID, []string{unreadPost.ChannelId}, unreadDate) 2203 if err != nil { 2204 return nil, err 2205 } 2206 } 2207 2208 unread, err := s.CountPostsAfter(unreadPost.ChannelId, unreadDate, "") 2209 if err != nil { 2210 return nil, err 2211 } 2212 2213 params := map[string]interface{}{ 2214 "mentions": mentionCount, 2215 "unreadCount": unread, 2216 "lastViewedAt": unreadDate, 2217 "userId": userID, 2218 "channelId": unreadPost.ChannelId, 2219 "updatedAt": model.GetMillis(), 2220 } 2221 2222 // msg count uses the value from channels to prevent counting on older channels where no. of messages can be high. 2223 // we only count the unread which will be a lot less in 99% cases 2224 setUnreadQuery := ` 2225 UPDATE 2226 ChannelMembers 2227 SET 2228 MentionCount = :mentions, 2229 MsgCount = (SELECT TotalMsgCount FROM Channels WHERE ID = :channelId) - :unreadCount, 2230 LastViewedAt = :lastViewedAt, 2231 LastUpdateAt = :updatedAt 2232 WHERE 2233 UserId = :userId 2234 AND ChannelId = :channelId 2235 ` 2236 _, err = s.GetMaster().Exec(setUnreadQuery, params) 2237 if err != nil { 2238 return nil, errors.Wrap(err, "failed to update ChannelMembers") 2239 } 2240 2241 chanUnreadQuery := ` 2242 SELECT 2243 c.TeamId TeamId, 2244 cm.UserId UserId, 2245 cm.ChannelId ChannelId, 2246 cm.MsgCount MsgCount, 2247 cm.MentionCount MentionCount, 2248 cm.LastViewedAt LastViewedAt, 2249 cm.NotifyProps NotifyProps 2250 FROM 2251 ChannelMembers cm 2252 LEFT JOIN Channels c ON c.Id=cm.ChannelId 2253 WHERE 2254 cm.UserId = :userId 2255 AND cm.channelId = :channelId 2256 AND c.DeleteAt = 0 2257 ` 2258 result := &model.ChannelUnreadAt{} 2259 if err = s.GetMaster().SelectOne(result, chanUnreadQuery, params); err != nil { 2260 return nil, errors.Wrapf(err, "failed to get ChannelMember with channelId=%s", unreadPost.ChannelId) 2261 } 2262 2263 if updateThreads { 2264 s.Thread().UpdateUnreadsByChannel(userID, threadsToUpdate, unreadDate, true) 2265 } 2266 return result, nil 2267 } 2268 2269 func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string, updateThreads bool) error { 2270 now := model.GetMillis() 2271 var threadsToUpdate []string 2272 if updateThreads { 2273 var err error 2274 threadsToUpdate, err = s.Thread().CollectThreadsWithNewerReplies(userId, []string{channelId}, now) 2275 if err != nil { 2276 return err 2277 } 2278 } 2279 2280 _, err := s.GetMaster().Exec( 2281 `UPDATE 2282 ChannelMembers 2283 SET 2284 MentionCount = MentionCount + 1, 2285 LastUpdateAt = :LastUpdateAt 2286 WHERE 2287 UserId = :UserId 2288 AND ChannelId = :ChannelId`, 2289 map[string]interface{}{"ChannelId": channelId, "UserId": userId, "LastUpdateAt": now}) 2290 if err != nil { 2291 return errors.Wrapf(err, "failed to Update ChannelMembers with channelId=%s and userId=%s", channelId, userId) 2292 } 2293 if updateThreads { 2294 s.Thread().UpdateUnreadsByChannel(userId, threadsToUpdate, now, false) 2295 } 2296 return nil 2297 } 2298 2299 func (s SqlChannelStore) GetAll(teamId string) ([]*model.Channel, error) { 2300 var data []*model.Channel 2301 _, err := s.GetReplica().Select(&data, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Type != 'D' ORDER BY Name", map[string]interface{}{"TeamId": teamId}) 2302 2303 if err != nil { 2304 return nil, errors.Wrapf(err, "failed to find Channels with teamId=%s", teamId) 2305 } 2306 2307 return data, nil 2308 } 2309 2310 func (s SqlChannelStore) GetChannelsByIds(channelIds []string, includeDeleted bool) ([]*model.Channel, error) { 2311 keys, params := MapStringsToQueryParams(channelIds, "Channel") 2312 query := `SELECT * FROM Channels WHERE Id IN ` + keys + ` ORDER BY Name` 2313 if !includeDeleted { 2314 query = `SELECT * FROM Channels WHERE DeleteAt=0 AND Id IN ` + keys + ` ORDER BY Name` 2315 } 2316 2317 var channels []*model.Channel 2318 _, err := s.GetReplica().Select(&channels, query, params) 2319 2320 if err != nil { 2321 return nil, errors.Wrap(err, "failed to find Channels") 2322 } 2323 return channels, nil 2324 } 2325 2326 func (s SqlChannelStore) GetForPost(postId string) (*model.Channel, error) { 2327 channel := &model.Channel{} 2328 if err := s.GetReplica().SelectOne( 2329 channel, 2330 `SELECT 2331 Channels.* 2332 FROM 2333 Channels, 2334 Posts 2335 WHERE 2336 Channels.Id = Posts.ChannelId 2337 AND Posts.Id = :PostId`, map[string]interface{}{"PostId": postId}); err != nil { 2338 return nil, errors.Wrapf(err, "failed to get Channel with postId=%s", postId) 2339 2340 } 2341 return channel, nil 2342 } 2343 2344 func (s SqlChannelStore) AnalyticsTypeCount(teamId string, channelType string) (int64, error) { 2345 query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType" 2346 2347 if teamId != "" { 2348 query += " AND TeamId = :TeamId" 2349 } 2350 2351 value, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId, "ChannelType": channelType}) 2352 if err != nil { 2353 return int64(0), errors.Wrap(err, "failed to count Channels") 2354 } 2355 return value, nil 2356 } 2357 2358 func (s SqlChannelStore) AnalyticsDeletedTypeCount(teamId string, channelType string) (int64, error) { 2359 query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType AND DeleteAt > 0" 2360 2361 if teamId != "" { 2362 query += " AND TeamId = :TeamId" 2363 } 2364 2365 v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId, "ChannelType": channelType}) 2366 if err != nil { 2367 return 0, errors.Wrapf(err, "failed to count Channels with teamId=%s and channelType=%s", teamId, channelType) 2368 } 2369 2370 return v, nil 2371 } 2372 2373 func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) (*model.ChannelMembers, error) { 2374 var dbMembers channelMemberWithSchemeRolesList 2375 _, err := s.GetReplica().Select(&dbMembers, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.UserId = :UserId AND (Teams.Id = :TeamId OR Teams.Id = '' OR Teams.Id IS NULL)", map[string]interface{}{"TeamId": teamId, "UserId": userId}) 2376 if err != nil { 2377 return nil, errors.Wrapf(err, "failed to find ChannelMembers data with teamId=%s and userId=%s", teamId, userId) 2378 } 2379 2380 return dbMembers.ToModel(), nil 2381 } 2382 2383 func (s SqlChannelStore) GetMembersForUserWithPagination(teamId, userId string, page, perPage int) (*model.ChannelMembers, error) { 2384 var dbMembers channelMemberWithSchemeRolesList 2385 offset := page * perPage 2386 _, err := s.GetReplica().Select(&dbMembers, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.UserId = :UserId Limit :Limit Offset :Offset", map[string]interface{}{"TeamId": teamId, "UserId": userId, "Limit": perPage, "Offset": offset}) 2387 2388 if err != nil { 2389 return nil, errors.Wrapf(err, "failed to find ChannelMembers data with teamId=%s and userId=%s", teamId, userId) 2390 } 2391 2392 return dbMembers.ToModel(), nil 2393 } 2394 2395 func (s SqlChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) (*model.ChannelList, error) { 2396 deleteFilter := "AND Channels.DeleteAt = 0" 2397 if includeDeleted { 2398 deleteFilter = "" 2399 } 2400 2401 queryFormat := ` 2402 SELECT 2403 Channels.* 2404 FROM 2405 Channels 2406 JOIN 2407 PublicChannels c ON (c.Id = Channels.Id) 2408 WHERE 2409 Channels.TeamId = :TeamId 2410 ` + deleteFilter + ` 2411 %v 2412 LIMIT ` + strconv.Itoa(model.CHANNEL_SEARCH_DEFAULT_LIMIT) 2413 2414 var channels model.ChannelList 2415 2416 if likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose"); likeClause == "" { 2417 if _, err := s.GetReplica().Select(&channels, fmt.Sprintf(queryFormat, ""), map[string]interface{}{"TeamId": teamId}); err != nil { 2418 return nil, errors.Wrapf(err, "failed to find Channels with term='%s'", term) 2419 } 2420 } else { 2421 // Using a UNION results in index_merge and fulltext queries and is much faster than the ref 2422 // query you would get using an OR of the LIKE and full-text clauses. 2423 fulltextClause, fulltextTerm := s.buildFulltextClause(term, "c.Name, c.DisplayName, c.Purpose") 2424 likeQuery := fmt.Sprintf(queryFormat, "AND "+likeClause) 2425 fulltextQuery := fmt.Sprintf(queryFormat, "AND "+fulltextClause) 2426 query := fmt.Sprintf("(%v) UNION (%v) LIMIT 50", likeQuery, fulltextQuery) 2427 2428 if _, err := s.GetReplica().Select(&channels, query, map[string]interface{}{"TeamId": teamId, "LikeTerm": likeTerm, "FulltextTerm": fulltextTerm}); err != nil { 2429 return nil, errors.Wrapf(err, "failed to find Channels with term='%s'", term) 2430 } 2431 } 2432 2433 sort.Slice(channels, func(a, b int) bool { 2434 return strings.ToLower(channels[a].DisplayName) < strings.ToLower(channels[b].DisplayName) 2435 }) 2436 return &channels, nil 2437 } 2438 2439 func (s SqlChannelStore) AutocompleteInTeamForSearch(teamId string, userId string, term string, includeDeleted bool) (*model.ChannelList, error) { 2440 deleteFilter := "AND DeleteAt = 0" 2441 if includeDeleted { 2442 deleteFilter = "" 2443 } 2444 2445 queryFormat := ` 2446 SELECT 2447 C.* 2448 FROM 2449 Channels AS C 2450 JOIN 2451 ChannelMembers AS CM ON CM.ChannelId = C.Id 2452 WHERE 2453 (C.TeamId = :TeamId OR (C.TeamId = '' AND C.Type = 'G')) 2454 AND CM.UserId = :UserId 2455 ` + deleteFilter + ` 2456 %v 2457 LIMIT 50` 2458 2459 var channels model.ChannelList 2460 2461 if likeClause, likeTerm := s.buildLIKEClause(term, "Name, DisplayName, Purpose"); likeClause == "" { 2462 if _, err := s.GetReplica().Select(&channels, fmt.Sprintf(queryFormat, ""), map[string]interface{}{"TeamId": teamId, "UserId": userId}); err != nil { 2463 return nil, errors.Wrapf(err, "failed to find Channels with term='%s'", term) 2464 } 2465 } else { 2466 // Using a UNION results in index_merge and fulltext queries and is much faster than the ref 2467 // query you would get using an OR of the LIKE and full-text clauses. 2468 fulltextClause, fulltextTerm := s.buildFulltextClause(term, "Name, DisplayName, Purpose") 2469 likeQuery := fmt.Sprintf(queryFormat, "AND "+likeClause) 2470 fulltextQuery := fmt.Sprintf(queryFormat, "AND "+fulltextClause) 2471 query := fmt.Sprintf("(%v) UNION (%v) LIMIT 50", likeQuery, fulltextQuery) 2472 2473 if _, err := s.GetReplica().Select(&channels, query, map[string]interface{}{"TeamId": teamId, "UserId": userId, "LikeTerm": likeTerm, "FulltextTerm": fulltextTerm}); err != nil { 2474 return nil, errors.Wrapf(err, "failed to find Channels with term='%s'", term) 2475 } 2476 } 2477 2478 directChannels, err := s.autocompleteInTeamForSearchDirectMessages(userId, term) 2479 if err != nil { 2480 return nil, err 2481 } 2482 2483 channels = append(channels, directChannels...) 2484 2485 sort.Slice(channels, func(a, b int) bool { 2486 return strings.ToLower(channels[a].DisplayName) < strings.ToLower(channels[b].DisplayName) 2487 }) 2488 return &channels, nil 2489 } 2490 2491 func (s SqlChannelStore) autocompleteInTeamForSearchDirectMessages(userId string, term string) ([]*model.Channel, error) { 2492 queryFormat := ` 2493 SELECT 2494 C.*, 2495 OtherUsers.Username as DisplayName 2496 FROM 2497 Channels AS C 2498 JOIN 2499 ChannelMembers AS CM ON CM.ChannelId = C.Id 2500 INNER JOIN ( 2501 SELECT 2502 ICM.ChannelId AS ChannelId, IU.Username AS Username 2503 FROM 2504 Users as IU 2505 JOIN 2506 ChannelMembers AS ICM ON ICM.UserId = IU.Id 2507 WHERE 2508 IU.Id != :UserId 2509 %v 2510 ) AS OtherUsers ON OtherUsers.ChannelId = C.Id 2511 WHERE 2512 C.Type = 'D' 2513 AND CM.UserId = :UserId 2514 LIMIT 50` 2515 2516 var channels model.ChannelList 2517 2518 if likeClause, likeTerm := s.buildLIKEClause(term, "IU.Username, IU.Nickname"); likeClause == "" { 2519 if _, err := s.GetReplica().Select(&channels, fmt.Sprintf(queryFormat, ""), map[string]interface{}{"UserId": userId}); err != nil { 2520 return nil, errors.Wrapf(err, "failed to find Channels with term='%s'", term) 2521 } 2522 } else { 2523 query := fmt.Sprintf(queryFormat, "AND "+likeClause) 2524 2525 if _, err := s.GetReplica().Select(&channels, query, map[string]interface{}{"UserId": userId, "LikeTerm": likeTerm}); err != nil { 2526 return nil, errors.Wrapf(err, "failed to find Channels with term='%s'", term) 2527 } 2528 } 2529 2530 return channels, nil 2531 } 2532 2533 func (s SqlChannelStore) SearchInTeam(teamId string, term string, includeDeleted bool) (*model.ChannelList, error) { 2534 deleteFilter := "AND c.DeleteAt = 0" 2535 if includeDeleted { 2536 deleteFilter = "" 2537 } 2538 2539 return s.performSearch(` 2540 SELECT 2541 Channels.* 2542 FROM 2543 Channels 2544 JOIN 2545 PublicChannels c ON (c.Id = Channels.Id) 2546 WHERE 2547 c.TeamId = :TeamId 2548 `+deleteFilter+` 2549 SEARCH_CLAUSE 2550 ORDER BY c.DisplayName 2551 LIMIT 100 2552 `, term, map[string]interface{}{ 2553 "TeamId": teamId, 2554 }) 2555 } 2556 2557 func (s SqlChannelStore) SearchArchivedInTeam(teamId string, term string, userId string) (*model.ChannelList, error) { 2558 publicChannels, publicErr := s.performSearch(` 2559 SELECT 2560 Channels.* 2561 FROM 2562 Channels 2563 JOIN 2564 Channels c ON (c.Id = Channels.Id) 2565 WHERE 2566 c.TeamId = :TeamId 2567 SEARCH_CLAUSE 2568 AND c.DeleteAt != 0 2569 AND c.Type != 'P' 2570 ORDER BY c.DisplayName 2571 LIMIT 100 2572 `, term, map[string]interface{}{ 2573 "TeamId": teamId, 2574 "UserId": userId, 2575 }) 2576 2577 privateChannels, privateErr := s.performSearch(` 2578 SELECT 2579 Channels.* 2580 FROM 2581 Channels 2582 JOIN 2583 Channels c ON (c.Id = Channels.Id) 2584 WHERE 2585 c.TeamId = :TeamId 2586 SEARCH_CLAUSE 2587 AND c.DeleteAt != 0 2588 AND c.Type = 'P' 2589 AND c.Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) 2590 ORDER BY c.DisplayName 2591 LIMIT 100 2592 `, term, map[string]interface{}{ 2593 "TeamId": teamId, 2594 "UserId": userId, 2595 }) 2596 2597 outputErr := publicErr 2598 if privateErr != nil { 2599 outputErr = privateErr 2600 } 2601 2602 if outputErr != nil { 2603 return nil, outputErr 2604 } 2605 2606 output := *publicChannels 2607 output = append(output, *privateChannels...) 2608 2609 return &output, nil 2610 } 2611 2612 func (s SqlChannelStore) SearchForUserInTeam(userId string, teamId string, term string, includeDeleted bool) (*model.ChannelList, error) { 2613 deleteFilter := "AND c.DeleteAt = 0" 2614 if includeDeleted { 2615 deleteFilter = "" 2616 } 2617 2618 return s.performSearch(` 2619 SELECT 2620 Channels.* 2621 FROM 2622 Channels 2623 JOIN 2624 PublicChannels c ON (c.Id = Channels.Id) 2625 JOIN 2626 ChannelMembers cm ON (c.Id = cm.ChannelId) 2627 WHERE 2628 c.TeamId = :TeamId 2629 AND 2630 cm.UserId = :UserId 2631 `+deleteFilter+` 2632 SEARCH_CLAUSE 2633 ORDER BY c.DisplayName 2634 LIMIT 100 2635 `, term, map[string]interface{}{ 2636 "TeamId": teamId, 2637 "UserId": userId, 2638 }) 2639 } 2640 2641 func (s SqlChannelStore) channelSearchQuery(term string, opts store.ChannelSearchOpts, countQuery bool) sq.SelectBuilder { 2642 var limit int 2643 if opts.PerPage != nil { 2644 limit = *opts.PerPage 2645 } else { 2646 limit = 100 2647 } 2648 2649 var selectStr string 2650 if countQuery { 2651 selectStr = "count(*)" 2652 } else { 2653 selectStr = "c.*, t.DisplayName AS TeamDisplayName, t.Name AS TeamName, t.UpdateAt as TeamUpdateAt" 2654 } 2655 2656 query := s.getQueryBuilder(). 2657 Select(selectStr). 2658 From("Channels AS c"). 2659 Join("Teams AS t ON t.Id = c.TeamId") 2660 2661 // don't bother ordering or limiting if we're just getting the count 2662 if !countQuery { 2663 query = query. 2664 OrderBy("c.DisplayName, t.DisplayName"). 2665 Limit(uint64(limit)) 2666 } 2667 if opts.Deleted { 2668 query = query.Where(sq.NotEq{"c.DeleteAt": int(0)}) 2669 } else if !opts.IncludeDeleted { 2670 query = query.Where(sq.Eq{"c.DeleteAt": int(0)}) 2671 } 2672 2673 if opts.IsPaginated() && !countQuery { 2674 query = query.Offset(uint64(*opts.Page * *opts.PerPage)) 2675 } 2676 2677 likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose") 2678 if likeTerm != "" { 2679 likeClause = strings.ReplaceAll(likeClause, ":LikeTerm", "?") 2680 fulltextClause, fulltextTerm := s.buildFulltextClause(term, "c.Name, c.DisplayName, c.Purpose") 2681 fulltextClause = strings.ReplaceAll(fulltextClause, ":FulltextTerm", "?") 2682 query = query.Where(sq.Or{ 2683 sq.Expr(likeClause, likeTerm, likeTerm, likeTerm), // Keep the number of likeTerms same as the number 2684 // of columns (c.Name, c.DisplayName, c.Purpose) 2685 sq.Expr(fulltextClause, fulltextTerm), 2686 }) 2687 } 2688 2689 if len(opts.ExcludeChannelNames) > 0 { 2690 query = query.Where(sq.NotEq{"c.Name": opts.ExcludeChannelNames}) 2691 } 2692 2693 if opts.NotAssociatedToGroup != "" { 2694 query = query.Where("c.Id NOT IN (SELECT ChannelId FROM GroupChannels WHERE GroupChannels.GroupId = ? AND GroupChannels.DeleteAt = 0)", opts.NotAssociatedToGroup) 2695 } 2696 2697 if len(opts.TeamIds) > 0 { 2698 query = query.Where(sq.Eq{"c.TeamId": opts.TeamIds}) 2699 } 2700 2701 if opts.GroupConstrained { 2702 query = query.Where(sq.Eq{"c.GroupConstrained": true}) 2703 } else if opts.ExcludeGroupConstrained { 2704 query = query.Where(sq.Or{ 2705 sq.NotEq{"c.GroupConstrained": true}, 2706 sq.Eq{"c.GroupConstrained": nil}, 2707 }) 2708 } 2709 2710 if opts.Public && !opts.Private { 2711 query = query.Where(sq.Eq{"c.Type": model.CHANNEL_OPEN}) 2712 } else if opts.Private && !opts.Public { 2713 query = query.Where(sq.Eq{"c.Type": model.CHANNEL_PRIVATE}) 2714 } else { 2715 query = query.Where(sq.Or{ 2716 sq.Eq{"c.Type": model.CHANNEL_OPEN}, 2717 sq.Eq{"c.Type": model.CHANNEL_PRIVATE}, 2718 }) 2719 } 2720 2721 return query 2722 } 2723 2724 func (s SqlChannelStore) SearchAllChannels(term string, opts store.ChannelSearchOpts) (*model.ChannelListWithTeamData, int64, error) { 2725 queryString, args, err := s.channelSearchQuery(term, opts, false).ToSql() 2726 if err != nil { 2727 return nil, 0, errors.Wrap(err, "channel_tosql") 2728 } 2729 var channels model.ChannelListWithTeamData 2730 if _, err = s.GetReplica().Select(&channels, queryString, args...); err != nil { 2731 return nil, 0, errors.Wrapf(err, "failed to find Channels with term='%s'", term) 2732 } 2733 2734 var totalCount int64 2735 2736 // only query a 2nd time for the count if the results are being requested paginated. 2737 if opts.IsPaginated() { 2738 queryString, args, err = s.channelSearchQuery(term, opts, true).ToSql() 2739 if err != nil { 2740 return nil, 0, errors.Wrap(err, "channel_tosql") 2741 } 2742 if totalCount, err = s.GetReplica().SelectInt(queryString, args...); err != nil { 2743 return nil, 0, errors.Wrapf(err, "failed to find Channels with term='%s'", term) 2744 } 2745 } else { 2746 totalCount = int64(len(channels)) 2747 } 2748 2749 return &channels, totalCount, nil 2750 } 2751 2752 func (s SqlChannelStore) SearchMore(userId string, teamId string, term string) (*model.ChannelList, error) { 2753 return s.performSearch(` 2754 SELECT 2755 Channels.* 2756 FROM 2757 Channels 2758 JOIN 2759 PublicChannels c ON (c.Id = Channels.Id) 2760 WHERE 2761 c.TeamId = :TeamId 2762 AND c.DeleteAt = 0 2763 AND c.Id NOT IN ( 2764 SELECT 2765 c.Id 2766 FROM 2767 PublicChannels c 2768 JOIN 2769 ChannelMembers cm ON (cm.ChannelId = c.Id) 2770 WHERE 2771 c.TeamId = :TeamId 2772 AND cm.UserId = :UserId 2773 AND c.DeleteAt = 0 2774 ) 2775 SEARCH_CLAUSE 2776 ORDER BY c.DisplayName 2777 LIMIT 100 2778 `, term, map[string]interface{}{ 2779 "TeamId": teamId, 2780 "UserId": userId, 2781 }) 2782 } 2783 2784 func (s SqlChannelStore) buildLIKEClause(term string, searchColumns string) (likeClause, likeTerm string) { 2785 likeTerm = sanitizeSearchTerm(term, "*") 2786 2787 if likeTerm == "" { 2788 return 2789 } 2790 2791 // Prepare the LIKE portion of the query. 2792 var searchFields []string 2793 for _, field := range strings.Split(searchColumns, ", ") { 2794 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 2795 searchFields = append(searchFields, fmt.Sprintf("lower(%s) LIKE lower(%s) escape '*'", field, ":LikeTerm")) 2796 } else { 2797 searchFields = append(searchFields, fmt.Sprintf("%s LIKE %s escape '*'", field, ":LikeTerm")) 2798 } 2799 } 2800 2801 likeClause = fmt.Sprintf("(%s)", strings.Join(searchFields, " OR ")) 2802 likeTerm = wildcardSearchTerm(likeTerm) 2803 return 2804 } 2805 2806 func (s SqlChannelStore) buildFulltextClause(term string, searchColumns string) (fulltextClause, fulltextTerm string) { 2807 // Copy the terms as we will need to prepare them differently for each search type. 2808 fulltextTerm = term 2809 2810 // These chars must be treated as spaces in the fulltext query. 2811 for _, c := range spaceFulltextSearchChar { 2812 fulltextTerm = strings.Replace(fulltextTerm, c, " ", -1) 2813 } 2814 2815 // Prepare the FULLTEXT portion of the query. 2816 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 2817 fulltextTerm = strings.Replace(fulltextTerm, "|", "", -1) 2818 2819 splitTerm := strings.Fields(fulltextTerm) 2820 for i, t := range strings.Fields(fulltextTerm) { 2821 if i == len(splitTerm)-1 { 2822 splitTerm[i] = t + ":*" 2823 } else { 2824 splitTerm[i] = t + ":* &" 2825 } 2826 } 2827 2828 fulltextTerm = strings.Join(splitTerm, " ") 2829 2830 fulltextClause = fmt.Sprintf("((to_tsvector('english', %s)) @@ to_tsquery('english', :FulltextTerm))", convertMySQLFullTextColumnsToPostgres(searchColumns)) 2831 } else if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 2832 splitTerm := strings.Fields(fulltextTerm) 2833 for i, t := range strings.Fields(fulltextTerm) { 2834 splitTerm[i] = "+" + t + "*" 2835 } 2836 2837 fulltextTerm = strings.Join(splitTerm, " ") 2838 2839 fulltextClause = fmt.Sprintf("MATCH(%s) AGAINST (:FulltextTerm IN BOOLEAN MODE)", searchColumns) 2840 } 2841 2842 return 2843 } 2844 2845 func (s SqlChannelStore) performSearch(searchQuery string, term string, parameters map[string]interface{}) (*model.ChannelList, error) { 2846 likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose") 2847 if likeTerm == "" { 2848 // If the likeTerm is empty after preparing, then don't bother searching. 2849 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1) 2850 } else { 2851 parameters["LikeTerm"] = likeTerm 2852 fulltextClause, fulltextTerm := s.buildFulltextClause(term, "c.Name, c.DisplayName, c.Purpose") 2853 parameters["FulltextTerm"] = fulltextTerm 2854 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "AND ("+likeClause+" OR "+fulltextClause+")", 1) 2855 } 2856 2857 var channels model.ChannelList 2858 2859 if _, err := s.GetReplica().Select(&channels, searchQuery, parameters); err != nil { 2860 return nil, errors.Wrapf(err, "failed to find Channels with term='%s'", term) 2861 } 2862 2863 return &channels, nil 2864 } 2865 2866 func (s SqlChannelStore) getSearchGroupChannelsQuery(userId, term string, isPostgreSQL bool) (string, map[string]interface{}) { 2867 var query, baseLikeClause string 2868 if isPostgreSQL { 2869 baseLikeClause = "ARRAY_TO_STRING(ARRAY_AGG(u.Username), ', ') LIKE %s" 2870 query = ` 2871 SELECT 2872 * 2873 FROM 2874 Channels 2875 WHERE 2876 Id IN ( 2877 SELECT 2878 cc.Id 2879 FROM ( 2880 SELECT 2881 c.Id 2882 FROM 2883 Channels c 2884 JOIN 2885 ChannelMembers cm on c.Id = cm.ChannelId 2886 JOIN 2887 Users u on u.Id = cm.UserId 2888 WHERE 2889 c.Type = 'G' 2890 AND 2891 u.Id = :UserId 2892 GROUP BY 2893 c.Id 2894 ) cc 2895 JOIN 2896 ChannelMembers cm on cc.Id = cm.ChannelId 2897 JOIN 2898 Users u on u.Id = cm.UserId 2899 GROUP BY 2900 cc.Id 2901 HAVING 2902 %s 2903 LIMIT 2904 ` + strconv.Itoa(model.CHANNEL_SEARCH_DEFAULT_LIMIT) + ` 2905 )` 2906 } else { 2907 baseLikeClause = "GROUP_CONCAT(u.Username SEPARATOR ', ') LIKE %s" 2908 query = ` 2909 SELECT 2910 cc.* 2911 FROM ( 2912 SELECT 2913 c.* 2914 FROM 2915 Channels c 2916 JOIN 2917 ChannelMembers cm on c.Id = cm.ChannelId 2918 JOIN 2919 Users u on u.Id = cm.UserId 2920 WHERE 2921 c.Type = 'G' 2922 AND 2923 u.Id = :UserId 2924 GROUP BY 2925 c.Id 2926 ) cc 2927 JOIN 2928 ChannelMembers cm on cc.Id = cm.ChannelId 2929 JOIN 2930 Users u on u.Id = cm.UserId 2931 GROUP BY 2932 cc.Id 2933 HAVING 2934 %s 2935 LIMIT 2936 ` + strconv.Itoa(model.CHANNEL_SEARCH_DEFAULT_LIMIT) 2937 } 2938 2939 var likeClauses []string 2940 args := map[string]interface{}{"UserId": userId} 2941 terms := strings.Split(strings.ToLower(strings.Trim(term, " ")), " ") 2942 2943 for idx, term := range terms { 2944 argName := fmt.Sprintf("Term%v", idx) 2945 term = sanitizeSearchTerm(term, "\\") 2946 likeClauses = append(likeClauses, fmt.Sprintf(baseLikeClause, ":"+argName)) 2947 args[argName] = "%" + term + "%" 2948 } 2949 2950 query = fmt.Sprintf(query, strings.Join(likeClauses, " AND ")) 2951 return query, args 2952 } 2953 2954 func (s SqlChannelStore) SearchGroupChannels(userId, term string) (*model.ChannelList, error) { 2955 isPostgreSQL := s.DriverName() == model.DATABASE_DRIVER_POSTGRES 2956 queryString, args := s.getSearchGroupChannelsQuery(userId, term, isPostgreSQL) 2957 2958 var groupChannels model.ChannelList 2959 if _, err := s.GetReplica().Select(&groupChannels, queryString, args); err != nil { 2960 return nil, errors.Wrapf(err, "failed to find Channels with term='%s' and userId=%s", term, userId) 2961 } 2962 return &groupChannels, nil 2963 } 2964 2965 func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) (*model.ChannelMembers, error) { 2966 var dbMembers channelMemberWithSchemeRolesList 2967 2968 keys, props := MapStringsToQueryParams(userIds, "User") 2969 props["ChannelId"] = channelId 2970 2971 if _, err := s.GetReplica().Select(&dbMembers, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId IN "+keys, props); err != nil { 2972 return nil, errors.Wrapf(err, "failed to find ChannelMembers with channelId=%s and userId in %v", channelId, userIds) 2973 } 2974 2975 return dbMembers.ToModel(), nil 2976 } 2977 2978 func (s SqlChannelStore) GetMembersByChannelIds(channelIds []string, userId string) (*model.ChannelMembers, error) { 2979 var dbMembers channelMemberWithSchemeRolesList 2980 2981 keys, props := MapStringsToQueryParams(channelIds, "Channel") 2982 props["UserId"] = userId 2983 2984 if _, err := s.GetReplica().Select(&dbMembers, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.UserId = :UserId AND ChannelMembers.ChannelId IN "+keys, props); err != nil { 2985 return nil, errors.Wrapf(err, "failed to find ChannelMembers with userId=%s and channelId in %v", userId, channelIds) 2986 } 2987 2988 return dbMembers.ToModel(), nil 2989 } 2990 2991 func (s SqlChannelStore) GetChannelsByScheme(schemeId string, offset int, limit int) (model.ChannelList, error) { 2992 var channels model.ChannelList 2993 _, err := s.GetReplica().Select(&channels, "SELECT * FROM Channels WHERE SchemeId = :SchemeId ORDER BY DisplayName LIMIT :Limit OFFSET :Offset", map[string]interface{}{"SchemeId": schemeId, "Offset": offset, "Limit": limit}) 2994 if err != nil { 2995 return nil, errors.Wrapf(err, "failed to find Channels with schemeId=%s", schemeId) 2996 } 2997 return channels, nil 2998 } 2999 3000 // This function does the Advanced Permissions Phase 2 migration for ChannelMember objects. It performs the migration 3001 // in batches as a single transaction per batch to ensure consistency but to also minimise execution time to avoid 3002 // causing unnecessary table locks. **THIS FUNCTION SHOULD NOT BE USED FOR ANY OTHER PURPOSE.** Executing this function 3003 // *after* the new Schemes functionality has been used on an installation will have unintended consequences. 3004 func (s SqlChannelStore) MigrateChannelMembers(fromChannelId string, fromUserId string) (map[string]string, error) { 3005 var transaction *gorp.Transaction 3006 var err error 3007 3008 if transaction, err = s.GetMaster().Begin(); err != nil { 3009 return nil, errors.Wrap(err, "begin_transaction") 3010 } 3011 defer finalizeTransaction(transaction) 3012 3013 var channelMembers []channelMember 3014 if _, err := transaction.Select(&channelMembers, "SELECT * from ChannelMembers WHERE (ChannelId, UserId) > (:FromChannelId, :FromUserId) ORDER BY ChannelId, UserId LIMIT 100", map[string]interface{}{"FromChannelId": fromChannelId, "FromUserId": fromUserId}); err != nil { 3015 return nil, errors.Wrap(err, "failed to find ChannelMembers") 3016 } 3017 3018 if len(channelMembers) == 0 { 3019 // No more channel members in query result means that the migration has finished. 3020 return nil, nil 3021 } 3022 3023 for i := range channelMembers { 3024 member := channelMembers[i] 3025 roles := strings.Fields(member.Roles) 3026 var newRoles []string 3027 if !member.SchemeAdmin.Valid { 3028 member.SchemeAdmin = sql.NullBool{Bool: false, Valid: true} 3029 } 3030 if !member.SchemeUser.Valid { 3031 member.SchemeUser = sql.NullBool{Bool: false, Valid: true} 3032 } 3033 if !member.SchemeGuest.Valid { 3034 member.SchemeGuest = sql.NullBool{Bool: false, Valid: true} 3035 } 3036 for _, role := range roles { 3037 if role == model.CHANNEL_ADMIN_ROLE_ID { 3038 member.SchemeAdmin = sql.NullBool{Bool: true, Valid: true} 3039 } else if role == model.CHANNEL_USER_ROLE_ID { 3040 member.SchemeUser = sql.NullBool{Bool: true, Valid: true} 3041 } else if role == model.CHANNEL_GUEST_ROLE_ID { 3042 member.SchemeGuest = sql.NullBool{Bool: true, Valid: true} 3043 } else { 3044 newRoles = append(newRoles, role) 3045 } 3046 } 3047 member.Roles = strings.Join(newRoles, " ") 3048 3049 if _, err := transaction.Update(&member); err != nil { 3050 return nil, errors.Wrap(err, "failed to update ChannelMember") 3051 } 3052 3053 } 3054 3055 if err := transaction.Commit(); err != nil { 3056 return nil, errors.Wrap(err, "commit_transaction") 3057 } 3058 3059 data := make(map[string]string) 3060 data["ChannelId"] = channelMembers[len(channelMembers)-1].ChannelId 3061 data["UserId"] = channelMembers[len(channelMembers)-1].UserId 3062 return data, nil 3063 } 3064 3065 func (s SqlChannelStore) ResetAllChannelSchemes() error { 3066 transaction, err := s.GetMaster().Begin() 3067 if err != nil { 3068 return errors.Wrap(err, "begin_transaction") 3069 } 3070 defer finalizeTransaction(transaction) 3071 3072 err = s.resetAllChannelSchemesT(transaction) 3073 if err != nil { 3074 return err 3075 } 3076 3077 if err := transaction.Commit(); err != nil { 3078 return errors.Wrap(err, "commit_transaction") 3079 } 3080 3081 return nil 3082 } 3083 3084 func (s SqlChannelStore) resetAllChannelSchemesT(transaction *gorp.Transaction) error { 3085 if _, err := transaction.Exec("UPDATE Channels SET SchemeId=''"); err != nil { 3086 return errors.Wrap(err, "failed to update Channels") 3087 } 3088 3089 return nil 3090 } 3091 3092 func (s SqlChannelStore) ClearAllCustomRoleAssignments() error { 3093 builtInRoles := model.MakeDefaultRoles() 3094 lastUserId := strings.Repeat("0", 26) 3095 lastChannelId := strings.Repeat("0", 26) 3096 3097 for { 3098 var transaction *gorp.Transaction 3099 var err error 3100 3101 if transaction, err = s.GetMaster().Begin(); err != nil { 3102 return errors.Wrap(err, "begin_transaction") 3103 } 3104 3105 var channelMembers []*channelMember 3106 if _, err := transaction.Select(&channelMembers, "SELECT * from ChannelMembers WHERE (ChannelId, UserId) > (:ChannelId, :UserId) ORDER BY ChannelId, UserId LIMIT 1000", map[string]interface{}{"ChannelId": lastChannelId, "UserId": lastUserId}); err != nil { 3107 finalizeTransaction(transaction) 3108 return errors.Wrap(err, "failed to find ChannelMembers") 3109 } 3110 3111 if len(channelMembers) == 0 { 3112 finalizeTransaction(transaction) 3113 break 3114 } 3115 3116 for _, member := range channelMembers { 3117 lastUserId = member.UserId 3118 lastChannelId = member.ChannelId 3119 3120 var newRoles []string 3121 3122 for _, role := range strings.Fields(member.Roles) { 3123 for name := range builtInRoles { 3124 if name == role { 3125 newRoles = append(newRoles, role) 3126 break 3127 } 3128 } 3129 } 3130 3131 newRolesString := strings.Join(newRoles, " ") 3132 if newRolesString != member.Roles { 3133 if _, err := transaction.Exec("UPDATE ChannelMembers SET Roles = :Roles WHERE UserId = :UserId AND ChannelId = :ChannelId", map[string]interface{}{"Roles": newRolesString, "ChannelId": member.ChannelId, "UserId": member.UserId}); err != nil { 3134 finalizeTransaction(transaction) 3135 return errors.Wrap(err, "failed to update ChannelMembers") 3136 } 3137 } 3138 } 3139 3140 if err := transaction.Commit(); err != nil { 3141 finalizeTransaction(transaction) 3142 return errors.Wrap(err, "commit_transaction") 3143 } 3144 } 3145 3146 return nil 3147 } 3148 3149 func (s SqlChannelStore) GetAllChannelsForExportAfter(limit int, afterId string) ([]*model.ChannelForExport, error) { 3150 var channels []*model.ChannelForExport 3151 if _, err := s.GetReplica().Select(&channels, ` 3152 SELECT 3153 Channels.*, 3154 Teams.Name as TeamName, 3155 Schemes.Name as SchemeName 3156 FROM Channels 3157 INNER JOIN 3158 Teams ON Channels.TeamId = Teams.Id 3159 LEFT JOIN 3160 Schemes ON Channels.SchemeId = Schemes.Id 3161 WHERE 3162 Channels.Id > :AfterId 3163 AND Channels.Type IN ('O', 'P') 3164 ORDER BY 3165 Id 3166 LIMIT :Limit`, 3167 map[string]interface{}{"AfterId": afterId, "Limit": limit}); err != nil { 3168 return nil, errors.Wrap(err, "failed to find Channels for export") 3169 } 3170 3171 return channels, nil 3172 } 3173 3174 func (s SqlChannelStore) GetChannelMembersForExport(userId string, teamId string) ([]*model.ChannelMemberForExport, error) { 3175 var members []*model.ChannelMemberForExport 3176 _, err := s.GetReplica().Select(&members, ` 3177 SELECT 3178 ChannelMembers.ChannelId, 3179 ChannelMembers.UserId, 3180 ChannelMembers.Roles, 3181 ChannelMembers.LastViewedAt, 3182 ChannelMembers.MsgCount, 3183 ChannelMembers.MentionCount, 3184 ChannelMembers.NotifyProps, 3185 ChannelMembers.LastUpdateAt, 3186 ChannelMembers.SchemeUser, 3187 ChannelMembers.SchemeAdmin, 3188 (ChannelMembers.SchemeGuest IS NOT NULL AND ChannelMembers.SchemeGuest) as SchemeGuest, 3189 Channels.Name as ChannelName 3190 FROM 3191 ChannelMembers 3192 INNER JOIN 3193 Channels ON ChannelMembers.ChannelId = Channels.Id 3194 WHERE 3195 ChannelMembers.UserId = :UserId 3196 AND Channels.TeamId = :TeamId 3197 AND Channels.DeleteAt = 0`, 3198 map[string]interface{}{"TeamId": teamId, "UserId": userId}) 3199 3200 if err != nil { 3201 return nil, errors.Wrap(err, "failed to find Channels for export") 3202 } 3203 3204 return members, nil 3205 } 3206 3207 func (s SqlChannelStore) GetAllDirectChannelsForExportAfter(limit int, afterId string) ([]*model.DirectChannelForExport, error) { 3208 var directChannelsForExport []*model.DirectChannelForExport 3209 query := s.getQueryBuilder(). 3210 Select("Channels.*"). 3211 From("Channels"). 3212 Where(sq.And{ 3213 sq.Gt{"Channels.Id": afterId}, 3214 sq.Eq{"Channels.DeleteAt": int(0)}, 3215 sq.Eq{"Channels.Type": []string{"D", "G"}}, 3216 }). 3217 OrderBy("Channels.Id"). 3218 Limit(uint64(limit)) 3219 3220 queryString, args, err := query.ToSql() 3221 if err != nil { 3222 return nil, errors.Wrap(err, "channel_tosql") 3223 } 3224 3225 if _, err = s.GetReplica().Select(&directChannelsForExport, queryString, args...); err != nil { 3226 return nil, errors.Wrap(err, "failed to find direct Channels for export") 3227 } 3228 3229 var channelIds []string 3230 for _, channel := range directChannelsForExport { 3231 channelIds = append(channelIds, channel.Id) 3232 } 3233 query = s.getQueryBuilder(). 3234 Select("u.Username as Username, ChannelId, UserId, cm.Roles as Roles, LastViewedAt, MsgCount, MentionCount, cm.NotifyProps as NotifyProps, LastUpdateAt, SchemeUser, SchemeAdmin, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest"). 3235 From("ChannelMembers cm"). 3236 Join("Users u ON ( u.Id = cm.UserId )"). 3237 Where(sq.And{ 3238 sq.Eq{"cm.ChannelId": channelIds}, 3239 sq.Eq{"u.DeleteAt": int(0)}, 3240 }) 3241 3242 queryString, args, err = query.ToSql() 3243 if err != nil { 3244 return nil, errors.Wrap(err, "channel_tosql") 3245 } 3246 3247 var channelMembers []*model.ChannelMemberForExport 3248 if _, err := s.GetReplica().Select(&channelMembers, queryString, args...); err != nil { 3249 return nil, errors.Wrap(err, "failed to find ChannelMembers") 3250 } 3251 3252 // Populate each channel with its members 3253 dmChannelsMap := make(map[string]*model.DirectChannelForExport) 3254 for _, channel := range directChannelsForExport { 3255 channel.Members = &[]string{} 3256 dmChannelsMap[channel.Id] = channel 3257 } 3258 for _, member := range channelMembers { 3259 members := dmChannelsMap[member.ChannelId].Members 3260 *members = append(*members, member.Username) 3261 } 3262 3263 return directChannelsForExport, nil 3264 } 3265 3266 func (s SqlChannelStore) GetChannelsBatchForIndexing(startTime, endTime int64, limit int) ([]*model.Channel, error) { 3267 query := 3268 `SELECT 3269 * 3270 FROM 3271 Channels 3272 WHERE 3273 Type = 'O' 3274 AND 3275 CreateAt >= :StartTime 3276 AND 3277 CreateAt < :EndTime 3278 ORDER BY 3279 CreateAt 3280 LIMIT 3281 :NumChannels` 3282 3283 var channels []*model.Channel 3284 _, err := s.GetSearchReplica().Select(&channels, query, map[string]interface{}{"StartTime": startTime, "EndTime": endTime, "NumChannels": limit}) 3285 if err != nil { 3286 return nil, errors.Wrap(err, "failed to find Channels") 3287 } 3288 3289 return channels, nil 3290 } 3291 3292 func (s SqlChannelStore) UserBelongsToChannels(userId string, channelIds []string) (bool, error) { 3293 query := s.getQueryBuilder(). 3294 Select("Count(*)"). 3295 From("ChannelMembers"). 3296 Where(sq.And{ 3297 sq.Eq{"UserId": userId}, 3298 sq.Eq{"ChannelId": channelIds}, 3299 }) 3300 3301 queryString, args, err := query.ToSql() 3302 if err != nil { 3303 return false, errors.Wrap(err, "channel_tosql") 3304 } 3305 c, err := s.GetReplica().SelectInt(queryString, args...) 3306 if err != nil { 3307 return false, errors.Wrap(err, "failed to count ChannelMembers") 3308 } 3309 return c > 0, nil 3310 } 3311 3312 func (s SqlChannelStore) UpdateMembersRole(channelID string, userIDs []string) error { 3313 sql := fmt.Sprintf(` 3314 UPDATE 3315 ChannelMembers 3316 SET 3317 SchemeAdmin = CASE WHEN UserId IN ('%s') THEN 3318 TRUE 3319 ELSE 3320 FALSE 3321 END 3322 WHERE 3323 ChannelId = :ChannelId 3324 AND (SchemeGuest = false OR SchemeGuest IS NULL) 3325 `, strings.Join(userIDs, "', '")) 3326 3327 if _, err := s.GetMaster().Exec(sql, map[string]interface{}{"ChannelId": channelID}); err != nil { 3328 return errors.Wrap(err, "failed to update ChannelMembers") 3329 } 3330 3331 return nil 3332 } 3333 3334 func (s SqlChannelStore) GroupSyncedChannelCount() (int64, error) { 3335 query := s.getQueryBuilder().Select("COUNT(*)").From("Channels").Where(sq.Eq{"GroupConstrained": true, "DeleteAt": 0}) 3336 3337 sql, args, err := query.ToSql() 3338 if err != nil { 3339 return 0, errors.Wrap(err, "channel_tosql") 3340 } 3341 3342 count, err := s.GetReplica().SelectInt(sql, args...) 3343 if err != nil { 3344 return 0, errors.Wrap(err, "failed to count Channels") 3345 } 3346 3347 return count, nil 3348 }