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