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