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