github.com/jfrerich/mattermost-server@v5.8.0-rc2+incompatible/store/sqlstore/channel_store.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package sqlstore 5 6 import ( 7 "database/sql" 8 "fmt" 9 "net/http" 10 "sort" 11 "strconv" 12 "strings" 13 14 "github.com/mattermost/gorp" 15 "github.com/pkg/errors" 16 17 "github.com/mattermost/mattermost-server/einterfaces" 18 "github.com/mattermost/mattermost-server/mlog" 19 "github.com/mattermost/mattermost-server/model" 20 "github.com/mattermost/mattermost-server/store" 21 "github.com/mattermost/mattermost-server/utils" 22 ) 23 24 const ( 25 ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE = model.SESSION_CACHE_SIZE 26 ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SEC = 900 // 15 mins 27 28 ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE = model.SESSION_CACHE_SIZE 29 ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SEC = 1800 // 30 mins 30 31 CHANNEL_MEMBERS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE 32 CHANNEL_MEMBERS_COUNTS_CACHE_SEC = 1800 // 30 mins 33 34 CHANNEL_CACHE_SEC = 900 // 15 mins 35 ) 36 37 type SqlChannelStore struct { 38 SqlStore 39 metrics einterfaces.MetricsInterface 40 } 41 42 type channelMember struct { 43 ChannelId string 44 UserId string 45 Roles string 46 LastViewedAt int64 47 MsgCount int64 48 MentionCount int64 49 NotifyProps model.StringMap 50 LastUpdateAt int64 51 SchemeUser sql.NullBool 52 SchemeAdmin sql.NullBool 53 } 54 55 func NewChannelMemberFromModel(cm *model.ChannelMember) *channelMember { 56 return &channelMember{ 57 ChannelId: cm.ChannelId, 58 UserId: cm.UserId, 59 Roles: cm.ExplicitRoles, 60 LastViewedAt: cm.LastViewedAt, 61 MsgCount: cm.MsgCount, 62 MentionCount: cm.MentionCount, 63 NotifyProps: cm.NotifyProps, 64 LastUpdateAt: cm.LastUpdateAt, 65 SchemeUser: sql.NullBool{Valid: true, Bool: cm.SchemeUser}, 66 SchemeAdmin: sql.NullBool{Valid: true, Bool: cm.SchemeAdmin}, 67 } 68 } 69 70 type channelMemberWithSchemeRoles struct { 71 ChannelId string 72 UserId string 73 Roles string 74 LastViewedAt int64 75 MsgCount int64 76 MentionCount int64 77 NotifyProps model.StringMap 78 LastUpdateAt int64 79 SchemeUser sql.NullBool 80 SchemeAdmin sql.NullBool 81 TeamSchemeDefaultUserRole sql.NullString 82 TeamSchemeDefaultAdminRole sql.NullString 83 ChannelSchemeDefaultUserRole sql.NullString 84 ChannelSchemeDefaultAdminRole sql.NullString 85 } 86 87 type channelMemberWithSchemeRolesList []channelMemberWithSchemeRoles 88 89 func (db channelMemberWithSchemeRoles) ToModel() *model.ChannelMember { 90 var roles []string 91 var explicitRoles []string 92 93 // Identify any system-wide scheme derived roles that are in "Roles" field due to not yet being migrated, 94 // and exclude them from ExplicitRoles field. 95 schemeUser := db.SchemeUser.Valid && db.SchemeUser.Bool 96 schemeAdmin := db.SchemeAdmin.Valid && db.SchemeAdmin.Bool 97 for _, role := range strings.Fields(db.Roles) { 98 isImplicit := false 99 if role == model.CHANNEL_USER_ROLE_ID { 100 // We have an implicit role via the system scheme. Override the "schemeUser" field to true. 101 schemeUser = true 102 isImplicit = true 103 } else if role == model.CHANNEL_ADMIN_ROLE_ID { 104 // We have an implicit role via the system scheme. 105 schemeAdmin = true 106 isImplicit = true 107 } 108 109 if !isImplicit { 110 explicitRoles = append(explicitRoles, role) 111 } 112 roles = append(roles, role) 113 } 114 115 // Add any scheme derived roles that are not in the Roles field due to being Implicit from the Scheme, and add 116 // them to the Roles field for backwards compatibility reasons. 117 var schemeImpliedRoles []string 118 if db.SchemeUser.Valid && db.SchemeUser.Bool { 119 if db.ChannelSchemeDefaultUserRole.Valid && db.ChannelSchemeDefaultUserRole.String != "" { 120 schemeImpliedRoles = append(schemeImpliedRoles, db.ChannelSchemeDefaultUserRole.String) 121 } else if db.TeamSchemeDefaultUserRole.Valid && db.TeamSchemeDefaultUserRole.String != "" { 122 schemeImpliedRoles = append(schemeImpliedRoles, db.TeamSchemeDefaultUserRole.String) 123 } else { 124 schemeImpliedRoles = append(schemeImpliedRoles, model.CHANNEL_USER_ROLE_ID) 125 } 126 } 127 if db.SchemeAdmin.Valid && db.SchemeAdmin.Bool { 128 if db.ChannelSchemeDefaultAdminRole.Valid && db.ChannelSchemeDefaultAdminRole.String != "" { 129 schemeImpliedRoles = append(schemeImpliedRoles, db.ChannelSchemeDefaultAdminRole.String) 130 } else if db.TeamSchemeDefaultAdminRole.Valid && db.TeamSchemeDefaultAdminRole.String != "" { 131 schemeImpliedRoles = append(schemeImpliedRoles, db.TeamSchemeDefaultAdminRole.String) 132 } else { 133 schemeImpliedRoles = append(schemeImpliedRoles, model.CHANNEL_ADMIN_ROLE_ID) 134 } 135 } 136 for _, impliedRole := range schemeImpliedRoles { 137 alreadyThere := false 138 for _, role := range roles { 139 if role == impliedRole { 140 alreadyThere = true 141 } 142 } 143 if !alreadyThere { 144 roles = append(roles, impliedRole) 145 } 146 } 147 148 return &model.ChannelMember{ 149 ChannelId: db.ChannelId, 150 UserId: db.UserId, 151 Roles: strings.Join(roles, " "), 152 LastViewedAt: db.LastViewedAt, 153 MsgCount: db.MsgCount, 154 MentionCount: db.MentionCount, 155 NotifyProps: db.NotifyProps, 156 LastUpdateAt: db.LastUpdateAt, 157 SchemeAdmin: schemeAdmin, 158 SchemeUser: schemeUser, 159 ExplicitRoles: strings.Join(explicitRoles, " "), 160 } 161 } 162 163 func (db channelMemberWithSchemeRolesList) ToModel() *model.ChannelMembers { 164 cms := model.ChannelMembers{} 165 166 for _, cm := range db { 167 cms = append(cms, *cm.ToModel()) 168 } 169 170 return &cms 171 } 172 173 type allChannelMember struct { 174 ChannelId string 175 Roles string 176 SchemeUser sql.NullBool 177 SchemeAdmin sql.NullBool 178 TeamSchemeDefaultUserRole sql.NullString 179 TeamSchemeDefaultAdminRole sql.NullString 180 ChannelSchemeDefaultUserRole sql.NullString 181 ChannelSchemeDefaultAdminRole sql.NullString 182 } 183 184 type allChannelMembers []allChannelMember 185 186 func (db allChannelMember) Process() (string, string) { 187 roles := strings.Fields(db.Roles) 188 189 // Add any scheme derived roles that are not in the Roles field due to being Implicit from the Scheme, and add 190 // them to the Roles field for backwards compatibility reasons. 191 var schemeImpliedRoles []string 192 if db.SchemeUser.Valid && db.SchemeUser.Bool { 193 if db.ChannelSchemeDefaultUserRole.Valid && db.ChannelSchemeDefaultUserRole.String != "" { 194 schemeImpliedRoles = append(schemeImpliedRoles, db.ChannelSchemeDefaultUserRole.String) 195 } else if db.TeamSchemeDefaultUserRole.Valid && db.TeamSchemeDefaultUserRole.String != "" { 196 schemeImpliedRoles = append(schemeImpliedRoles, db.TeamSchemeDefaultUserRole.String) 197 } else { 198 schemeImpliedRoles = append(schemeImpliedRoles, model.CHANNEL_USER_ROLE_ID) 199 } 200 } 201 if db.SchemeAdmin.Valid && db.SchemeAdmin.Bool { 202 if db.ChannelSchemeDefaultAdminRole.Valid && db.ChannelSchemeDefaultAdminRole.String != "" { 203 schemeImpliedRoles = append(schemeImpliedRoles, db.ChannelSchemeDefaultAdminRole.String) 204 } else if db.TeamSchemeDefaultAdminRole.Valid && db.TeamSchemeDefaultAdminRole.String != "" { 205 schemeImpliedRoles = append(schemeImpliedRoles, db.TeamSchemeDefaultAdminRole.String) 206 } else { 207 schemeImpliedRoles = append(schemeImpliedRoles, model.CHANNEL_ADMIN_ROLE_ID) 208 } 209 } 210 for _, impliedRole := range schemeImpliedRoles { 211 alreadyThere := false 212 for _, role := range roles { 213 if role == impliedRole { 214 alreadyThere = true 215 } 216 } 217 if !alreadyThere { 218 roles = append(roles, impliedRole) 219 } 220 } 221 222 return db.ChannelId, strings.Join(roles, " ") 223 } 224 225 func (db allChannelMembers) ToMapStringString() map[string]string { 226 result := make(map[string]string) 227 228 for _, item := range db { 229 key, value := item.Process() 230 result[key] = value 231 } 232 233 return result 234 } 235 236 // publicChannel is a subset of the metadata corresponding to public channels only. 237 type publicChannel struct { 238 Id string `json:"id"` 239 DeleteAt int64 `json:"delete_at"` 240 TeamId string `json:"team_id"` 241 DisplayName string `json:"display_name"` 242 Name string `json:"name"` 243 Header string `json:"header"` 244 Purpose string `json:"purpose"` 245 } 246 247 var channelMemberCountsCache = utils.NewLru(CHANNEL_MEMBERS_COUNTS_CACHE_SIZE) 248 var allChannelMembersForUserCache = utils.NewLru(ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE) 249 var allChannelMembersNotifyPropsForChannelCache = utils.NewLru(ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE) 250 var channelCache = utils.NewLru(model.CHANNEL_CACHE_SIZE) 251 var channelByNameCache = utils.NewLru(model.CHANNEL_CACHE_SIZE) 252 253 func (s SqlChannelStore) ClearCaches() { 254 channelMemberCountsCache.Purge() 255 allChannelMembersForUserCache.Purge() 256 allChannelMembersNotifyPropsForChannelCache.Purge() 257 channelCache.Purge() 258 channelByNameCache.Purge() 259 260 if s.metrics != nil { 261 s.metrics.IncrementMemCacheInvalidationCounter("Channel Member Counts - Purge") 262 s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members for User - Purge") 263 s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members Notify Props for Channel - Purge") 264 s.metrics.IncrementMemCacheInvalidationCounter("Channel - Purge") 265 s.metrics.IncrementMemCacheInvalidationCounter("Channel By Name - Purge") 266 } 267 } 268 269 func NewSqlChannelStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) store.ChannelStore { 270 s := &SqlChannelStore{ 271 SqlStore: sqlStore, 272 metrics: metrics, 273 } 274 275 for _, db := range sqlStore.GetAllConns() { 276 table := db.AddTableWithName(model.Channel{}, "Channels").SetKeys(false, "Id") 277 table.ColMap("Id").SetMaxSize(26) 278 table.ColMap("TeamId").SetMaxSize(26) 279 table.ColMap("Type").SetMaxSize(1) 280 table.ColMap("DisplayName").SetMaxSize(64) 281 table.ColMap("Name").SetMaxSize(64) 282 table.SetUniqueTogether("Name", "TeamId") 283 table.ColMap("Header").SetMaxSize(1024) 284 table.ColMap("Purpose").SetMaxSize(250) 285 table.ColMap("CreatorId").SetMaxSize(26) 286 table.ColMap("SchemeId").SetMaxSize(26) 287 288 tablem := db.AddTableWithName(channelMember{}, "ChannelMembers").SetKeys(false, "ChannelId", "UserId") 289 tablem.ColMap("ChannelId").SetMaxSize(26) 290 tablem.ColMap("UserId").SetMaxSize(26) 291 tablem.ColMap("Roles").SetMaxSize(64) 292 tablem.ColMap("NotifyProps").SetMaxSize(2000) 293 294 tablePublicChannels := db.AddTableWithName(publicChannel{}, "PublicChannels").SetKeys(false, "Id") 295 tablePublicChannels.ColMap("Id").SetMaxSize(26) 296 tablePublicChannels.ColMap("TeamId").SetMaxSize(26) 297 tablePublicChannels.ColMap("DisplayName").SetMaxSize(64) 298 tablePublicChannels.ColMap("Name").SetMaxSize(64) 299 tablePublicChannels.SetUniqueTogether("Name", "TeamId") 300 tablePublicChannels.ColMap("Header").SetMaxSize(1024) 301 tablePublicChannels.ColMap("Purpose").SetMaxSize(250) 302 } 303 304 return s 305 } 306 307 func (s SqlChannelStore) CreateIndexesIfNotExists() { 308 s.CreateIndexIfNotExists("idx_channels_team_id", "Channels", "TeamId") 309 s.CreateIndexIfNotExists("idx_channels_name", "Channels", "Name") 310 s.CreateIndexIfNotExists("idx_channels_update_at", "Channels", "UpdateAt") 311 s.CreateIndexIfNotExists("idx_channels_create_at", "Channels", "CreateAt") 312 s.CreateIndexIfNotExists("idx_channels_delete_at", "Channels", "DeleteAt") 313 314 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 315 s.CreateIndexIfNotExists("idx_channels_name_lower", "Channels", "lower(Name)") 316 s.CreateIndexIfNotExists("idx_channels_displayname_lower", "Channels", "lower(DisplayName)") 317 } 318 319 s.CreateIndexIfNotExists("idx_channelmembers_channel_id", "ChannelMembers", "ChannelId") 320 s.CreateIndexIfNotExists("idx_channelmembers_user_id", "ChannelMembers", "UserId") 321 322 s.CreateFullTextIndexIfNotExists("idx_channel_search_txt", "Channels", "Name, DisplayName, Purpose") 323 324 s.CreateIndexIfNotExists("idx_publicchannels_team_id", "PublicChannels", "TeamId") 325 s.CreateIndexIfNotExists("idx_publicchannels_name", "PublicChannels", "Name") 326 s.CreateIndexIfNotExists("idx_publicchannels_delete_at", "PublicChannels", "DeleteAt") 327 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 328 s.CreateIndexIfNotExists("idx_publicchannels_name_lower", "PublicChannels", "lower(Name)") 329 s.CreateIndexIfNotExists("idx_publicchannels_displayname_lower", "PublicChannels", "lower(DisplayName)") 330 } 331 s.CreateFullTextIndexIfNotExists("idx_publicchannels_search_txt", "PublicChannels", "Name, DisplayName, Purpose") 332 } 333 334 // MigratePublicChannels initializes the PublicChannels table with data created before this version 335 // of the Mattermost server kept it up-to-date. 336 func (s SqlChannelStore) MigratePublicChannels() error { 337 transaction, err := s.GetMaster().Begin() 338 if err != nil { 339 return err 340 } 341 342 if _, err := transaction.Exec(` 343 INSERT INTO PublicChannels 344 (Id, DeleteAt, TeamId, DisplayName, Name, Header, Purpose) 345 SELECT 346 c.Id, c.DeleteAt, c.TeamId, c.DisplayName, c.Name, c.Header, c.Purpose 347 FROM 348 Channels c 349 LEFT JOIN 350 PublicChannels pc ON (pc.Id = c.Id) 351 WHERE 352 c.Type = 'O' 353 AND pc.Id IS NULL 354 `); err != nil { 355 return err 356 } 357 358 if err := transaction.Commit(); err != nil { 359 return err 360 } 361 362 return nil 363 } 364 365 func (s SqlChannelStore) upsertPublicChannelT(transaction *gorp.Transaction, channel *model.Channel) error { 366 publicChannel := &publicChannel{ 367 Id: channel.Id, 368 DeleteAt: channel.DeleteAt, 369 TeamId: channel.TeamId, 370 DisplayName: channel.DisplayName, 371 Name: channel.Name, 372 Header: channel.Header, 373 Purpose: channel.Purpose, 374 } 375 376 if channel.Type != model.CHANNEL_OPEN { 377 if _, err := transaction.Delete(publicChannel); err != nil { 378 return errors.Wrap(err, "failed to delete public channel") 379 } 380 381 return nil 382 } 383 384 if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 385 // Leverage native upsert for MySQL, since RowsAffected returns 0 if the row exists 386 // but no changes were made, breaking the update-then-insert paradigm below when 387 // the row already exists. (Postgres 9.4 doesn't support native upsert.) 388 if _, err := transaction.Exec(` 389 INSERT INTO 390 PublicChannels(Id, DeleteAt, TeamId, DisplayName, Name, Header, Purpose) 391 VALUES 392 (:Id, :DeleteAt, :TeamId, :DisplayName, :Name, :Header, :Purpose) 393 ON DUPLICATE KEY UPDATE 394 DeleteAt = :DeleteAt, 395 TeamId = :TeamId, 396 DisplayName = :DisplayName, 397 Name = :Name, 398 Header = :Header, 399 Purpose = :Purpose; 400 `, map[string]interface{}{ 401 "Id": publicChannel.Id, 402 "DeleteAt": publicChannel.DeleteAt, 403 "TeamId": publicChannel.TeamId, 404 "DisplayName": publicChannel.DisplayName, 405 "Name": publicChannel.Name, 406 "Header": publicChannel.Header, 407 "Purpose": publicChannel.Purpose, 408 }); err != nil { 409 return errors.Wrap(err, "failed to insert public channel") 410 } 411 } else { 412 count, err := transaction.Update(publicChannel) 413 if err != nil { 414 return errors.Wrap(err, "failed to update public channel") 415 } 416 if count > 0 { 417 return nil 418 } 419 420 if err := transaction.Insert(publicChannel); err != nil { 421 return errors.Wrap(err, "failed to insert public channel") 422 } 423 } 424 425 return nil 426 } 427 428 // Save writes the (non-direct) channel channel to the database. 429 func (s SqlChannelStore) Save(channel *model.Channel, maxChannelsPerTeam int64) store.StoreChannel { 430 return store.Do(func(result *store.StoreResult) { 431 if channel.DeleteAt != 0 { 432 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.archived_channel.app_error", nil, "", http.StatusBadRequest) 433 return 434 } 435 436 if channel.Type == model.CHANNEL_DIRECT { 437 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.direct_channel.app_error", nil, "", http.StatusBadRequest) 438 return 439 } 440 441 transaction, err := s.GetMaster().Begin() 442 if err != nil { 443 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 444 return 445 } 446 447 *result = s.saveChannelT(transaction, channel, maxChannelsPerTeam) 448 if result.Err != nil { 449 transaction.Rollback() 450 return 451 } 452 453 // Additionally propagate the write to the PublicChannels table. 454 if err := s.upsertPublicChannelT(transaction, result.Data.(*model.Channel)); err != nil { 455 transaction.Rollback() 456 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.upsert_public_channel.app_error", nil, err.Error(), http.StatusInternalServerError) 457 return 458 } 459 460 if err := transaction.Commit(); err != nil { 461 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 462 return 463 } 464 }) 465 } 466 467 func (s SqlChannelStore) CreateDirectChannel(userId string, otherUserId string) store.StoreChannel { 468 channel := new(model.Channel) 469 470 channel.DisplayName = "" 471 channel.Name = model.GetDMNameFromIds(otherUserId, userId) 472 473 channel.Header = "" 474 channel.Type = model.CHANNEL_DIRECT 475 476 cm1 := &model.ChannelMember{ 477 UserId: userId, 478 NotifyProps: model.GetDefaultChannelNotifyProps(), 479 SchemeUser: true, 480 } 481 cm2 := &model.ChannelMember{ 482 UserId: otherUserId, 483 NotifyProps: model.GetDefaultChannelNotifyProps(), 484 SchemeUser: true, 485 } 486 487 return s.SaveDirectChannel(channel, cm1, cm2) 488 } 489 490 func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1 *model.ChannelMember, member2 *model.ChannelMember) store.StoreChannel { 491 return store.Do(func(result *store.StoreResult) { 492 if directchannel.DeleteAt != 0 { 493 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.archived_channel.app_error", nil, "", http.StatusBadRequest) 494 return 495 } 496 497 if directchannel.Type != model.CHANNEL_DIRECT { 498 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.not_direct.app_error", nil, "", http.StatusBadRequest) 499 return 500 } 501 502 transaction, err := s.GetMaster().Begin() 503 if err != nil { 504 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 505 return 506 } 507 508 directchannel.TeamId = "" 509 channelResult := s.saveChannelT(transaction, directchannel, 0) 510 511 if channelResult.Err != nil { 512 transaction.Rollback() 513 result.Err = channelResult.Err 514 result.Data = channelResult.Data 515 return 516 } 517 518 newChannel := channelResult.Data.(*model.Channel) 519 // Members need new channel ID 520 member1.ChannelId = newChannel.Id 521 member2.ChannelId = newChannel.Id 522 523 member1Result := s.saveMemberT(transaction, member1, newChannel) 524 member2Result := member1Result 525 if member1.UserId != member2.UserId { 526 member2Result = s.saveMemberT(transaction, member2, newChannel) 527 } 528 529 if member1Result.Err != nil || member2Result.Err != nil { 530 transaction.Rollback() 531 details := "" 532 if member1Result.Err != nil { 533 details += "Member1Err: " + member1Result.Err.Message 534 } 535 if member2Result.Err != nil { 536 details += "Member2Err: " + member2Result.Err.Message 537 } 538 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.add_members.app_error", nil, details, http.StatusInternalServerError) 539 return 540 } 541 542 if err := transaction.Commit(); err != nil { 543 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.commit.app_error", nil, err.Error(), http.StatusInternalServerError) 544 return 545 } 546 547 *result = channelResult 548 }) 549 } 550 551 func (s SqlChannelStore) saveChannelT(transaction *gorp.Transaction, channel *model.Channel, maxChannelsPerTeam int64) store.StoreResult { 552 result := store.StoreResult{} 553 554 if len(channel.Id) > 0 { 555 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.existing.app_error", nil, "id="+channel.Id, http.StatusBadRequest) 556 return result 557 } 558 559 channel.PreSave() 560 if result.Err = channel.IsValid(); result.Err != nil { 561 return result 562 } 563 564 if channel.Type != model.CHANNEL_DIRECT && channel.Type != model.CHANNEL_GROUP && maxChannelsPerTeam >= 0 { 565 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 { 566 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.current_count.app_error", nil, "teamId="+channel.TeamId+", "+err.Error(), http.StatusInternalServerError) 567 return result 568 } else if count >= maxChannelsPerTeam { 569 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.limit.app_error", nil, "teamId="+channel.TeamId, http.StatusBadRequest) 570 return result 571 } 572 } 573 574 if err := transaction.Insert(channel); err != nil { 575 if IsUniqueConstraintError(err, []string{"Name", "channels_name_teamid_key"}) { 576 dupChannel := model.Channel{} 577 s.GetMaster().SelectOne(&dupChannel, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name = :Name", map[string]interface{}{"TeamId": channel.TeamId, "Name": channel.Name}) 578 if dupChannel.DeleteAt > 0 { 579 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.previously.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 580 } else { 581 result.Err = model.NewAppError("SqlChannelStore.Save", store.CHANNEL_EXISTS_ERROR, nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 582 result.Data = &dupChannel 583 } 584 } else { 585 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.save.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusInternalServerError) 586 } 587 } else { 588 result.Data = channel 589 } 590 591 return result 592 } 593 594 // Update writes the updated channel to the database. 595 func (s SqlChannelStore) Update(channel *model.Channel) store.StoreChannel { 596 return store.Do(func(result *store.StoreResult) { 597 transaction, err := s.GetMaster().Begin() 598 if err != nil { 599 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 600 return 601 } 602 603 *result = s.updateChannelT(transaction, channel) 604 if result.Err != nil { 605 transaction.Rollback() 606 return 607 } 608 609 // Additionally propagate the write to the PublicChannels table. 610 if err := s.upsertPublicChannelT(transaction, result.Data.(*model.Channel)); err != nil { 611 transaction.Rollback() 612 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.upsert_public_channel.app_error", nil, err.Error(), http.StatusInternalServerError) 613 return 614 } 615 616 if err := transaction.Commit(); err != nil { 617 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 618 return 619 } 620 }) 621 622 } 623 624 func (s SqlChannelStore) updateChannelT(transaction *gorp.Transaction, channel *model.Channel) store.StoreResult { 625 result := store.StoreResult{} 626 627 channel.PreUpdate() 628 629 if channel.DeleteAt != 0 { 630 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.archived_channel.app_error", nil, "", http.StatusBadRequest) 631 return result 632 } 633 634 if result.Err = channel.IsValid(); result.Err != nil { 635 return result 636 } 637 638 count, err := transaction.Update(channel) 639 if err != nil { 640 if IsUniqueConstraintError(err, []string{"Name", "channels_name_teamid_key"}) { 641 dupChannel := model.Channel{} 642 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}) 643 if dupChannel.DeleteAt > 0 { 644 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.previously.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 645 return result 646 } 647 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.exists.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 648 return result 649 } 650 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.updating.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusInternalServerError) 651 return result 652 } 653 654 if count != 1 { 655 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.app_error", nil, "id="+channel.Id, http.StatusInternalServerError) 656 return result 657 } 658 659 result.Data = channel 660 661 return result 662 } 663 664 func (s SqlChannelStore) GetChannelUnread(channelId, userId string) store.StoreChannel { 665 return store.Do(func(result *store.StoreResult) { 666 var unreadChannel model.ChannelUnread 667 err := s.GetReplica().SelectOne(&unreadChannel, 668 `SELECT 669 Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps 670 FROM 671 Channels, ChannelMembers 672 WHERE 673 Id = ChannelId 674 AND Id = :ChannelId 675 AND UserId = :UserId 676 AND DeleteAt = 0`, 677 map[string]interface{}{"ChannelId": channelId, "UserId": userId}) 678 679 if err != nil { 680 result.Err = model.NewAppError("SqlChannelStore.GetChannelUnread", "store.sql_channel.get_unread.app_error", nil, "channelId="+channelId+" "+err.Error(), http.StatusInternalServerError) 681 if err == sql.ErrNoRows { 682 result.Err.StatusCode = http.StatusNotFound 683 } 684 } else { 685 result.Data = &unreadChannel 686 } 687 }) 688 } 689 690 func (s SqlChannelStore) InvalidateChannel(id string) { 691 channelCache.Remove(id) 692 if s.metrics != nil { 693 s.metrics.IncrementMemCacheInvalidationCounter("Channel - Remove by ChannelId") 694 } 695 } 696 697 func (s SqlChannelStore) InvalidateChannelByName(teamId, name string) { 698 channelByNameCache.Remove(teamId + name) 699 if s.metrics != nil { 700 s.metrics.IncrementMemCacheInvalidationCounter("Channel by Name - Remove by TeamId and Name") 701 } 702 } 703 704 func (s SqlChannelStore) Get(id string, allowFromCache bool) store.StoreChannel { 705 return s.get(id, false, allowFromCache) 706 } 707 708 func (s SqlChannelStore) GetPinnedPosts(channelId string) store.StoreChannel { 709 return store.Do(func(result *store.StoreResult) { 710 pl := model.NewPostList() 711 712 var posts []*model.Post 713 if _, err := s.GetReplica().Select(&posts, "SELECT * FROM Posts WHERE IsPinned = true AND ChannelId = :ChannelId AND DeleteAt = 0 ORDER BY CreateAt ASC", map[string]interface{}{"ChannelId": channelId}); err != nil { 714 result.Err = model.NewAppError("SqlPostStore.GetPinnedPosts", "store.sql_channel.pinned_posts.app_error", nil, err.Error(), http.StatusInternalServerError) 715 } else { 716 for _, post := range posts { 717 pl.AddPost(post) 718 pl.AddOrder(post.Id) 719 } 720 } 721 722 result.Data = pl 723 }) 724 } 725 726 func (s SqlChannelStore) GetFromMaster(id string) store.StoreChannel { 727 return s.get(id, true, false) 728 } 729 730 func (s SqlChannelStore) get(id string, master bool, allowFromCache bool) store.StoreChannel { 731 return store.Do(func(result *store.StoreResult) { 732 var db *gorp.DbMap 733 if master { 734 db = s.GetMaster() 735 } else { 736 db = s.GetReplica() 737 } 738 739 if allowFromCache { 740 if cacheItem, ok := channelCache.Get(id); ok { 741 if s.metrics != nil { 742 s.metrics.IncrementMemCacheHitCounter("Channel") 743 } 744 result.Data = (cacheItem.(*model.Channel)).DeepCopy() 745 return 746 } 747 } 748 749 if s.metrics != nil { 750 s.metrics.IncrementMemCacheMissCounter("Channel") 751 } 752 753 obj, err := db.Get(model.Channel{}, id) 754 if err != nil { 755 result.Err = model.NewAppError("SqlChannelStore.Get", "store.sql_channel.get.find.app_error", nil, "id="+id+", "+err.Error(), http.StatusInternalServerError) 756 return 757 } 758 759 if obj == nil { 760 result.Err = model.NewAppError("SqlChannelStore.Get", "store.sql_channel.get.existing.app_error", nil, "id="+id, http.StatusNotFound) 761 return 762 } 763 764 result.Data = obj.(*model.Channel) 765 channelCache.AddWithExpiresInSecs(id, obj.(*model.Channel), CHANNEL_CACHE_SEC) 766 }) 767 } 768 769 // Delete records the given deleted timestamp to the channel in question. 770 func (s SqlChannelStore) Delete(channelId string, time int64) store.StoreChannel { 771 return s.SetDeleteAt(channelId, time, time) 772 } 773 774 // Restore reverts a previous deleted timestamp from the channel in question. 775 func (s SqlChannelStore) Restore(channelId string, time int64) store.StoreChannel { 776 return s.SetDeleteAt(channelId, 0, time) 777 } 778 779 // SetDeleteAt records the given deleted and updated timestamp to the channel in question. 780 func (s SqlChannelStore) SetDeleteAt(channelId string, deleteAt, updateAt int64) store.StoreChannel { 781 return store.Do(func(result *store.StoreResult) { 782 defer s.InvalidateChannel(channelId) 783 784 transaction, err := s.GetMaster().Begin() 785 if err != nil { 786 result.Err = model.NewAppError("SqlChannelStore.SetDeleteAt", "store.sql_channel.set_delete_at.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 787 return 788 } 789 790 *result = s.setDeleteAtT(transaction, channelId, deleteAt, updateAt) 791 if result.Err != nil { 792 transaction.Rollback() 793 return 794 } 795 796 // Additionally propagate the write to the PublicChannels table. 797 if _, err := transaction.Exec(` 798 UPDATE 799 PublicChannels 800 SET 801 DeleteAt = :DeleteAt 802 WHERE 803 Id = :ChannelId 804 `, map[string]interface{}{ 805 "DeleteAt": deleteAt, 806 "ChannelId": channelId, 807 }); err != nil { 808 transaction.Rollback() 809 result.Err = model.NewAppError("SqlChannelStore.SetDeleteAt", "store.sql_channel.set_delete_at.update_public_channel.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 810 return 811 } 812 813 if err := transaction.Commit(); err != nil { 814 result.Err = model.NewAppError("SqlChannelStore.SetDeleteAt", "store.sql_channel.set_delete_at.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 815 return 816 } 817 }) 818 } 819 820 func (s SqlChannelStore) setDeleteAtT(transaction *gorp.Transaction, channelId string, deleteAt, updateAt int64) store.StoreResult { 821 result := store.StoreResult{} 822 823 _, err := transaction.Exec("Update Channels SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :ChannelId", map[string]interface{}{"DeleteAt": deleteAt, "UpdateAt": updateAt, "ChannelId": channelId}) 824 if err != nil { 825 result.Err = model.NewAppError("SqlChannelStore.Delete", "store.sql_channel.delete.channel.app_error", nil, "id="+channelId+", err="+err.Error(), http.StatusInternalServerError) 826 return result 827 } 828 829 return result 830 } 831 832 // PermanentDeleteByTeam removes all channels for the given team from the database. 833 func (s SqlChannelStore) PermanentDeleteByTeam(teamId string) store.StoreChannel { 834 return store.Do(func(result *store.StoreResult) { 835 transaction, err := s.GetMaster().Begin() 836 if err != nil { 837 result.Err = model.NewAppError("SqlChannelStore.PermanentDeleteByTeam", "store.sql_channel.permanent_delete_by_team.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 838 return 839 } 840 841 *result = s.permanentDeleteByTeamtT(transaction, teamId) 842 if result.Err != nil { 843 transaction.Rollback() 844 return 845 } 846 847 // Additionally propagate the deletions to the PublicChannels table. 848 if _, err := transaction.Exec(` 849 DELETE FROM 850 PublicChannels 851 WHERE 852 TeamId = :TeamId 853 `, map[string]interface{}{ 854 "TeamId": teamId, 855 }); err != nil { 856 transaction.Rollback() 857 result.Err = model.NewAppError("SqlChannelStore.PermanentDeleteByTeamt", "store.sql_channel.permanent_delete_by_team.delete_public_channels.app_error", nil, "team_id="+teamId+", "+err.Error(), http.StatusInternalServerError) 858 return 859 } 860 861 if err := transaction.Commit(); err != nil { 862 result.Err = model.NewAppError("SqlChannelStore.PermanentDeleteByTeam", "store.sql_channel.permanent_delete_by_team.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 863 return 864 } 865 }) 866 } 867 868 func (s SqlChannelStore) permanentDeleteByTeamtT(transaction *gorp.Transaction, teamId string) store.StoreResult { 869 result := store.StoreResult{} 870 871 if _, err := transaction.Exec("DELETE FROM Channels WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil { 872 result.Err = model.NewAppError("SqlChannelStore.PermanentDeleteByTeam", "store.sql_channel.permanent_delete_by_team.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError) 873 return result 874 } 875 876 return result 877 } 878 879 // PermanentDelete removes the given channel from the database. 880 func (s SqlChannelStore) PermanentDelete(channelId string) store.StoreChannel { 881 return store.Do(func(result *store.StoreResult) { 882 transaction, err := s.GetMaster().Begin() 883 if err != nil { 884 result.Err = model.NewAppError("SqlChannelStore.PermanentDelete", "store.sql_channel.permanent_delete.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 885 return 886 } 887 888 *result = s.permanentDeleteT(transaction, channelId) 889 if result.Err != nil { 890 transaction.Rollback() 891 return 892 } 893 894 // Additionally propagate the deletion to the PublicChannels table. 895 if _, err := transaction.Exec(` 896 DELETE FROM 897 PublicChannels 898 WHERE 899 Id = :ChannelId 900 `, map[string]interface{}{ 901 "ChannelId": channelId, 902 }); err != nil { 903 transaction.Rollback() 904 result.Err = model.NewAppError("SqlChannelStore.PermanentDelete", "store.sql_channel.permanent_delete.delete_public_channel.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 905 return 906 } 907 908 if err := transaction.Commit(); err != nil { 909 result.Err = model.NewAppError("SqlChannelStore.PermanentDelete", "store.sql_channel.permanent_delete.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 910 return 911 } 912 }) 913 } 914 915 func (s SqlChannelStore) permanentDeleteT(transaction *gorp.Transaction, channelId string) store.StoreResult { 916 result := store.StoreResult{} 917 918 if _, err := transaction.Exec("DELETE FROM Channels WHERE Id = :ChannelId", map[string]interface{}{"ChannelId": channelId}); err != nil { 919 result.Err = model.NewAppError("SqlChannelStore.PermanentDelete", "store.sql_channel.permanent_delete.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 920 return result 921 } 922 923 return result 924 } 925 926 func (s SqlChannelStore) PermanentDeleteMembersByChannel(channelId string) store.StoreChannel { 927 return store.Do(func(result *store.StoreResult) { 928 _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId}) 929 if err != nil { 930 result.Err = model.NewAppError("SqlChannelStore.RemoveAllMembersByChannel", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 931 } 932 }) 933 } 934 935 func (s SqlChannelStore) GetChannels(teamId string, userId string, includeDeleted bool) store.StoreChannel { 936 return store.Do(func(result *store.StoreResult) { 937 query := "SELECT Channels.* FROM Channels, ChannelMembers WHERE Id = ChannelId AND UserId = :UserId AND DeleteAt = 0 AND (TeamId = :TeamId OR TeamId = '') ORDER BY DisplayName" 938 if includeDeleted { 939 query = "SELECT Channels.* FROM Channels, ChannelMembers WHERE Id = ChannelId AND UserId = :UserId AND (TeamId = :TeamId OR TeamId = '') ORDER BY DisplayName" 940 } 941 data := &model.ChannelList{} 942 _, err := s.GetReplica().Select(data, query, map[string]interface{}{"TeamId": teamId, "UserId": userId}) 943 944 if err != nil { 945 result.Err = model.NewAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 946 return 947 } 948 949 if len(*data) == 0 { 950 result.Err = model.NewAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.not_found.app_error", nil, "teamId="+teamId+", userId="+userId, http.StatusBadRequest) 951 return 952 } 953 954 result.Data = data 955 }) 956 } 957 958 func (s SqlChannelStore) GetAllChannels(offset int, limit int, includeDeleted bool) store.StoreChannel { 959 return store.Do(func(result *store.StoreResult) { 960 deleteFilter := "AND c.DeleteAt = 0" 961 if includeDeleted { 962 deleteFilter = "" 963 } 964 965 query := "SELECT c.*, Teams.DisplayName AS TeamDisplayName, Teams.Name AS TeamName, Teams.UpdateAt as TeamUpdateAt FROM Channels AS c JOIN Teams ON Teams.Id = c.TeamId WHERE (c.Type = 'P' OR c.Type = 'O') " + deleteFilter + " ORDER BY c.DisplayName, Teams.DisplayName LIMIT :Limit OFFSET :Offset" 966 967 data := &model.ChannelListWithTeamData{} 968 _, err := s.GetReplica().Select(data, query, map[string]interface{}{"Limit": limit, "Offset": offset}) 969 970 if err != nil { 971 result.Err = model.NewAppError("SqlChannelStore.GetAllChannels", "store.sql_channel.get_all_channels.get.app_error", nil, err.Error(), http.StatusInternalServerError) 972 return 973 } 974 975 result.Data = data 976 }) 977 } 978 979 func (s SqlChannelStore) GetMoreChannels(teamId string, userId string, offset int, limit int) store.StoreChannel { 980 return store.Do(func(result *store.StoreResult) { 981 data := &model.ChannelList{} 982 _, err := s.GetReplica().Select(data, ` 983 SELECT 984 Channels.* 985 FROM 986 Channels 987 JOIN 988 PublicChannels c ON (c.Id = Channels.Id) 989 WHERE 990 c.TeamId = :TeamId 991 AND c.DeleteAt = 0 992 AND c.Id NOT IN ( 993 SELECT 994 c.Id 995 FROM 996 PublicChannels c 997 JOIN 998 ChannelMembers cm ON (cm.ChannelId = c.Id) 999 WHERE 1000 c.TeamId = :TeamId 1001 AND cm.UserId = :UserId 1002 AND c.DeleteAt = 0 1003 ) 1004 ORDER BY 1005 c.DisplayName 1006 LIMIT :Limit 1007 OFFSET :Offset 1008 `, map[string]interface{}{ 1009 "TeamId": teamId, 1010 "UserId": userId, 1011 "Limit": limit, 1012 "Offset": offset, 1013 }) 1014 1015 if err != nil { 1016 result.Err = model.NewAppError("SqlChannelStore.GetMoreChannels", "store.sql_channel.get_more_channels.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 1017 return 1018 } 1019 1020 result.Data = data 1021 }) 1022 } 1023 1024 func (s SqlChannelStore) GetPublicChannelsForTeam(teamId string, offset int, limit int) store.StoreChannel { 1025 return store.Do(func(result *store.StoreResult) { 1026 data := &model.ChannelList{} 1027 _, err := s.GetReplica().Select(data, ` 1028 SELECT 1029 Channels.* 1030 FROM 1031 Channels 1032 JOIN 1033 PublicChannels pc ON (pc.Id = Channels.Id) 1034 WHERE 1035 pc.TeamId = :TeamId 1036 AND pc.DeleteAt = 0 1037 ORDER BY pc.DisplayName 1038 LIMIT :Limit 1039 OFFSET :Offset 1040 `, map[string]interface{}{ 1041 "TeamId": teamId, 1042 "Limit": limit, 1043 "Offset": offset, 1044 }) 1045 1046 if err != nil { 1047 result.Err = model.NewAppError("SqlChannelStore.GetPublicChannelsForTeam", "store.sql_channel.get_public_channels.get.app_error", nil, "teamId="+teamId+", err="+err.Error(), http.StatusInternalServerError) 1048 return 1049 } 1050 1051 result.Data = data 1052 }) 1053 } 1054 1055 func (s SqlChannelStore) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) store.StoreChannel { 1056 return store.Do(func(result *store.StoreResult) { 1057 props := make(map[string]interface{}) 1058 props["teamId"] = teamId 1059 1060 idQuery := "" 1061 1062 for index, channelId := range channelIds { 1063 if len(idQuery) > 0 { 1064 idQuery += ", " 1065 } 1066 1067 props["channelId"+strconv.Itoa(index)] = channelId 1068 idQuery += ":channelId" + strconv.Itoa(index) 1069 } 1070 1071 data := &model.ChannelList{} 1072 _, err := s.GetReplica().Select(data, ` 1073 SELECT 1074 Channels.* 1075 FROM 1076 Channels 1077 JOIN 1078 PublicChannels pc ON (pc.Id = Channels.Id) 1079 WHERE 1080 pc.TeamId = :teamId 1081 AND pc.DeleteAt = 0 1082 AND pc.Id IN (`+idQuery+`) 1083 ORDER BY pc.DisplayName 1084 `, props) 1085 1086 if err != nil { 1087 result.Err = model.NewAppError("SqlChannelStore.GetPublicChannelsByIdsForTeam", "store.sql_channel.get_channels_by_ids.get.app_error", nil, err.Error(), http.StatusInternalServerError) 1088 } 1089 1090 if len(*data) == 0 { 1091 result.Err = model.NewAppError("SqlChannelStore.GetPublicChannelsByIdsForTeam", "store.sql_channel.get_channels_by_ids.not_found.app_error", nil, "", http.StatusNotFound) 1092 } 1093 1094 result.Data = data 1095 }) 1096 } 1097 1098 type channelIdWithCountAndUpdateAt struct { 1099 Id string 1100 TotalMsgCount int64 1101 UpdateAt int64 1102 } 1103 1104 func (s SqlChannelStore) GetChannelCounts(teamId string, userId string) store.StoreChannel { 1105 return store.Do(func(result *store.StoreResult) { 1106 var data []channelIdWithCountAndUpdateAt 1107 _, err := s.GetReplica().Select(&data, "SELECT Id, TotalMsgCount, UpdateAt FROM Channels WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) AND (TeamId = :TeamId OR TeamId = '') AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId}) 1108 1109 if err != nil { 1110 result.Err = model.NewAppError("SqlChannelStore.GetChannelCounts", "store.sql_channel.get_channel_counts.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 1111 return 1112 } 1113 1114 counts := &model.ChannelCounts{Counts: make(map[string]int64), UpdateTimes: make(map[string]int64)} 1115 for i := range data { 1116 v := data[i] 1117 counts.Counts[v.Id] = v.TotalMsgCount 1118 counts.UpdateTimes[v.Id] = v.UpdateAt 1119 } 1120 1121 result.Data = counts 1122 }) 1123 } 1124 1125 func (s SqlChannelStore) GetTeamChannels(teamId string) store.StoreChannel { 1126 return store.Do(func(result *store.StoreResult) { 1127 data := &model.ChannelList{} 1128 _, err := s.GetReplica().Select(data, "SELECT * FROM Channels WHERE TeamId = :TeamId And Type != 'D' ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId}) 1129 1130 if err != nil { 1131 result.Err = model.NewAppError("SqlChannelStore.GetTeamChannels", "store.sql_channel.get_channels.get.app_error", nil, "teamId="+teamId+", err="+err.Error(), http.StatusInternalServerError) 1132 return 1133 } 1134 1135 if len(*data) == 0 { 1136 result.Err = model.NewAppError("SqlChannelStore.GetTeamChannels", "store.sql_channel.get_channels.not_found.app_error", nil, "teamId="+teamId, http.StatusNotFound) 1137 return 1138 } 1139 1140 result.Data = data 1141 }) 1142 } 1143 1144 func (s SqlChannelStore) GetByName(teamId string, name string, allowFromCache bool) store.StoreChannel { 1145 return s.getByName(teamId, name, false, allowFromCache) 1146 } 1147 1148 func (s SqlChannelStore) GetByNames(teamId string, names []string, allowFromCache bool) store.StoreChannel { 1149 return store.Do(func(result *store.StoreResult) { 1150 var channels []*model.Channel 1151 1152 if allowFromCache { 1153 var misses []string 1154 visited := make(map[string]struct{}) 1155 for _, name := range names { 1156 if _, ok := visited[name]; ok { 1157 continue 1158 } 1159 visited[name] = struct{}{} 1160 if cacheItem, ok := channelByNameCache.Get(teamId + name); ok { 1161 if s.metrics != nil { 1162 s.metrics.IncrementMemCacheHitCounter("Channel By Name") 1163 } 1164 channels = append(channels, cacheItem.(*model.Channel)) 1165 } else { 1166 if s.metrics != nil { 1167 s.metrics.IncrementMemCacheMissCounter("Channel By Name") 1168 } 1169 misses = append(misses, name) 1170 } 1171 } 1172 names = misses 1173 } 1174 1175 if len(names) > 0 { 1176 props := map[string]interface{}{} 1177 var namePlaceholders []string 1178 for _, name := range names { 1179 key := fmt.Sprintf("Name%v", len(namePlaceholders)) 1180 props[key] = name 1181 namePlaceholders = append(namePlaceholders, ":"+key) 1182 } 1183 1184 var query string 1185 if teamId == "" { 1186 query = `SELECT * FROM Channels WHERE Name IN (` + strings.Join(namePlaceholders, ", ") + `) AND DeleteAt = 0` 1187 } else { 1188 props["TeamId"] = teamId 1189 query = `SELECT * FROM Channels WHERE Name IN (` + strings.Join(namePlaceholders, ", ") + `) AND TeamId = :TeamId AND DeleteAt = 0` 1190 } 1191 1192 var dbChannels []*model.Channel 1193 if _, err := s.GetReplica().Select(&dbChannels, query, props); err != nil && err != sql.ErrNoRows { 1194 result.Err = model.NewAppError("SqlChannelStore.GetByName", "store.sql_channel.get_by_name.existing.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError) 1195 return 1196 } 1197 for _, channel := range dbChannels { 1198 channelByNameCache.AddWithExpiresInSecs(teamId+channel.Name, channel, CHANNEL_CACHE_SEC) 1199 channels = append(channels, channel) 1200 } 1201 } 1202 1203 result.Data = channels 1204 }) 1205 } 1206 1207 func (s SqlChannelStore) GetByNameIncludeDeleted(teamId string, name string, allowFromCache bool) store.StoreChannel { 1208 return s.getByName(teamId, name, true, allowFromCache) 1209 } 1210 1211 func (s SqlChannelStore) getByName(teamId string, name string, includeDeleted bool, allowFromCache bool) store.StoreChannel { 1212 var query string 1213 if includeDeleted { 1214 query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name" 1215 } else { 1216 query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name AND DeleteAt = 0" 1217 } 1218 return store.Do(func(result *store.StoreResult) { 1219 channel := model.Channel{} 1220 1221 if allowFromCache { 1222 if cacheItem, ok := channelByNameCache.Get(teamId + name); ok { 1223 if s.metrics != nil { 1224 s.metrics.IncrementMemCacheHitCounter("Channel By Name") 1225 } 1226 result.Data = cacheItem.(*model.Channel) 1227 return 1228 } 1229 if s.metrics != nil { 1230 s.metrics.IncrementMemCacheMissCounter("Channel By Name") 1231 } 1232 } 1233 1234 if err := s.GetReplica().SelectOne(&channel, query, map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil { 1235 if err == sql.ErrNoRows { 1236 result.Err = model.NewAppError("SqlChannelStore.GetByName", store.MISSING_CHANNEL_ERROR, nil, "teamId="+teamId+", "+"name="+name+", "+err.Error(), http.StatusNotFound) 1237 return 1238 } 1239 result.Err = model.NewAppError("SqlChannelStore.GetByName", "store.sql_channel.get_by_name.existing.app_error", nil, "teamId="+teamId+", "+"name="+name+", "+err.Error(), http.StatusInternalServerError) 1240 return 1241 } 1242 1243 result.Data = &channel 1244 channelByNameCache.AddWithExpiresInSecs(teamId+name, &channel, CHANNEL_CACHE_SEC) 1245 }) 1246 } 1247 1248 func (s SqlChannelStore) GetDeletedByName(teamId string, name string) store.StoreChannel { 1249 return store.Do(func(result *store.StoreResult) { 1250 channel := model.Channel{} 1251 1252 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 { 1253 if err == sql.ErrNoRows { 1254 result.Err = model.NewAppError("SqlChannelStore.GetDeletedByName", "store.sql_channel.get_deleted_by_name.missing.app_error", nil, "teamId="+teamId+", "+"name="+name+", "+err.Error(), http.StatusNotFound) 1255 return 1256 } 1257 result.Err = model.NewAppError("SqlChannelStore.GetDeletedByName", "store.sql_channel.get_deleted_by_name.existing.app_error", nil, "teamId="+teamId+", "+"name="+name+", "+err.Error(), http.StatusInternalServerError) 1258 return 1259 } 1260 1261 result.Data = &channel 1262 }) 1263 } 1264 1265 func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int) store.StoreChannel { 1266 return store.Do(func(result *store.StoreResult) { 1267 channels := &model.ChannelList{} 1268 1269 if _, err := s.GetReplica().Select(channels, "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND DeleteAt != 0 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset", map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset}); err != nil { 1270 if err == sql.ErrNoRows { 1271 result.Err = model.NewAppError("SqlChannelStore.GetDeleted", "store.sql_channel.get_deleted.missing.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusNotFound) 1272 return 1273 } 1274 result.Err = model.NewAppError("SqlChannelStore.GetDeleted", "store.sql_channel.get_deleted.existing.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError) 1275 return 1276 } 1277 1278 result.Data = channels 1279 }) 1280 } 1281 1282 var CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY = ` 1283 SELECT 1284 ChannelMembers.*, 1285 TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole, 1286 TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole, 1287 ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole, 1288 ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole 1289 FROM 1290 ChannelMembers 1291 INNER JOIN 1292 Channels ON ChannelMembers.ChannelId = Channels.Id 1293 LEFT JOIN 1294 Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id 1295 LEFT JOIN 1296 Teams ON Channels.TeamId = Teams.Id 1297 LEFT JOIN 1298 Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id 1299 ` 1300 1301 func (s SqlChannelStore) SaveMember(member *model.ChannelMember) store.StoreChannel { 1302 return store.Do(func(result *store.StoreResult) { 1303 defer s.InvalidateAllChannelMembersForUser(member.UserId) 1304 1305 // Grab the channel we are saving this member to 1306 cr := <-s.GetFromMaster(member.ChannelId) 1307 if cr.Err != nil { 1308 result.Err = cr.Err 1309 return 1310 } 1311 1312 channel := cr.Data.(*model.Channel) 1313 1314 transaction, err := s.GetMaster().Begin() 1315 if err != nil { 1316 result.Err = model.NewAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 1317 return 1318 } 1319 1320 *result = s.saveMemberT(transaction, member, channel) 1321 if result.Err != nil { 1322 transaction.Rollback() 1323 return 1324 } 1325 1326 if err := transaction.Commit(); err != nil { 1327 result.Err = model.NewAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 1328 return 1329 } 1330 }) 1331 } 1332 1333 func (s SqlChannelStore) saveMemberT(transaction *gorp.Transaction, member *model.ChannelMember, channel *model.Channel) store.StoreResult { 1334 result := store.StoreResult{} 1335 1336 member.PreSave() 1337 if result.Err = member.IsValid(); result.Err != nil { 1338 return result 1339 } 1340 1341 dbMember := NewChannelMemberFromModel(member) 1342 1343 if err := transaction.Insert(dbMember); err != nil { 1344 if IsUniqueConstraintError(err, []string{"ChannelId", "channelmembers_pkey"}) { 1345 result.Err = model.NewAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.exists.app_error", nil, "channel_id="+member.ChannelId+", user_id="+member.UserId+", "+err.Error(), http.StatusBadRequest) 1346 return result 1347 } 1348 result.Err = model.NewAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.save.app_error", nil, "channel_id="+member.ChannelId+", user_id="+member.UserId+", "+err.Error(), http.StatusInternalServerError) 1349 return result 1350 } 1351 1352 var retrievedMember channelMemberWithSchemeRoles 1353 if err := transaction.SelectOne(&retrievedMember, CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId", map[string]interface{}{"ChannelId": dbMember.ChannelId, "UserId": dbMember.UserId}); err != nil { 1354 if err == sql.ErrNoRows { 1355 result.Err = model.NewAppError("SqlChannelStore.GetMember", store.MISSING_CHANNEL_MEMBER_ERROR, nil, "channel_id="+dbMember.ChannelId+"user_id="+dbMember.UserId+","+err.Error(), http.StatusNotFound) 1356 return result 1357 } 1358 result.Err = model.NewAppError("SqlChannelStore.GetMember", "store.sql_channel.get_member.app_error", nil, "channel_id="+dbMember.ChannelId+"user_id="+dbMember.UserId+","+err.Error(), http.StatusInternalServerError) 1359 return result 1360 } 1361 1362 result.Data = retrievedMember.ToModel() 1363 return result 1364 } 1365 1366 func (s SqlChannelStore) UpdateMember(member *model.ChannelMember) store.StoreChannel { 1367 return store.Do(func(result *store.StoreResult) { 1368 member.PreUpdate() 1369 1370 if result.Err = member.IsValid(); result.Err != nil { 1371 return 1372 } 1373 1374 if _, err := s.GetMaster().Update(NewChannelMemberFromModel(member)); err != nil { 1375 result.Err = model.NewAppError("SqlChannelStore.UpdateMember", "store.sql_channel.update_member.app_error", nil, "channel_id="+member.ChannelId+", "+"user_id="+member.UserId+", "+err.Error(), http.StatusInternalServerError) 1376 return 1377 } 1378 1379 var dbMember channelMemberWithSchemeRoles 1380 1381 if err := s.GetReplica().SelectOne(&dbMember, CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId", map[string]interface{}{"ChannelId": member.ChannelId, "UserId": member.UserId}); err != nil { 1382 if err == sql.ErrNoRows { 1383 result.Err = model.NewAppError("SqlChannelStore.GetMember", store.MISSING_CHANNEL_MEMBER_ERROR, nil, "channel_id="+member.ChannelId+"user_id="+member.UserId+","+err.Error(), http.StatusNotFound) 1384 return 1385 } 1386 result.Err = model.NewAppError("SqlChannelStore.GetMember", "store.sql_channel.get_member.app_error", nil, "channel_id="+member.ChannelId+"user_id="+member.UserId+","+err.Error(), http.StatusInternalServerError) 1387 return 1388 } 1389 result.Data = dbMember.ToModel() 1390 }) 1391 } 1392 1393 func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) store.StoreChannel { 1394 return store.Do(func(result *store.StoreResult) { 1395 var dbMembers channelMemberWithSchemeRolesList 1396 _, err := s.GetReplica().Select(&dbMembers, CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE ChannelId = :ChannelId LIMIT :Limit OFFSET :Offset", map[string]interface{}{"ChannelId": channelId, "Limit": limit, "Offset": offset}) 1397 if err != nil { 1398 result.Err = model.NewAppError("SqlChannelStore.GetMembers", "store.sql_channel.get_members.app_error", nil, "channel_id="+channelId+","+err.Error(), http.StatusInternalServerError) 1399 return 1400 } 1401 1402 result.Data = dbMembers.ToModel() 1403 }) 1404 } 1405 1406 func (s SqlChannelStore) GetChannelMembersTimezones(channelId string) store.StoreChannel { 1407 return store.Do(func(result *store.StoreResult) { 1408 var dbMembersTimezone []map[string]string 1409 _, err := s.GetReplica().Select(&dbMembersTimezone, ` 1410 SELECT 1411 Users.Timezone 1412 FROM 1413 ChannelMembers 1414 LEFT JOIN 1415 Users ON ChannelMembers.UserId = Id 1416 WHERE ChannelId = :ChannelId 1417 `, map[string]interface{}{ 1418 "ChannelId": channelId}) 1419 if err != nil { 1420 result.Err = model.NewAppError("SqlChannelStore.GetChannelMembersTimezones", "store.sql_channel.get_members.app_error", nil, "channel_id="+channelId+","+err.Error(), http.StatusInternalServerError) 1421 return 1422 } 1423 result.Data = dbMembersTimezone 1424 }) 1425 } 1426 1427 func (s SqlChannelStore) GetMember(channelId string, userId string) store.StoreChannel { 1428 return store.Do(func(result *store.StoreResult) { 1429 var dbMember channelMemberWithSchemeRoles 1430 1431 if err := s.GetReplica().SelectOne(&dbMember, CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil { 1432 if err == sql.ErrNoRows { 1433 result.Err = model.NewAppError("SqlChannelStore.GetMember", store.MISSING_CHANNEL_MEMBER_ERROR, nil, "channel_id="+channelId+"user_id="+userId+","+err.Error(), http.StatusNotFound) 1434 return 1435 } 1436 result.Err = model.NewAppError("SqlChannelStore.GetMember", "store.sql_channel.get_member.app_error", nil, "channel_id="+channelId+"user_id="+userId+","+err.Error(), http.StatusInternalServerError) 1437 return 1438 } 1439 1440 result.Data = dbMember.ToModel() 1441 }) 1442 } 1443 1444 func (s SqlChannelStore) InvalidateAllChannelMembersForUser(userId string) { 1445 allChannelMembersForUserCache.Remove(userId) 1446 allChannelMembersForUserCache.Remove(userId + "_deleted") 1447 if s.metrics != nil { 1448 s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members for User - Remove by UserId") 1449 } 1450 } 1451 1452 func (s SqlChannelStore) IsUserInChannelUseCache(userId string, channelId string) bool { 1453 if cacheItem, ok := allChannelMembersForUserCache.Get(userId); ok { 1454 if s.metrics != nil { 1455 s.metrics.IncrementMemCacheHitCounter("All Channel Members for User") 1456 } 1457 ids := cacheItem.(map[string]string) 1458 if _, ok := ids[channelId]; ok { 1459 return true 1460 } 1461 return false 1462 } 1463 1464 if s.metrics != nil { 1465 s.metrics.IncrementMemCacheMissCounter("All Channel Members for User") 1466 } 1467 1468 result := <-s.GetAllChannelMembersForUser(userId, true, false) 1469 if result.Err != nil { 1470 mlog.Error("SqlChannelStore.IsUserInChannelUseCache: " + result.Err.Error()) 1471 return false 1472 } 1473 1474 ids := result.Data.(map[string]string) 1475 if _, ok := ids[channelId]; ok { 1476 return true 1477 } 1478 1479 return false 1480 } 1481 1482 func (s SqlChannelStore) GetMemberForPost(postId string, userId string) store.StoreChannel { 1483 return store.Do(func(result *store.StoreResult) { 1484 var dbMember channelMemberWithSchemeRoles 1485 if err := s.GetReplica().SelectOne(&dbMember, 1486 ` 1487 SELECT 1488 ChannelMembers.*, 1489 TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole, 1490 TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole, 1491 ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole, 1492 ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole 1493 FROM 1494 ChannelMembers 1495 INNER JOIN 1496 Posts ON ChannelMembers.ChannelId = Posts.ChannelId 1497 INNER JOIN 1498 Channels ON ChannelMembers.ChannelId = Channels.Id 1499 LEFT JOIN 1500 Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id 1501 LEFT JOIN 1502 Teams ON Channels.TeamId = Teams.Id 1503 LEFT JOIN 1504 Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id 1505 WHERE 1506 ChannelMembers.UserId = :UserId 1507 AND Posts.Id = :PostId`, map[string]interface{}{"UserId": userId, "PostId": postId}); err != nil { 1508 result.Err = model.NewAppError("SqlChannelStore.GetMemberForPost", "store.sql_channel.get_member_for_post.app_error", nil, "postId="+postId+", err="+err.Error(), http.StatusInternalServerError) 1509 return 1510 } 1511 result.Data = dbMember.ToModel() 1512 }) 1513 } 1514 1515 func (s SqlChannelStore) GetAllChannelMembersForUser(userId string, allowFromCache bool, includeDeleted bool) store.StoreChannel { 1516 return store.Do(func(result *store.StoreResult) { 1517 cache_key := userId 1518 if includeDeleted { 1519 cache_key += "_deleted" 1520 } 1521 if allowFromCache { 1522 if cacheItem, ok := allChannelMembersForUserCache.Get(cache_key); ok { 1523 if s.metrics != nil { 1524 s.metrics.IncrementMemCacheHitCounter("All Channel Members for User") 1525 } 1526 result.Data = cacheItem.(map[string]string) 1527 return 1528 } 1529 } 1530 1531 if s.metrics != nil { 1532 s.metrics.IncrementMemCacheMissCounter("All Channel Members for User") 1533 } 1534 1535 var deletedClause string 1536 if !includeDeleted { 1537 deletedClause = "Channels.DeleteAt = 0 AND" 1538 } 1539 1540 var data allChannelMembers 1541 _, err := s.GetReplica().Select(&data, ` 1542 SELECT 1543 ChannelMembers.ChannelId, ChannelMembers.Roles, ChannelMembers.SchemeUser, ChannelMembers.SchemeAdmin, 1544 TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole, 1545 TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole, 1546 ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole, 1547 ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole 1548 FROM 1549 ChannelMembers 1550 INNER JOIN 1551 Channels ON ChannelMembers.ChannelId = Channels.Id 1552 LEFT JOIN 1553 Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id 1554 LEFT JOIN 1555 Teams ON Channels.TeamId = Teams.Id 1556 LEFT JOIN 1557 Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id 1558 WHERE 1559 `+deletedClause+` 1560 ChannelMembers.UserId = :UserId`, map[string]interface{}{"UserId": userId}) 1561 1562 if err != nil { 1563 result.Err = model.NewAppError("SqlChannelStore.GetAllChannelMembersForUser", "store.sql_channel.get_channels.get.app_error", nil, "userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 1564 return 1565 } 1566 1567 ids := data.ToMapStringString() 1568 result.Data = ids 1569 1570 if allowFromCache { 1571 allChannelMembersForUserCache.AddWithExpiresInSecs(cache_key, ids, ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SEC) 1572 } 1573 }) 1574 } 1575 1576 func (s SqlChannelStore) InvalidateCacheForChannelMembersNotifyProps(channelId string) { 1577 allChannelMembersNotifyPropsForChannelCache.Remove(channelId) 1578 if s.metrics != nil { 1579 s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members Notify Props for Channel - Remove by ChannelId") 1580 } 1581 } 1582 1583 type allChannelMemberNotifyProps struct { 1584 UserId string 1585 NotifyProps model.StringMap 1586 } 1587 1588 func (s SqlChannelStore) GetAllChannelMembersNotifyPropsForChannel(channelId string, allowFromCache bool) store.StoreChannel { 1589 return store.Do(func(result *store.StoreResult) { 1590 if allowFromCache { 1591 if cacheItem, ok := allChannelMembersNotifyPropsForChannelCache.Get(channelId); ok { 1592 if s.metrics != nil { 1593 s.metrics.IncrementMemCacheHitCounter("All Channel Members Notify Props for Channel") 1594 } 1595 result.Data = cacheItem.(map[string]model.StringMap) 1596 return 1597 } 1598 } 1599 1600 if s.metrics != nil { 1601 s.metrics.IncrementMemCacheMissCounter("All Channel Members Notify Props for Channel") 1602 } 1603 1604 var data []allChannelMemberNotifyProps 1605 _, err := s.GetReplica().Select(&data, ` 1606 SELECT UserId, NotifyProps 1607 FROM ChannelMembers 1608 WHERE ChannelId = :ChannelId`, map[string]interface{}{"ChannelId": channelId}) 1609 1610 if err != nil { 1611 result.Err = model.NewAppError("SqlChannelStore.GetAllChannelMembersPropsForChannel", "store.sql_channel.get_members.app_error", nil, "channelId="+channelId+", err="+err.Error(), http.StatusInternalServerError) 1612 return 1613 } 1614 1615 props := make(map[string]model.StringMap) 1616 for i := range data { 1617 props[data[i].UserId] = data[i].NotifyProps 1618 } 1619 1620 result.Data = props 1621 1622 allChannelMembersNotifyPropsForChannelCache.AddWithExpiresInSecs(channelId, props, ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SEC) 1623 }) 1624 } 1625 1626 func (s SqlChannelStore) InvalidateMemberCount(channelId string) { 1627 channelMemberCountsCache.Remove(channelId) 1628 if s.metrics != nil { 1629 s.metrics.IncrementMemCacheInvalidationCounter("Channel Member Counts - Remove by ChannelId") 1630 } 1631 } 1632 1633 func (s SqlChannelStore) GetMemberCountFromCache(channelId string) int64 { 1634 if cacheItem, ok := channelMemberCountsCache.Get(channelId); ok { 1635 if s.metrics != nil { 1636 s.metrics.IncrementMemCacheHitCounter("Channel Member Counts") 1637 } 1638 return cacheItem.(int64) 1639 } 1640 1641 if s.metrics != nil { 1642 s.metrics.IncrementMemCacheMissCounter("Channel Member Counts") 1643 } 1644 1645 result := <-s.GetMemberCount(channelId, true) 1646 if result.Err != nil { 1647 return 0 1648 } 1649 1650 return result.Data.(int64) 1651 } 1652 1653 func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) store.StoreChannel { 1654 return store.Do(func(result *store.StoreResult) { 1655 if allowFromCache { 1656 if cacheItem, ok := channelMemberCountsCache.Get(channelId); ok { 1657 if s.metrics != nil { 1658 s.metrics.IncrementMemCacheHitCounter("Channel Member Counts") 1659 } 1660 result.Data = cacheItem.(int64) 1661 return 1662 } 1663 } 1664 1665 if s.metrics != nil { 1666 s.metrics.IncrementMemCacheMissCounter("Channel Member Counts") 1667 } 1668 1669 count, err := s.GetReplica().SelectInt(` 1670 SELECT 1671 count(*) 1672 FROM 1673 ChannelMembers, 1674 Users 1675 WHERE 1676 ChannelMembers.UserId = Users.Id 1677 AND ChannelMembers.ChannelId = :ChannelId 1678 AND Users.DeleteAt = 0`, map[string]interface{}{"ChannelId": channelId}) 1679 if err != nil { 1680 result.Err = model.NewAppError("SqlChannelStore.GetMemberCount", "store.sql_channel.get_member_count.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 1681 return 1682 } 1683 result.Data = count 1684 1685 if allowFromCache { 1686 channelMemberCountsCache.AddWithExpiresInSecs(channelId, count, CHANNEL_MEMBERS_COUNTS_CACHE_SEC) 1687 } 1688 }) 1689 } 1690 1691 func (s SqlChannelStore) RemoveMember(channelId string, userId string) store.StoreChannel { 1692 return store.Do(func(result *store.StoreResult) { 1693 _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE ChannelId = :ChannelId AND UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}) 1694 if err != nil { 1695 result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError) 1696 } 1697 }) 1698 } 1699 1700 func (s SqlChannelStore) RemoveAllDeactivatedMembers(channelId string) store.StoreChannel { 1701 return store.Do(func(result *store.StoreResult) { 1702 query := ` 1703 DELETE 1704 FROM 1705 ChannelMembers 1706 WHERE 1707 UserId IN ( 1708 SELECT 1709 Id 1710 FROM 1711 Users 1712 WHERE 1713 Users.DeleteAt != 0 1714 ) 1715 AND 1716 ChannelMembers.ChannelId = :ChannelId 1717 ` 1718 1719 _, err := s.GetMaster().Exec(query, map[string]interface{}{"ChannelId": channelId}) 1720 if err != nil { 1721 result.Err = model.NewAppError("SqlChannelStore.RemoveAllDeactivatedMembers", "store.sql_channel.remove_all_deactivated_members.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 1722 } 1723 }) 1724 } 1725 1726 func (s SqlChannelStore) PermanentDeleteMembersByUser(userId string) store.StoreChannel { 1727 return store.Do(func(result *store.StoreResult) { 1728 if _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil { 1729 result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_channel.permanent_delete_members_by_user.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError) 1730 } 1731 }) 1732 } 1733 1734 func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string) store.StoreChannel { 1735 return store.Do(func(result *store.StoreResult) { 1736 props := make(map[string]interface{}) 1737 1738 updateIdQuery := "" 1739 for index, channelId := range channelIds { 1740 if len(updateIdQuery) > 0 { 1741 updateIdQuery += " OR " 1742 } 1743 1744 props["channelId"+strconv.Itoa(index)] = channelId 1745 updateIdQuery += "ChannelId = :channelId" + strconv.Itoa(index) 1746 } 1747 1748 selectIdQuery := strings.Replace(updateIdQuery, "ChannelId", "Id", -1) 1749 1750 var lastPostAtTimes []struct { 1751 Id string 1752 LastPostAt int64 1753 TotalMsgCount int64 1754 } 1755 1756 selectQuery := "SELECT Id, LastPostAt, TotalMsgCount FROM Channels WHERE (" + selectIdQuery + ")" 1757 1758 if _, err := s.GetMaster().Select(&lastPostAtTimes, selectQuery, props); err != nil || len(lastPostAtTimes) <= 0 { 1759 var extra string 1760 status := http.StatusInternalServerError 1761 if err == nil { 1762 status = http.StatusBadRequest 1763 extra = "No channels found" 1764 } else { 1765 extra = err.Error() 1766 } 1767 result.Err = model.NewAppError("SqlChannelStore.UpdateLastViewedAt", "store.sql_channel.update_last_viewed_at.app_error", nil, "channel_ids="+strings.Join(channelIds, ",")+", user_id="+userId+", "+extra, status) 1768 return 1769 } 1770 1771 times := map[string]int64{} 1772 msgCountQuery := "" 1773 lastViewedQuery := "" 1774 for index, t := range lastPostAtTimes { 1775 times[t.Id] = t.LastPostAt 1776 1777 props["msgCount"+strconv.Itoa(index)] = t.TotalMsgCount 1778 msgCountQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(MsgCount, :msgCount%d) ", index, index) 1779 1780 props["lastViewed"+strconv.Itoa(index)] = t.LastPostAt 1781 lastViewedQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(LastViewedAt, :lastViewed%d) ", index, index) 1782 1783 props["channelId"+strconv.Itoa(index)] = t.Id 1784 } 1785 1786 var updateQuery string 1787 1788 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 1789 updateQuery = `UPDATE 1790 ChannelMembers 1791 SET 1792 MentionCount = 0, 1793 MsgCount = CAST(CASE ChannelId ` + msgCountQuery + ` END AS BIGINT), 1794 LastViewedAt = CAST(CASE ChannelId ` + lastViewedQuery + ` END AS BIGINT), 1795 LastUpdateAt = CAST(CASE ChannelId ` + lastViewedQuery + ` END AS BIGINT) 1796 WHERE 1797 UserId = :UserId 1798 AND (` + updateIdQuery + `)` 1799 } else if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 1800 updateQuery = `UPDATE 1801 ChannelMembers 1802 SET 1803 MentionCount = 0, 1804 MsgCount = CASE ChannelId ` + msgCountQuery + ` END, 1805 LastViewedAt = CASE ChannelId ` + lastViewedQuery + ` END, 1806 LastUpdateAt = CASE ChannelId ` + lastViewedQuery + ` END 1807 WHERE 1808 UserId = :UserId 1809 AND (` + updateIdQuery + `)` 1810 } 1811 1812 props["UserId"] = userId 1813 1814 if _, err := s.GetMaster().Exec(updateQuery, props); err != nil { 1815 result.Err = model.NewAppError("SqlChannelStore.UpdateLastViewedAt", "store.sql_channel.update_last_viewed_at.app_error", nil, "channel_ids="+strings.Join(channelIds, ",")+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError) 1816 return 1817 } 1818 1819 result.Data = times 1820 }) 1821 } 1822 1823 func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string) store.StoreChannel { 1824 return store.Do(func(result *store.StoreResult) { 1825 _, err := s.GetMaster().Exec( 1826 `UPDATE 1827 ChannelMembers 1828 SET 1829 MentionCount = MentionCount + 1, 1830 LastUpdateAt = :LastUpdateAt 1831 WHERE 1832 UserId = :UserId 1833 AND ChannelId = :ChannelId`, 1834 map[string]interface{}{"ChannelId": channelId, "UserId": userId, "LastUpdateAt": model.GetMillis()}) 1835 if err != nil { 1836 result.Err = model.NewAppError("SqlChannelStore.IncrementMentionCount", "store.sql_channel.increment_mention_count.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError) 1837 } 1838 }) 1839 } 1840 1841 func (s SqlChannelStore) GetAll(teamId string) store.StoreChannel { 1842 return store.Do(func(result *store.StoreResult) { 1843 var data []*model.Channel 1844 _, err := s.GetReplica().Select(&data, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Type != 'D' ORDER BY Name", map[string]interface{}{"TeamId": teamId}) 1845 1846 if err != nil { 1847 result.Err = model.NewAppError("SqlChannelStore.GetAll", "store.sql_channel.get_all.app_error", nil, "teamId="+teamId+", err="+err.Error(), http.StatusInternalServerError) 1848 return 1849 } 1850 1851 result.Data = data 1852 }) 1853 } 1854 1855 func (s SqlChannelStore) GetForPost(postId string) store.StoreChannel { 1856 return store.Do(func(result *store.StoreResult) { 1857 channel := &model.Channel{} 1858 if err := s.GetReplica().SelectOne( 1859 channel, 1860 `SELECT 1861 Channels.* 1862 FROM 1863 Channels, 1864 Posts 1865 WHERE 1866 Channels.Id = Posts.ChannelId 1867 AND Posts.Id = :PostId`, map[string]interface{}{"PostId": postId}); err != nil { 1868 result.Err = model.NewAppError("SqlChannelStore.GetForPost", "store.sql_channel.get_for_post.app_error", nil, "postId="+postId+", err="+err.Error(), http.StatusInternalServerError) 1869 return 1870 } 1871 1872 result.Data = channel 1873 }) 1874 } 1875 1876 func (s SqlChannelStore) AnalyticsTypeCount(teamId string, channelType string) store.StoreChannel { 1877 return store.Do(func(result *store.StoreResult) { 1878 query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType" 1879 1880 if len(teamId) > 0 { 1881 query += " AND TeamId = :TeamId" 1882 } 1883 1884 v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId, "ChannelType": channelType}) 1885 if err != nil { 1886 result.Err = model.NewAppError("SqlChannelStore.AnalyticsTypeCount", "store.sql_channel.analytics_type_count.app_error", nil, err.Error(), http.StatusInternalServerError) 1887 return 1888 } 1889 1890 result.Data = v 1891 }) 1892 } 1893 1894 func (s SqlChannelStore) AnalyticsDeletedTypeCount(teamId string, channelType string) store.StoreChannel { 1895 return store.Do(func(result *store.StoreResult) { 1896 query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType AND DeleteAt > 0" 1897 1898 if len(teamId) > 0 { 1899 query += " AND TeamId = :TeamId" 1900 } 1901 1902 v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId, "ChannelType": channelType}) 1903 if err != nil { 1904 result.Err = model.NewAppError("SqlChannelStore.AnalyticsDeletedTypeCount", "store.sql_channel.analytics_deleted_type_count.app_error", nil, err.Error(), http.StatusInternalServerError) 1905 return 1906 } 1907 1908 result.Data = v 1909 }) 1910 } 1911 1912 func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) store.StoreChannel { 1913 return store.Do(func(result *store.StoreResult) { 1914 var dbMembers channelMemberWithSchemeRolesList 1915 _, err := s.GetReplica().Select(&dbMembers, CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE ChannelMembers.UserId = :UserId", map[string]interface{}{"TeamId": teamId, "UserId": userId}) 1916 1917 if err != nil { 1918 result.Err = model.NewAppError("SqlChannelStore.GetMembersForUser", "store.sql_channel.get_members.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 1919 return 1920 } 1921 1922 result.Data = dbMembers.ToModel() 1923 }) 1924 } 1925 1926 func (s SqlChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) store.StoreChannel { 1927 return store.Do(func(result *store.StoreResult) { 1928 deleteFilter := "AND c.DeleteAt = 0" 1929 if includeDeleted { 1930 deleteFilter = "" 1931 } 1932 1933 queryFormat := ` 1934 SELECT 1935 Channels.* 1936 FROM 1937 Channels 1938 JOIN 1939 PublicChannels c ON (c.Id = Channels.Id) 1940 WHERE 1941 c.TeamId = :TeamId 1942 ` + deleteFilter + ` 1943 %v 1944 LIMIT 50 1945 ` 1946 1947 var channels model.ChannelList 1948 1949 if likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose"); likeClause == "" { 1950 if _, err := s.GetReplica().Select(&channels, fmt.Sprintf(queryFormat, ""), map[string]interface{}{"TeamId": teamId}); err != nil { 1951 result.Err = model.NewAppError("SqlChannelStore.AutocompleteInTeam", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 1952 } 1953 } else { 1954 // Using a UNION results in index_merge and fulltext queries and is much faster than the ref 1955 // query you would get using an OR of the LIKE and full-text clauses. 1956 fulltextClause, fulltextTerm := s.buildFulltextClause(term, "c.Name, c.DisplayName, c.Purpose") 1957 likeQuery := fmt.Sprintf(queryFormat, "AND "+likeClause) 1958 fulltextQuery := fmt.Sprintf(queryFormat, "AND "+fulltextClause) 1959 query := fmt.Sprintf("(%v) UNION (%v) LIMIT 50", likeQuery, fulltextQuery) 1960 1961 if _, err := s.GetReplica().Select(&channels, query, map[string]interface{}{"TeamId": teamId, "LikeTerm": likeTerm, "FulltextTerm": fulltextTerm}); err != nil { 1962 result.Err = model.NewAppError("SqlChannelStore.AutocompleteInTeam", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 1963 } 1964 } 1965 1966 sort.Slice(channels, func(a, b int) bool { 1967 return strings.ToLower(channels[a].DisplayName) < strings.ToLower(channels[b].DisplayName) 1968 }) 1969 result.Data = &channels 1970 }) 1971 } 1972 1973 func (s SqlChannelStore) AutocompleteInTeamForSearch(teamId string, userId string, term string, includeDeleted bool) store.StoreChannel { 1974 return store.Do(func(result *store.StoreResult) { 1975 deleteFilter := "AND DeleteAt = 0" 1976 if includeDeleted { 1977 deleteFilter = "" 1978 } 1979 1980 queryFormat := ` 1981 SELECT 1982 C.* 1983 FROM 1984 Channels AS C 1985 JOIN 1986 ChannelMembers AS CM ON CM.ChannelId = C.Id 1987 WHERE 1988 (C.TeamId = :TeamId OR (C.TeamId = '' AND C.Type = 'G')) 1989 AND CM.UserId = :UserId 1990 ` + deleteFilter + ` 1991 %v 1992 LIMIT 50` 1993 1994 var channels model.ChannelList 1995 1996 if likeClause, likeTerm := s.buildLIKEClause(term, "Name, DisplayName, Purpose"); likeClause == "" { 1997 if _, err := s.GetReplica().Select(&channels, fmt.Sprintf(queryFormat, ""), map[string]interface{}{"TeamId": teamId, "UserId": userId}); err != nil { 1998 result.Err = model.NewAppError("SqlChannelStore.AutocompleteInTeamForSearch", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 1999 } 2000 } else { 2001 // Using a UNION results in index_merge and fulltext queries and is much faster than the ref 2002 // query you would get using an OR of the LIKE and full-text clauses. 2003 fulltextClause, fulltextTerm := s.buildFulltextClause(term, "Name, DisplayName, Purpose") 2004 likeQuery := fmt.Sprintf(queryFormat, "AND "+likeClause) 2005 fulltextQuery := fmt.Sprintf(queryFormat, "AND "+fulltextClause) 2006 query := fmt.Sprintf("(%v) UNION (%v) LIMIT 50", likeQuery, fulltextQuery) 2007 2008 if _, err := s.GetReplica().Select(&channels, query, map[string]interface{}{"TeamId": teamId, "UserId": userId, "LikeTerm": likeTerm, "FulltextTerm": fulltextTerm}); err != nil { 2009 result.Err = model.NewAppError("SqlChannelStore.AutocompleteInTeamForSearch", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 2010 } 2011 } 2012 2013 directChannels, err := s.autocompleteInTeamForSearchDirectMessages(userId, term) 2014 if err != nil { 2015 result.Err = err 2016 return 2017 } 2018 2019 channels = append(channels, directChannels...) 2020 2021 sort.Slice(channels, func(a, b int) bool { 2022 return strings.ToLower(channels[a].DisplayName) < strings.ToLower(channels[b].DisplayName) 2023 }) 2024 result.Data = &channels 2025 }) 2026 } 2027 2028 func (s SqlChannelStore) autocompleteInTeamForSearchDirectMessages(userId string, term string) ([]*model.Channel, *model.AppError) { 2029 queryFormat := ` 2030 SELECT 2031 C.*, 2032 OtherUsers.Username as DisplayName 2033 FROM 2034 Channels AS C 2035 JOIN 2036 ChannelMembers AS CM ON CM.ChannelId = C.Id 2037 INNER JOIN ( 2038 SELECT 2039 ICM.ChannelId AS ChannelId, IU.Username AS Username 2040 FROM 2041 Users as IU 2042 JOIN 2043 ChannelMembers AS ICM ON ICM.UserId = IU.Id 2044 WHERE 2045 IU.Id != :UserId 2046 %v 2047 ) AS OtherUsers ON OtherUsers.ChannelId = C.Id 2048 WHERE 2049 C.Type = 'D' 2050 AND CM.UserId = :UserId 2051 LIMIT 50` 2052 2053 var channels model.ChannelList 2054 2055 if likeClause, likeTerm := s.buildLIKEClause(term, "IU.Username, IU.Nickname"); likeClause == "" { 2056 if _, err := s.GetReplica().Select(&channels, fmt.Sprintf(queryFormat, ""), map[string]interface{}{"UserId": userId}); err != nil { 2057 return nil, model.NewAppError("SqlChannelStore.AutocompleteInTeamForSearch", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 2058 } 2059 } else { 2060 query := fmt.Sprintf(queryFormat, "AND "+likeClause) 2061 2062 if _, err := s.GetReplica().Select(&channels, query, map[string]interface{}{"UserId": userId, "LikeTerm": likeTerm}); err != nil { 2063 return nil, model.NewAppError("SqlChannelStore.AutocompleteInTeamForSearch", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 2064 } 2065 } 2066 2067 return channels, nil 2068 } 2069 2070 func (s SqlChannelStore) SearchInTeam(teamId string, term string, includeDeleted bool) store.StoreChannel { 2071 return store.Do(func(result *store.StoreResult) { 2072 deleteFilter := "AND c.DeleteAt = 0" 2073 if includeDeleted { 2074 deleteFilter = "" 2075 } 2076 2077 *result = s.performSearch(` 2078 SELECT 2079 Channels.* 2080 FROM 2081 Channels 2082 JOIN 2083 PublicChannels c ON (c.Id = Channels.Id) 2084 WHERE 2085 c.TeamId = :TeamId 2086 `+deleteFilter+` 2087 SEARCH_CLAUSE 2088 ORDER BY c.DisplayName 2089 LIMIT 100 2090 `, term, map[string]interface{}{ 2091 "TeamId": teamId, 2092 }) 2093 }) 2094 } 2095 2096 func (s SqlChannelStore) SearchAllChannels(term string, includeDeleted bool) store.StoreChannel { 2097 return store.Do(func(result *store.StoreResult) { 2098 parameters := map[string]interface{}{} 2099 deleteFilter := "AND c.DeleteAt = 0" 2100 if includeDeleted { 2101 deleteFilter = "" 2102 } 2103 searchQuery := `SELECT c.*, t.DisplayName AS TeamDisplayName, t.Name AS TeamName, t.UpdateAt as TeamUpdateAt FROM Channels AS c JOIN Teams AS t ON t.Id = c.TeamId WHERE (c.Type = 'P' OR c.Type = 'O') ` + deleteFilter + ` SEARCH_CLAUSE ORDER BY c.DisplayName, t.DisplayName LIMIT 100` 2104 2105 likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose") 2106 if likeTerm == "" { 2107 // If the likeTerm is empty after preparing, then don't bother searching. 2108 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1) 2109 } else { 2110 parameters["LikeTerm"] = likeTerm 2111 fulltextClause, fulltextTerm := s.buildFulltextClause(term, "c.Name, c.DisplayName, c.Purpose") 2112 parameters["FulltextTerm"] = fulltextTerm 2113 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "AND ("+likeClause+" OR "+fulltextClause+")", 1) 2114 } 2115 2116 var channels model.ChannelListWithTeamData 2117 2118 if _, err := s.GetReplica().Select(&channels, searchQuery, parameters); err != nil { 2119 result.Err = model.NewAppError("SqlChannelStore.Search", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 2120 } 2121 2122 result.Data = &channels 2123 }) 2124 } 2125 2126 func (s SqlChannelStore) SearchMore(userId string, teamId string, term string) store.StoreChannel { 2127 return store.Do(func(result *store.StoreResult) { 2128 *result = s.performSearch(` 2129 SELECT 2130 Channels.* 2131 FROM 2132 Channels 2133 JOIN 2134 PublicChannels c ON (c.Id = Channels.Id) 2135 WHERE 2136 c.TeamId = :TeamId 2137 AND c.DeleteAt = 0 2138 AND c.Id NOT IN ( 2139 SELECT 2140 c.Id 2141 FROM 2142 PublicChannels c 2143 JOIN 2144 ChannelMembers cm ON (cm.ChannelId = c.Id) 2145 WHERE 2146 c.TeamId = :TeamId 2147 AND cm.UserId = :UserId 2148 AND c.DeleteAt = 0 2149 ) 2150 SEARCH_CLAUSE 2151 ORDER BY c.DisplayName 2152 LIMIT 100 2153 `, term, map[string]interface{}{ 2154 "TeamId": teamId, 2155 "UserId": userId, 2156 }) 2157 }) 2158 } 2159 2160 func (s SqlChannelStore) buildLIKEClause(term string, searchColumns string) (likeClause, likeTerm string) { 2161 likeTerm = term 2162 2163 // These chars must be removed from the like query. 2164 for _, c := range ignoreLikeSearchChar { 2165 likeTerm = strings.Replace(likeTerm, c, "", -1) 2166 } 2167 2168 // These chars must be escaped in the like query. 2169 for _, c := range escapeLikeSearchChar { 2170 likeTerm = strings.Replace(likeTerm, c, "*"+c, -1) 2171 } 2172 2173 if likeTerm == "" { 2174 return 2175 } 2176 2177 // Prepare the LIKE portion of the query. 2178 var searchFields []string 2179 for _, field := range strings.Split(searchColumns, ", ") { 2180 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 2181 searchFields = append(searchFields, fmt.Sprintf("lower(%s) LIKE lower(%s) escape '*'", field, ":LikeTerm")) 2182 } else { 2183 searchFields = append(searchFields, fmt.Sprintf("%s LIKE %s escape '*'", field, ":LikeTerm")) 2184 } 2185 } 2186 2187 likeClause = fmt.Sprintf("(%s)", strings.Join(searchFields, " OR ")) 2188 likeTerm += "%" 2189 return 2190 } 2191 2192 func (s SqlChannelStore) buildFulltextClause(term string, searchColumns string) (fulltextClause, fulltextTerm string) { 2193 // Copy the terms as we will need to prepare them differently for each search type. 2194 fulltextTerm = term 2195 2196 // These chars must be treated as spaces in the fulltext query. 2197 for _, c := range spaceFulltextSearchChar { 2198 fulltextTerm = strings.Replace(fulltextTerm, c, " ", -1) 2199 } 2200 2201 // Prepare the FULLTEXT portion of the query. 2202 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 2203 fulltextTerm = strings.Replace(fulltextTerm, "|", "", -1) 2204 2205 splitTerm := strings.Fields(fulltextTerm) 2206 for i, t := range strings.Fields(fulltextTerm) { 2207 if i == len(splitTerm)-1 { 2208 splitTerm[i] = t + ":*" 2209 } else { 2210 splitTerm[i] = t + ":* &" 2211 } 2212 } 2213 2214 fulltextTerm = strings.Join(splitTerm, " ") 2215 2216 fulltextClause = fmt.Sprintf("((%s) @@ to_tsquery(:FulltextTerm))", convertMySQLFullTextColumnsToPostgres(searchColumns)) 2217 } else if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 2218 splitTerm := strings.Fields(fulltextTerm) 2219 for i, t := range strings.Fields(fulltextTerm) { 2220 splitTerm[i] = "+" + t + "*" 2221 } 2222 2223 fulltextTerm = strings.Join(splitTerm, " ") 2224 2225 fulltextClause = fmt.Sprintf("MATCH(%s) AGAINST (:FulltextTerm IN BOOLEAN MODE)", searchColumns) 2226 } 2227 2228 return 2229 } 2230 2231 func (s SqlChannelStore) performSearch(searchQuery string, term string, parameters map[string]interface{}) store.StoreResult { 2232 result := store.StoreResult{} 2233 2234 likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose") 2235 if likeTerm == "" { 2236 // If the likeTerm is empty after preparing, then don't bother searching. 2237 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1) 2238 } else { 2239 parameters["LikeTerm"] = likeTerm 2240 fulltextClause, fulltextTerm := s.buildFulltextClause(term, "c.Name, c.DisplayName, c.Purpose") 2241 parameters["FulltextTerm"] = fulltextTerm 2242 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "AND ("+likeClause+" OR "+fulltextClause+")", 1) 2243 } 2244 2245 var channels model.ChannelList 2246 2247 if _, err := s.GetReplica().Select(&channels, searchQuery, parameters); err != nil { 2248 result.Err = model.NewAppError("SqlChannelStore.Search", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 2249 return result 2250 } 2251 2252 result.Data = &channels 2253 return result 2254 } 2255 2256 func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) store.StoreChannel { 2257 return store.Do(func(result *store.StoreResult) { 2258 var dbMembers channelMemberWithSchemeRolesList 2259 props := make(map[string]interface{}) 2260 idQuery := "" 2261 2262 for index, userId := range userIds { 2263 if len(idQuery) > 0 { 2264 idQuery += ", " 2265 } 2266 2267 props["userId"+strconv.Itoa(index)] = userId 2268 idQuery += ":userId" + strconv.Itoa(index) 2269 } 2270 2271 props["ChannelId"] = channelId 2272 2273 if _, err := s.GetReplica().Select(&dbMembers, CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId IN ("+idQuery+")", props); err != nil { 2274 result.Err = model.NewAppError("SqlChannelStore.GetMembersByIds", "store.sql_channel.get_members_by_ids.app_error", nil, "channelId="+channelId+" "+err.Error(), http.StatusInternalServerError) 2275 return 2276 } 2277 2278 result.Data = dbMembers.ToModel() 2279 }) 2280 } 2281 2282 func (s SqlChannelStore) GetChannelsByScheme(schemeId string, offset int, limit int) store.StoreChannel { 2283 return store.Do(func(result *store.StoreResult) { 2284 var channels model.ChannelList 2285 _, 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}) 2286 if err != nil { 2287 result.Err = model.NewAppError("SqlChannelStore.GetChannelsByScheme", "store.sql_channel.get_by_scheme.app_error", nil, "schemeId="+schemeId+" "+err.Error(), http.StatusInternalServerError) 2288 return 2289 } 2290 result.Data = channels 2291 }) 2292 } 2293 2294 // This function does the Advanced Permissions Phase 2 migration for ChannelMember objects. It performs the migration 2295 // in batches as a single transaction per batch to ensure consistency but to also minimise execution time to avoid 2296 // causing unnecessary table locks. **THIS FUNCTION SHOULD NOT BE USED FOR ANY OTHER PURPOSE.** Executing this function 2297 // *after* the new Schemes functionality has been used on an installation will have unintended consequences. 2298 func (s SqlChannelStore) MigrateChannelMembers(fromChannelId string, fromUserId string) store.StoreChannel { 2299 return store.Do(func(result *store.StoreResult) { 2300 var transaction *gorp.Transaction 2301 var err error 2302 2303 if transaction, err = s.GetMaster().Begin(); err != nil { 2304 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 2305 return 2306 } 2307 2308 var channelMembers []channelMember 2309 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 { 2310 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.select.app_error", nil, err.Error(), http.StatusInternalServerError) 2311 return 2312 } 2313 2314 if len(channelMembers) == 0 { 2315 // No more channel members in query result means that the migration has finished. 2316 return 2317 } 2318 2319 for _, member := range channelMembers { 2320 roles := strings.Fields(member.Roles) 2321 var newRoles []string 2322 if !member.SchemeAdmin.Valid { 2323 member.SchemeAdmin = sql.NullBool{Bool: false, Valid: true} 2324 } 2325 if !member.SchemeUser.Valid { 2326 member.SchemeUser = sql.NullBool{Bool: false, Valid: true} 2327 } 2328 for _, role := range roles { 2329 if role == model.CHANNEL_ADMIN_ROLE_ID { 2330 member.SchemeAdmin = sql.NullBool{Bool: true, Valid: true} 2331 } else if role == model.CHANNEL_USER_ROLE_ID { 2332 member.SchemeUser = sql.NullBool{Bool: true, Valid: true} 2333 } else { 2334 newRoles = append(newRoles, role) 2335 } 2336 } 2337 member.Roles = strings.Join(newRoles, " ") 2338 2339 if _, err := transaction.Update(&member); err != nil { 2340 if err2 := transaction.Rollback(); err2 != nil { 2341 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError) 2342 return 2343 } 2344 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.update.app_error", nil, err.Error(), http.StatusInternalServerError) 2345 return 2346 } 2347 2348 } 2349 2350 if err := transaction.Commit(); err != nil { 2351 if err2 := transaction.Rollback(); err2 != nil { 2352 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError) 2353 return 2354 } 2355 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 2356 return 2357 } 2358 2359 data := make(map[string]string) 2360 data["ChannelId"] = channelMembers[len(channelMembers)-1].ChannelId 2361 data["UserId"] = channelMembers[len(channelMembers)-1].UserId 2362 result.Data = data 2363 }) 2364 } 2365 2366 func (s SqlChannelStore) ResetAllChannelSchemes() store.StoreChannel { 2367 return store.Do(func(result *store.StoreResult) { 2368 transaction, err := s.GetMaster().Begin() 2369 if err != nil { 2370 result.Err = model.NewAppError("SqlChannelStore.ResetAllChannelSchemes", "store.sql_channel.reset_all_channel_schemes.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 2371 return 2372 } 2373 2374 *result = s.resetAllChannelSchemesT(transaction) 2375 if result.Err != nil { 2376 transaction.Rollback() 2377 return 2378 } 2379 2380 if err := transaction.Commit(); err != nil { 2381 result.Err = model.NewAppError("SqlChannelStore.ResetAllChannelSchemes", "store.sql_channel.reset_all_channel_schemes.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 2382 return 2383 } 2384 }) 2385 } 2386 2387 func (s SqlChannelStore) resetAllChannelSchemesT(transaction *gorp.Transaction) store.StoreResult { 2388 result := store.StoreResult{} 2389 2390 if _, err := transaction.Exec("UPDATE Channels SET SchemeId=''"); err != nil { 2391 result.Err = model.NewAppError("SqlChannelStore.ResetAllChannelSchemes", "store.sql_channel.reset_all_channel_schemes.app_error", nil, err.Error(), http.StatusInternalServerError) 2392 return result 2393 } 2394 2395 return result 2396 } 2397 2398 func (s SqlChannelStore) ClearAllCustomRoleAssignments() store.StoreChannel { 2399 return store.Do(func(result *store.StoreResult) { 2400 builtInRoles := model.MakeDefaultRoles() 2401 lastUserId := strings.Repeat("0", 26) 2402 lastChannelId := strings.Repeat("0", 26) 2403 2404 for { 2405 var transaction *gorp.Transaction 2406 var err error 2407 2408 if transaction, err = s.GetMaster().Begin(); err != nil { 2409 result.Err = model.NewAppError("SqlChannelStore.ClearAllCustomRoleAssignments", "store.sql_channel.clear_all_custom_role_assignments.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 2410 return 2411 } 2412 2413 var channelMembers []*channelMember 2414 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 { 2415 if err2 := transaction.Rollback(); err2 != nil { 2416 result.Err = model.NewAppError("SqlChannelStore.ClearAllCustomRoleAssignments", "store.sql_channel.clear_all_custom_role_assignments.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError) 2417 return 2418 } 2419 result.Err = model.NewAppError("SqlChannelStore.ClearAllCustomRoleAssignments", "store.sql_channel.clear_all_custom_role_assignments.select.app_error", nil, err.Error(), http.StatusInternalServerError) 2420 return 2421 } 2422 2423 if len(channelMembers) == 0 { 2424 break 2425 } 2426 2427 for _, member := range channelMembers { 2428 lastUserId = member.UserId 2429 lastChannelId = member.ChannelId 2430 2431 var newRoles []string 2432 2433 for _, role := range strings.Fields(member.Roles) { 2434 for name := range builtInRoles { 2435 if name == role { 2436 newRoles = append(newRoles, role) 2437 break 2438 } 2439 } 2440 } 2441 2442 newRolesString := strings.Join(newRoles, " ") 2443 if newRolesString != member.Roles { 2444 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 { 2445 if err2 := transaction.Rollback(); err2 != nil { 2446 result.Err = model.NewAppError("SqlChannelStore.ClearAllCustomRoleAssignments", "store.sql_channel.clear_all_custom_role_assignments.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError) 2447 return 2448 } 2449 result.Err = model.NewAppError("SqlChannelStore.ClearAllCustomRoleAssignments", "store.sql_channel.clear_all_custom_role_assignments.update.app_error", nil, err.Error(), http.StatusInternalServerError) 2450 return 2451 } 2452 } 2453 } 2454 2455 if err := transaction.Commit(); err != nil { 2456 if err2 := transaction.Rollback(); err2 != nil { 2457 result.Err = model.NewAppError("SqlChannelStore.ClearAllCustomRoleAssignments", "store.sql_channel.clear_all_custom_role_assignments.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError) 2458 return 2459 } 2460 result.Err = model.NewAppError("SqlChannelStore.ClearAllCustomRoleAssignments", "store.sql_channel.clear_all_custom_role_assignments.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 2461 return 2462 } 2463 } 2464 }) 2465 } 2466 2467 func (s SqlChannelStore) ResetLastPostAt() store.StoreChannel { 2468 return store.Do(func(result *store.StoreResult) { 2469 transaction, err := s.GetMaster().Begin() 2470 if err != nil { 2471 result.Err = model.NewAppError("SqlChannelStore.ResetLastPostAt", "store.sql_channel.reset_last_post_at.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 2472 return 2473 } 2474 2475 *result = s.resetLastPostAtT(transaction) 2476 if result.Err != nil { 2477 transaction.Rollback() 2478 return 2479 } 2480 2481 if err := transaction.Commit(); err != nil { 2482 result.Err = model.NewAppError("SqlChannelStore.ResetLastPostAt", "store.sql_channel.reset_last_post_at.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 2483 return 2484 } 2485 }) 2486 } 2487 2488 func (s SqlChannelStore) resetLastPostAtT(transaction *gorp.Transaction) store.StoreResult { 2489 result := store.StoreResult{} 2490 2491 var query string 2492 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 2493 query = "UPDATE Channels SET LastPostAt = COALESCE((SELECT UpdateAt FROM Posts WHERE ChannelId = Channels.Id ORDER BY UpdateAt DESC LIMIT 1), Channels.CreateAt);" 2494 } else { 2495 query = "UPDATE Channels SET LastPostAt = IFNULL((SELECT UpdateAt FROM Posts WHERE ChannelId = Channels.Id ORDER BY UpdateAt DESC LIMIT 1), Channels.CreateAt);" 2496 } 2497 2498 if _, err := transaction.Exec(query); err != nil { 2499 result.Err = model.NewAppError("SqlChannelStore.ResetLastPostAt", "store.sql_channel.reset_last_post_at.app_error", nil, err.Error(), http.StatusInternalServerError) 2500 return result 2501 } 2502 2503 return result 2504 } 2505 2506 func (s SqlChannelStore) GetAllChannelsForExportAfter(limit int, afterId string) store.StoreChannel { 2507 return store.Do(func(result *store.StoreResult) { 2508 var data []*model.ChannelForExport 2509 if _, err := s.GetReplica().Select(&data, ` 2510 SELECT 2511 Channels.*, 2512 Teams.Name as TeamName, 2513 Schemes.Name as SchemeName 2514 FROM Channels 2515 INNER JOIN 2516 Teams ON Channels.TeamId = Teams.Id 2517 LEFT JOIN 2518 Schemes ON Channels.SchemeId = Schemes.Id 2519 WHERE 2520 Channels.Id > :AfterId 2521 AND Channels.Type IN ('O', 'P') 2522 ORDER BY 2523 Id 2524 LIMIT :Limit`, 2525 map[string]interface{}{"AfterId": afterId, "Limit": limit}); err != nil { 2526 result.Err = model.NewAppError("SqlTeamStore.GetAllChannelsForExportAfter", "store.sql_channel.get_all.app_error", nil, err.Error(), http.StatusInternalServerError) 2527 return 2528 } 2529 2530 result.Data = data 2531 }) 2532 } 2533 2534 func (s SqlChannelStore) GetChannelMembersForExport(userId string, teamId string) store.StoreChannel { 2535 return store.Do(func(result *store.StoreResult) { 2536 var members []*model.ChannelMemberForExport 2537 _, err := s.GetReplica().Select(&members, ` 2538 SELECT 2539 ChannelMembers.*, 2540 Channels.Name as ChannelName 2541 FROM 2542 ChannelMembers 2543 INNER JOIN 2544 Channels ON ChannelMembers.ChannelId = Channels.Id 2545 WHERE 2546 ChannelMembers.UserId = :UserId 2547 AND Channels.TeamId = :TeamId 2548 AND Channels.DeleteAt = 0`, 2549 map[string]interface{}{"TeamId": teamId, "UserId": userId}) 2550 2551 if err != nil { 2552 result.Err = model.NewAppError("SqlChannelStore.GetChannelMembersForExport", "store.sql_channel.get_members.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 2553 return 2554 } 2555 2556 result.Data = members 2557 }) 2558 }