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