github.com/psyb0t/mattermost-server@v4.6.1-0.20180125161845-5503a1351abf+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 "strconv" 11 "strings" 12 13 l4g "github.com/alecthomas/log4go" 14 "github.com/mattermost/gorp" 15 "github.com/mattermost/mattermost-server/einterfaces" 16 "github.com/mattermost/mattermost-server/model" 17 "github.com/mattermost/mattermost-server/store" 18 "github.com/mattermost/mattermost-server/utils" 19 ) 20 21 const ( 22 ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE = model.SESSION_CACHE_SIZE 23 ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SEC = 900 // 15 mins 24 25 ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE = model.SESSION_CACHE_SIZE 26 ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SEC = 1800 // 30 mins 27 28 CHANNEL_MEMBERS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE 29 CHANNEL_MEMBERS_COUNTS_CACHE_SEC = 1800 // 30 mins 30 31 CHANNEL_CACHE_SEC = 900 // 15 mins 32 ) 33 34 type SqlChannelStore struct { 35 SqlStore 36 metrics einterfaces.MetricsInterface 37 } 38 39 var channelMemberCountsCache = utils.NewLru(CHANNEL_MEMBERS_COUNTS_CACHE_SIZE) 40 var allChannelMembersForUserCache = utils.NewLru(ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE) 41 var allChannelMembersNotifyPropsForChannelCache = utils.NewLru(ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE) 42 var channelCache = utils.NewLru(model.CHANNEL_CACHE_SIZE) 43 var channelByNameCache = utils.NewLru(model.CHANNEL_CACHE_SIZE) 44 45 func ClearChannelCaches() { 46 channelMemberCountsCache.Purge() 47 allChannelMembersForUserCache.Purge() 48 allChannelMembersNotifyPropsForChannelCache.Purge() 49 channelCache.Purge() 50 channelByNameCache.Purge() 51 } 52 53 func NewSqlChannelStore(sqlStore SqlStore, metrics einterfaces.MetricsInterface) store.ChannelStore { 54 s := &SqlChannelStore{ 55 SqlStore: sqlStore, 56 metrics: metrics, 57 } 58 59 for _, db := range sqlStore.GetAllConns() { 60 table := db.AddTableWithName(model.Channel{}, "Channels").SetKeys(false, "Id") 61 table.ColMap("Id").SetMaxSize(26) 62 table.ColMap("TeamId").SetMaxSize(26) 63 table.ColMap("Type").SetMaxSize(1) 64 table.ColMap("DisplayName").SetMaxSize(64) 65 table.ColMap("Name").SetMaxSize(64) 66 table.SetUniqueTogether("Name", "TeamId") 67 table.ColMap("Header").SetMaxSize(1024) 68 table.ColMap("Purpose").SetMaxSize(250) 69 table.ColMap("CreatorId").SetMaxSize(26) 70 71 tablem := db.AddTableWithName(model.ChannelMember{}, "ChannelMembers").SetKeys(false, "ChannelId", "UserId") 72 tablem.ColMap("ChannelId").SetMaxSize(26) 73 tablem.ColMap("UserId").SetMaxSize(26) 74 tablem.ColMap("Roles").SetMaxSize(64) 75 tablem.ColMap("NotifyProps").SetMaxSize(2000) 76 } 77 78 return s 79 } 80 81 func (s SqlChannelStore) CreateIndexesIfNotExists() { 82 s.CreateIndexIfNotExists("idx_channels_team_id", "Channels", "TeamId") 83 s.CreateIndexIfNotExists("idx_channels_name", "Channels", "Name") 84 s.CreateIndexIfNotExists("idx_channels_update_at", "Channels", "UpdateAt") 85 s.CreateIndexIfNotExists("idx_channels_create_at", "Channels", "CreateAt") 86 s.CreateIndexIfNotExists("idx_channels_delete_at", "Channels", "DeleteAt") 87 88 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 89 s.CreateIndexIfNotExists("idx_channels_name_lower", "Channels", "lower(Name)") 90 s.CreateIndexIfNotExists("idx_channels_displayname_lower", "Channels", "lower(DisplayName)") 91 } 92 93 s.CreateIndexIfNotExists("idx_channelmembers_channel_id", "ChannelMembers", "ChannelId") 94 s.CreateIndexIfNotExists("idx_channelmembers_user_id", "ChannelMembers", "UserId") 95 96 s.CreateFullTextIndexIfNotExists("idx_channels_txt", "Channels", "Name, DisplayName") 97 } 98 99 func (s SqlChannelStore) Save(channel *model.Channel, maxChannelsPerTeam int64) store.StoreChannel { 100 return store.Do(func(result *store.StoreResult) { 101 if channel.Type == model.CHANNEL_DIRECT { 102 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.direct_channel.app_error", nil, "", http.StatusBadRequest) 103 } else { 104 if transaction, err := s.GetMaster().Begin(); err != nil { 105 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 106 } else { 107 *result = s.saveChannelT(transaction, channel, maxChannelsPerTeam) 108 if result.Err != nil { 109 transaction.Rollback() 110 } else { 111 if err := transaction.Commit(); err != nil { 112 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 113 } 114 } 115 } 116 } 117 }) 118 } 119 120 func (s SqlChannelStore) CreateDirectChannel(userId string, otherUserId string) store.StoreChannel { 121 channel := new(model.Channel) 122 123 channel.DisplayName = "" 124 channel.Name = model.GetDMNameFromIds(otherUserId, userId) 125 126 channel.Header = "" 127 channel.Type = model.CHANNEL_DIRECT 128 129 cm1 := &model.ChannelMember{ 130 UserId: userId, 131 NotifyProps: model.GetDefaultChannelNotifyProps(), 132 Roles: model.CHANNEL_USER_ROLE_ID, 133 } 134 cm2 := &model.ChannelMember{ 135 UserId: otherUserId, 136 NotifyProps: model.GetDefaultChannelNotifyProps(), 137 Roles: model.CHANNEL_USER_ROLE_ID, 138 } 139 140 return s.SaveDirectChannel(channel, cm1, cm2) 141 } 142 143 func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1 *model.ChannelMember, member2 *model.ChannelMember) store.StoreChannel { 144 return store.Do(func(result *store.StoreResult) { 145 if directchannel.Type != model.CHANNEL_DIRECT { 146 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.not_direct.app_error", nil, "", http.StatusBadRequest) 147 } else { 148 if transaction, err := s.GetMaster().Begin(); err != nil { 149 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 150 } else { 151 directchannel.TeamId = "" 152 channelResult := s.saveChannelT(transaction, directchannel, 0) 153 154 if channelResult.Err != nil { 155 transaction.Rollback() 156 result.Err = channelResult.Err 157 result.Data = channelResult.Data 158 } else { 159 newChannel := channelResult.Data.(*model.Channel) 160 // Members need new channel ID 161 member1.ChannelId = newChannel.Id 162 member2.ChannelId = newChannel.Id 163 164 member1Result := s.saveMemberT(transaction, member1, newChannel) 165 member2Result := member1Result 166 if member1.UserId != member2.UserId { 167 member2Result = s.saveMemberT(transaction, member2, newChannel) 168 } 169 170 if member1Result.Err != nil || member2Result.Err != nil { 171 transaction.Rollback() 172 details := "" 173 if member1Result.Err != nil { 174 details += "Member1Err: " + member1Result.Err.Message 175 } 176 if member2Result.Err != nil { 177 details += "Member2Err: " + member2Result.Err.Message 178 } 179 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.add_members.app_error", nil, details, http.StatusInternalServerError) 180 } else { 181 if err := transaction.Commit(); err != nil { 182 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.commit.app_error", nil, err.Error(), http.StatusInternalServerError) 183 } else { 184 *result = channelResult 185 } 186 } 187 } 188 } 189 } 190 }) 191 } 192 193 func (s SqlChannelStore) saveChannelT(transaction *gorp.Transaction, channel *model.Channel, maxChannelsPerTeam int64) store.StoreResult { 194 result := store.StoreResult{} 195 196 if len(channel.Id) > 0 { 197 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.existing.app_error", nil, "id="+channel.Id, http.StatusBadRequest) 198 return result 199 } 200 201 channel.PreSave() 202 if result.Err = channel.IsValid(); result.Err != nil { 203 return result 204 } 205 206 if channel.Type != model.CHANNEL_DIRECT && channel.Type != model.CHANNEL_GROUP && maxChannelsPerTeam >= 0 { 207 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 { 208 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.current_count.app_error", nil, "teamId="+channel.TeamId+", "+err.Error(), http.StatusInternalServerError) 209 return result 210 } else if count >= maxChannelsPerTeam { 211 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.limit.app_error", nil, "teamId="+channel.TeamId, http.StatusBadRequest) 212 return result 213 } 214 } 215 216 if err := transaction.Insert(channel); err != nil { 217 if IsUniqueConstraintError(err, []string{"Name", "channels_name_teamid_key"}) { 218 dupChannel := model.Channel{} 219 s.GetMaster().SelectOne(&dupChannel, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name = :Name", map[string]interface{}{"TeamId": channel.TeamId, "Name": channel.Name}) 220 if dupChannel.DeleteAt > 0 { 221 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.previously.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 222 } else { 223 result.Err = model.NewAppError("SqlChannelStore.Save", store.CHANNEL_EXISTS_ERROR, nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 224 result.Data = &dupChannel 225 } 226 } else { 227 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.save.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusInternalServerError) 228 } 229 } else { 230 result.Data = channel 231 } 232 233 return result 234 } 235 236 func (s SqlChannelStore) Update(channel *model.Channel) store.StoreChannel { 237 return store.Do(func(result *store.StoreResult) { 238 channel.PreUpdate() 239 240 if result.Err = channel.IsValid(); result.Err != nil { 241 return 242 } 243 244 if count, err := s.GetMaster().Update(channel); err != nil { 245 if IsUniqueConstraintError(err, []string{"Name", "channels_name_teamid_key"}) { 246 dupChannel := model.Channel{} 247 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}) 248 if dupChannel.DeleteAt > 0 { 249 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.previously.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 250 } else { 251 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.exists.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 252 } 253 } else { 254 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.updating.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusInternalServerError) 255 } 256 } else if count != 1 { 257 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.app_error", nil, "id="+channel.Id, http.StatusInternalServerError) 258 } else { 259 result.Data = channel 260 } 261 }) 262 } 263 264 func (s SqlChannelStore) extraUpdated(channel *model.Channel) store.StoreChannel { 265 return store.Do(func(result *store.StoreResult) { 266 channel.ExtraUpdated() 267 268 _, err := s.GetMaster().Exec( 269 `UPDATE 270 Channels 271 SET 272 ExtraUpdateAt = :Time 273 WHERE 274 Id = :Id`, 275 map[string]interface{}{"Id": channel.Id, "Time": channel.ExtraUpdateAt}) 276 277 if err != nil { 278 result.Err = model.NewAppError("SqlChannelStore.extraUpdated", "store.sql_channel.extra_updated.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusInternalServerError) 279 } 280 }) 281 } 282 283 func (s SqlChannelStore) GetChannelUnread(channelId, userId string) store.StoreChannel { 284 return store.Do(func(result *store.StoreResult) { 285 var unreadChannel model.ChannelUnread 286 err := s.GetReplica().SelectOne(&unreadChannel, 287 `SELECT 288 Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps 289 FROM 290 Channels, ChannelMembers 291 WHERE 292 Id = ChannelId 293 AND Id = :ChannelId 294 AND UserId = :UserId 295 AND DeleteAt = 0`, 296 map[string]interface{}{"ChannelId": channelId, "UserId": userId}) 297 298 if err != nil { 299 result.Err = model.NewAppError("SqlChannelStore.GetChannelUnread", "store.sql_channel.get_unread.app_error", nil, "channelId="+channelId+" "+err.Error(), http.StatusInternalServerError) 300 if err == sql.ErrNoRows { 301 result.Err.StatusCode = http.StatusNotFound 302 } 303 } else { 304 result.Data = &unreadChannel 305 } 306 }) 307 } 308 309 func (us SqlChannelStore) InvalidateChannel(id string) { 310 channelCache.Remove(id) 311 } 312 313 func (us SqlChannelStore) InvalidateChannelByName(teamId, name string) { 314 channelByNameCache.Remove(teamId + name) 315 } 316 317 func (s SqlChannelStore) Get(id string, allowFromCache bool) store.StoreChannel { 318 return s.get(id, false, allowFromCache) 319 } 320 321 func (s SqlChannelStore) GetPinnedPosts(channelId string) store.StoreChannel { 322 return store.Do(func(result *store.StoreResult) { 323 pl := model.NewPostList() 324 325 var posts []*model.Post 326 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 { 327 result.Err = model.NewAppError("SqlPostStore.GetPinnedPosts", "store.sql_channel.pinned_posts.app_error", nil, err.Error(), http.StatusInternalServerError) 328 } else { 329 for _, post := range posts { 330 pl.AddPost(post) 331 pl.AddOrder(post.Id) 332 } 333 } 334 335 result.Data = pl 336 }) 337 } 338 339 func (s SqlChannelStore) GetFromMaster(id string) store.StoreChannel { 340 return s.get(id, true, false) 341 } 342 343 func (s SqlChannelStore) get(id string, master bool, allowFromCache bool) store.StoreChannel { 344 return store.Do(func(result *store.StoreResult) { 345 var db *gorp.DbMap 346 if master { 347 db = s.GetMaster() 348 } else { 349 db = s.GetReplica() 350 } 351 352 if allowFromCache { 353 if cacheItem, ok := channelCache.Get(id); ok { 354 if s.metrics != nil { 355 s.metrics.IncrementMemCacheHitCounter("Channel") 356 } 357 result.Data = (cacheItem.(*model.Channel)).DeepCopy() 358 return 359 } else { 360 if s.metrics != nil { 361 s.metrics.IncrementMemCacheMissCounter("Channel") 362 } 363 } 364 } else { 365 if s.metrics != nil { 366 s.metrics.IncrementMemCacheMissCounter("Channel") 367 } 368 } 369 370 if obj, err := db.Get(model.Channel{}, id); err != nil { 371 result.Err = model.NewAppError("SqlChannelStore.Get", "store.sql_channel.get.find.app_error", nil, "id="+id+", "+err.Error(), http.StatusInternalServerError) 372 } else if obj == nil { 373 result.Err = model.NewAppError("SqlChannelStore.Get", "store.sql_channel.get.existing.app_error", nil, "id="+id, http.StatusNotFound) 374 } else { 375 result.Data = obj.(*model.Channel) 376 channelCache.AddWithExpiresInSecs(id, obj.(*model.Channel), CHANNEL_CACHE_SEC) 377 } 378 }) 379 } 380 381 func (s SqlChannelStore) Delete(channelId string, time int64) store.StoreChannel { 382 return s.SetDeleteAt(channelId, time, time) 383 } 384 385 func (s SqlChannelStore) Restore(channelId string, time int64) store.StoreChannel { 386 return s.SetDeleteAt(channelId, 0, time) 387 } 388 389 func (s SqlChannelStore) SetDeleteAt(channelId string, deleteAt int64, updateAt int64) store.StoreChannel { 390 return store.Do(func(result *store.StoreResult) { 391 _, err := s.GetMaster().Exec("Update Channels SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :ChannelId", map[string]interface{}{"DeleteAt": deleteAt, "UpdateAt": updateAt, "ChannelId": channelId}) 392 if err != nil { 393 result.Err = model.NewAppError("SqlChannelStore.Delete", "store.sql_channel.delete.channel.app_error", nil, "id="+channelId+", err="+err.Error(), http.StatusInternalServerError) 394 } 395 }) 396 } 397 398 func (s SqlChannelStore) PermanentDeleteByTeam(teamId string) store.StoreChannel { 399 return store.Do(func(result *store.StoreResult) { 400 if _, err := s.GetMaster().Exec("DELETE FROM Channels WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil { 401 result.Err = model.NewAppError("SqlChannelStore.PermanentDeleteByTeam", "store.sql_channel.permanent_delete_by_team.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError) 402 } 403 }) 404 } 405 406 func (s SqlChannelStore) PermanentDelete(channelId string) store.StoreChannel { 407 return store.Do(func(result *store.StoreResult) { 408 if _, err := s.GetMaster().Exec("DELETE FROM Channels WHERE Id = :ChannelId", map[string]interface{}{"ChannelId": channelId}); err != nil { 409 result.Err = model.NewAppError("SqlChannelStore.PermanentDelete", "store.sql_channel.permanent_delete.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 410 } 411 }) 412 } 413 414 func (s SqlChannelStore) PermanentDeleteMembersByChannel(channelId string) store.StoreChannel { 415 return store.Do(func(result *store.StoreResult) { 416 _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId}) 417 if err != nil { 418 result.Err = model.NewAppError("SqlChannelStore.RemoveAllMembersByChannel", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 419 } 420 }) 421 } 422 423 func (s SqlChannelStore) GetChannels(teamId string, userId string) store.StoreChannel { 424 return store.Do(func(result *store.StoreResult) { 425 data := &model.ChannelList{} 426 _, err := s.GetReplica().Select(data, "SELECT Channels.* FROM Channels, ChannelMembers WHERE Id = ChannelId AND UserId = :UserId AND DeleteAt = 0 AND (TeamId = :TeamId OR TeamId = '') ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId}) 427 428 if err != nil { 429 result.Err = model.NewAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 430 } else { 431 if len(*data) == 0 { 432 result.Err = model.NewAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.not_found.app_error", nil, "teamId="+teamId+", userId="+userId, http.StatusBadRequest) 433 } else { 434 result.Data = data 435 } 436 } 437 }) 438 } 439 440 func (s SqlChannelStore) GetMoreChannels(teamId string, userId string, offset int, limit int) store.StoreChannel { 441 return store.Do(func(result *store.StoreResult) { 442 data := &model.ChannelList{} 443 _, err := s.GetReplica().Select(data, 444 `SELECT 445 * 446 FROM 447 Channels 448 WHERE 449 TeamId = :TeamId1 450 AND Type IN ('O') 451 AND DeleteAt = 0 452 AND Id NOT IN (SELECT 453 Channels.Id 454 FROM 455 Channels, 456 ChannelMembers 457 WHERE 458 Id = ChannelId 459 AND TeamId = :TeamId2 460 AND UserId = :UserId 461 AND DeleteAt = 0) 462 ORDER BY DisplayName 463 LIMIT :Limit 464 OFFSET :Offset`, 465 map[string]interface{}{"TeamId1": teamId, "TeamId2": teamId, "UserId": userId, "Limit": limit, "Offset": offset}) 466 467 if err != nil { 468 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) 469 } else { 470 result.Data = data 471 } 472 }) 473 } 474 475 func (s SqlChannelStore) GetPublicChannelsForTeam(teamId string, offset int, limit int) store.StoreChannel { 476 return store.Do(func(result *store.StoreResult) { 477 data := &model.ChannelList{} 478 _, err := s.GetReplica().Select(data, 479 `SELECT 480 * 481 FROM 482 Channels 483 WHERE 484 TeamId = :TeamId 485 AND Type = 'O' 486 AND DeleteAt = 0 487 ORDER BY DisplayName 488 LIMIT :Limit 489 OFFSET :Offset`, 490 map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset}) 491 492 if err != nil { 493 result.Err = model.NewAppError("SqlChannelStore.GetPublicChannelsForTeam", "store.sql_channel.get_public_channels.get.app_error", nil, "teamId="+teamId+", err="+err.Error(), http.StatusInternalServerError) 494 } else { 495 result.Data = data 496 } 497 }) 498 } 499 500 func (s SqlChannelStore) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) store.StoreChannel { 501 return store.Do(func(result *store.StoreResult) { 502 props := make(map[string]interface{}) 503 props["teamId"] = teamId 504 505 idQuery := "" 506 507 for index, channelId := range channelIds { 508 if len(idQuery) > 0 { 509 idQuery += ", " 510 } 511 512 props["channelId"+strconv.Itoa(index)] = channelId 513 idQuery += ":channelId" + strconv.Itoa(index) 514 } 515 516 data := &model.ChannelList{} 517 _, err := s.GetReplica().Select(data, 518 `SELECT 519 * 520 FROM 521 Channels 522 WHERE 523 TeamId = :teamId 524 AND Type = 'O' 525 AND DeleteAt = 0 526 AND Id IN (`+idQuery+`) 527 ORDER BY DisplayName`, 528 props) 529 530 if err != nil { 531 result.Err = model.NewAppError("SqlChannelStore.GetPublicChannelsByIdsForTeam", "store.sql_channel.get_channels_by_ids.get.app_error", nil, err.Error(), http.StatusInternalServerError) 532 } 533 534 if len(*data) == 0 { 535 result.Err = model.NewAppError("SqlChannelStore.GetPublicChannelsByIdsForTeam", "store.sql_channel.get_channels_by_ids.not_found.app_error", nil, "", http.StatusNotFound) 536 } 537 538 result.Data = data 539 }) 540 } 541 542 type channelIdWithCountAndUpdateAt struct { 543 Id string 544 TotalMsgCount int64 545 UpdateAt int64 546 } 547 548 func (s SqlChannelStore) GetChannelCounts(teamId string, userId string) store.StoreChannel { 549 return store.Do(func(result *store.StoreResult) { 550 var data []channelIdWithCountAndUpdateAt 551 _, 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}) 552 553 if err != nil { 554 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) 555 } else { 556 counts := &model.ChannelCounts{Counts: make(map[string]int64), UpdateTimes: make(map[string]int64)} 557 for i := range data { 558 v := data[i] 559 counts.Counts[v.Id] = v.TotalMsgCount 560 counts.UpdateTimes[v.Id] = v.UpdateAt 561 } 562 563 result.Data = counts 564 } 565 }) 566 } 567 568 func (s SqlChannelStore) GetTeamChannels(teamId string) store.StoreChannel { 569 return store.Do(func(result *store.StoreResult) { 570 data := &model.ChannelList{} 571 _, err := s.GetReplica().Select(data, "SELECT * FROM Channels WHERE TeamId = :TeamId And Type != 'D' ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId}) 572 573 if err != nil { 574 result.Err = model.NewAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.get.app_error", nil, "teamId="+teamId+", err="+err.Error(), http.StatusInternalServerError) 575 } else { 576 if len(*data) == 0 { 577 result.Err = model.NewAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.not_found.app_error", nil, "teamId="+teamId, http.StatusNotFound) 578 } else { 579 result.Data = data 580 } 581 } 582 }) 583 } 584 585 func (s SqlChannelStore) GetByName(teamId string, name string, allowFromCache bool) store.StoreChannel { 586 return s.getByName(teamId, name, false, allowFromCache) 587 } 588 589 func (s SqlChannelStore) GetByNames(teamId string, names []string, allowFromCache bool) store.StoreChannel { 590 return store.Do(func(result *store.StoreResult) { 591 var channels []*model.Channel 592 593 if allowFromCache { 594 var misses []string 595 visited := make(map[string]struct{}) 596 for _, name := range names { 597 if _, ok := visited[name]; ok { 598 continue 599 } 600 visited[name] = struct{}{} 601 if cacheItem, ok := channelByNameCache.Get(teamId + name); ok { 602 if s.metrics != nil { 603 s.metrics.IncrementMemCacheHitCounter("Channel By Name") 604 } 605 channels = append(channels, cacheItem.(*model.Channel)) 606 } else { 607 if s.metrics != nil { 608 s.metrics.IncrementMemCacheMissCounter("Channel By Name") 609 } 610 misses = append(misses, name) 611 } 612 } 613 names = misses 614 } 615 616 if len(names) > 0 { 617 props := map[string]interface{}{} 618 var namePlaceholders []string 619 for _, name := range names { 620 key := fmt.Sprintf("Name%v", len(namePlaceholders)) 621 props[key] = name 622 namePlaceholders = append(namePlaceholders, ":"+key) 623 } 624 625 var query string 626 if teamId == "" { 627 query = `SELECT * FROM Channels WHERE Name IN (` + strings.Join(namePlaceholders, ", ") + `) AND DeleteAt = 0` 628 } else { 629 props["TeamId"] = teamId 630 query = `SELECT * FROM Channels WHERE Name IN (` + strings.Join(namePlaceholders, ", ") + `) AND TeamId = :TeamId AND DeleteAt = 0` 631 } 632 633 var dbChannels []*model.Channel 634 if _, err := s.GetReplica().Select(&dbChannels, query, props); err != nil && err != sql.ErrNoRows { 635 result.Err = model.NewAppError("SqlChannelStore.GetByName", "store.sql_channel.get_by_name.existing.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError) 636 return 637 } 638 for _, channel := range dbChannels { 639 channelByNameCache.AddWithExpiresInSecs(teamId+channel.Name, channel, CHANNEL_CACHE_SEC) 640 channels = append(channels, channel) 641 } 642 } 643 644 result.Data = channels 645 }) 646 } 647 648 func (s SqlChannelStore) GetByNameIncludeDeleted(teamId string, name string, allowFromCache bool) store.StoreChannel { 649 return s.getByName(teamId, name, true, allowFromCache) 650 } 651 652 func (s SqlChannelStore) getByName(teamId string, name string, includeDeleted bool, allowFromCache bool) store.StoreChannel { 653 var query string 654 if includeDeleted { 655 query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name" 656 } else { 657 query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name AND DeleteAt = 0" 658 } 659 return store.Do(func(result *store.StoreResult) { 660 channel := model.Channel{} 661 662 if allowFromCache { 663 if cacheItem, ok := channelByNameCache.Get(teamId + name); ok { 664 if s.metrics != nil { 665 s.metrics.IncrementMemCacheHitCounter("Channel By Name") 666 } 667 result.Data = cacheItem.(*model.Channel) 668 return 669 } else { 670 if s.metrics != nil { 671 s.metrics.IncrementMemCacheMissCounter("Channel By Name") 672 } 673 } 674 } 675 if err := s.GetReplica().SelectOne(&channel, query, map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil { 676 if err == sql.ErrNoRows { 677 result.Err = model.NewAppError("SqlChannelStore.GetByName", store.MISSING_CHANNEL_ERROR, nil, "teamId="+teamId+", "+"name="+name+", "+err.Error(), http.StatusNotFound) 678 } else { 679 result.Err = model.NewAppError("SqlChannelStore.GetByName", "store.sql_channel.get_by_name.existing.app_error", nil, "teamId="+teamId+", "+"name="+name+", "+err.Error(), http.StatusInternalServerError) 680 } 681 } else { 682 result.Data = &channel 683 channelByNameCache.AddWithExpiresInSecs(teamId+name, &channel, CHANNEL_CACHE_SEC) 684 } 685 }) 686 } 687 688 func (s SqlChannelStore) GetDeletedByName(teamId string, name string) store.StoreChannel { 689 return store.Do(func(result *store.StoreResult) { 690 channel := model.Channel{} 691 692 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 { 693 if err == sql.ErrNoRows { 694 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) 695 } else { 696 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) 697 } 698 } else { 699 result.Data = &channel 700 } 701 }) 702 } 703 704 func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int) store.StoreChannel { 705 return store.Do(func(result *store.StoreResult) { 706 channels := &model.ChannelList{} 707 708 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 { 709 if err == sql.ErrNoRows { 710 result.Err = model.NewAppError("SqlChannelStore.GetDeleted", "store.sql_channel.get_deleted.missing.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusNotFound) 711 } else { 712 result.Err = model.NewAppError("SqlChannelStore.GetDeleted", "store.sql_channel.get_deleted.existing.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError) 713 } 714 } else { 715 result.Data = channels 716 } 717 }) 718 } 719 720 func (s SqlChannelStore) SaveMember(member *model.ChannelMember) store.StoreChannel { 721 return store.Do(func(result *store.StoreResult) { 722 // Grab the channel we are saving this member to 723 if cr := <-s.GetFromMaster(member.ChannelId); cr.Err != nil { 724 result.Err = cr.Err 725 } else { 726 channel := cr.Data.(*model.Channel) 727 728 if transaction, err := s.GetMaster().Begin(); err != nil { 729 result.Err = model.NewAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 730 } else { 731 *result = s.saveMemberT(transaction, member, channel) 732 if result.Err != nil { 733 transaction.Rollback() 734 } else { 735 if err := transaction.Commit(); err != nil { 736 result.Err = model.NewAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 737 } 738 // If sucessfull record members have changed in channel 739 if mu := <-s.extraUpdated(channel); mu.Err != nil { 740 result.Err = mu.Err 741 } 742 } 743 } 744 } 745 746 s.InvalidateAllChannelMembersForUser(member.UserId) 747 }) 748 } 749 750 func (s SqlChannelStore) saveMemberT(transaction *gorp.Transaction, member *model.ChannelMember, channel *model.Channel) store.StoreResult { 751 result := store.StoreResult{} 752 753 member.PreSave() 754 if result.Err = member.IsValid(); result.Err != nil { 755 return result 756 } 757 758 if err := transaction.Insert(member); err != nil { 759 if IsUniqueConstraintError(err, []string{"ChannelId", "channelmembers_pkey"}) { 760 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) 761 } else { 762 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) 763 } 764 } else { 765 result.Data = member 766 } 767 768 return result 769 } 770 771 func (s SqlChannelStore) UpdateMember(member *model.ChannelMember) store.StoreChannel { 772 return store.Do(func(result *store.StoreResult) { 773 member.PreUpdate() 774 775 if result.Err = member.IsValid(); result.Err != nil { 776 return 777 } 778 779 if _, err := s.GetMaster().Update(member); err != nil { 780 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) 781 } else { 782 result.Data = member 783 } 784 }) 785 } 786 787 func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) store.StoreChannel { 788 return store.Do(func(result *store.StoreResult) { 789 var members model.ChannelMembers 790 _, err := s.GetReplica().Select(&members, "SELECT * FROM ChannelMembers WHERE ChannelId = :ChannelId LIMIT :Limit OFFSET :Offset", map[string]interface{}{"ChannelId": channelId, "Limit": limit, "Offset": offset}) 791 if err != nil { 792 result.Err = model.NewAppError("SqlChannelStore.GetMembers", "store.sql_channel.get_members.app_error", nil, "channel_id="+channelId+err.Error(), http.StatusInternalServerError) 793 } else { 794 result.Data = &members 795 } 796 }) 797 } 798 799 func (s SqlChannelStore) GetMember(channelId string, userId string) store.StoreChannel { 800 return store.Do(func(result *store.StoreResult) { 801 var member model.ChannelMember 802 803 if err := s.GetReplica().SelectOne(&member, "SELECT * FROM ChannelMembers WHERE ChannelId = :ChannelId AND UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil { 804 if err == sql.ErrNoRows { 805 result.Err = model.NewAppError("SqlChannelStore.GetMember", store.MISSING_CHANNEL_MEMBER_ERROR, nil, "channel_id="+channelId+"user_id="+userId+","+err.Error(), http.StatusNotFound) 806 } else { 807 result.Err = model.NewAppError("SqlChannelStore.GetMember", "store.sql_channel.get_member.app_error", nil, "channel_id="+channelId+"user_id="+userId+","+err.Error(), http.StatusInternalServerError) 808 } 809 } else { 810 result.Data = &member 811 } 812 }) 813 } 814 815 func (us SqlChannelStore) InvalidateAllChannelMembersForUser(userId string) { 816 allChannelMembersForUserCache.Remove(userId) 817 } 818 819 func (us SqlChannelStore) IsUserInChannelUseCache(userId string, channelId string) bool { 820 if cacheItem, ok := allChannelMembersForUserCache.Get(userId); ok { 821 if us.metrics != nil { 822 us.metrics.IncrementMemCacheHitCounter("All Channel Members for User") 823 } 824 ids := cacheItem.(map[string]string) 825 if _, ok := ids[channelId]; ok { 826 return true 827 } else { 828 return false 829 } 830 } else { 831 if us.metrics != nil { 832 us.metrics.IncrementMemCacheMissCounter("All Channel Members for User") 833 } 834 } 835 836 if result := <-us.GetAllChannelMembersForUser(userId, true); result.Err != nil { 837 l4g.Error("SqlChannelStore.IsUserInChannelUseCache: " + result.Err.Error()) 838 return false 839 } else { 840 ids := result.Data.(map[string]string) 841 if _, ok := ids[channelId]; ok { 842 return true 843 } else { 844 return false 845 } 846 } 847 } 848 849 func (s SqlChannelStore) GetMemberForPost(postId string, userId string) store.StoreChannel { 850 return store.Do(func(result *store.StoreResult) { 851 member := &model.ChannelMember{} 852 if err := s.GetReplica().SelectOne( 853 member, 854 `SELECT 855 ChannelMembers.* 856 FROM 857 ChannelMembers, 858 Posts 859 WHERE 860 ChannelMembers.ChannelId = Posts.ChannelId 861 AND ChannelMembers.UserId = :UserId 862 AND Posts.Id = :PostId`, map[string]interface{}{"UserId": userId, "PostId": postId}); err != nil { 863 result.Err = model.NewAppError("SqlChannelStore.GetMemberForPost", "store.sql_channel.get_member_for_post.app_error", nil, "postId="+postId+", err="+err.Error(), http.StatusInternalServerError) 864 } else { 865 result.Data = member 866 } 867 }) 868 } 869 870 type allChannelMember struct { 871 ChannelId string 872 Roles string 873 } 874 875 func (s SqlChannelStore) GetAllChannelMembersForUser(userId string, allowFromCache bool) store.StoreChannel { 876 return store.Do(func(result *store.StoreResult) { 877 if allowFromCache { 878 if cacheItem, ok := allChannelMembersForUserCache.Get(userId); ok { 879 if s.metrics != nil { 880 s.metrics.IncrementMemCacheHitCounter("All Channel Members for User") 881 } 882 result.Data = cacheItem.(map[string]string) 883 return 884 } else { 885 if s.metrics != nil { 886 s.metrics.IncrementMemCacheMissCounter("All Channel Members for User") 887 } 888 } 889 } else { 890 if s.metrics != nil { 891 s.metrics.IncrementMemCacheMissCounter("All Channel Members for User") 892 } 893 } 894 895 var data []allChannelMember 896 _, err := s.GetReplica().Select(&data, "SELECT ChannelId, Roles FROM Channels, ChannelMembers WHERE Channels.Id = ChannelMembers.ChannelId AND ChannelMembers.UserId = :UserId AND Channels.DeleteAt = 0", map[string]interface{}{"UserId": userId}) 897 898 if err != nil { 899 result.Err = model.NewAppError("SqlChannelStore.GetAllChannelMembersForUser", "store.sql_channel.get_channels.get.app_error", nil, "userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 900 } else { 901 902 ids := make(map[string]string) 903 for i := range data { 904 ids[data[i].ChannelId] = data[i].Roles 905 } 906 907 result.Data = ids 908 909 if allowFromCache { 910 allChannelMembersForUserCache.AddWithExpiresInSecs(userId, ids, ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SEC) 911 } 912 } 913 }) 914 } 915 916 func (us SqlChannelStore) InvalidateCacheForChannelMembersNotifyProps(channelId string) { 917 allChannelMembersNotifyPropsForChannelCache.Remove(channelId) 918 } 919 920 type allChannelMemberNotifyProps struct { 921 UserId string 922 NotifyProps model.StringMap 923 } 924 925 func (s SqlChannelStore) GetAllChannelMembersNotifyPropsForChannel(channelId string, allowFromCache bool) store.StoreChannel { 926 return store.Do(func(result *store.StoreResult) { 927 if allowFromCache { 928 if cacheItem, ok := allChannelMembersNotifyPropsForChannelCache.Get(channelId); ok { 929 if s.metrics != nil { 930 s.metrics.IncrementMemCacheHitCounter("All Channel Members Notify Props for Channel") 931 } 932 result.Data = cacheItem.(map[string]model.StringMap) 933 return 934 } else { 935 if s.metrics != nil { 936 s.metrics.IncrementMemCacheMissCounter("All Channel Members Notify Props for Channel") 937 } 938 } 939 } else { 940 if s.metrics != nil { 941 s.metrics.IncrementMemCacheMissCounter("All Channel Members Notify Props for Channel") 942 } 943 } 944 945 var data []allChannelMemberNotifyProps 946 _, err := s.GetReplica().Select(&data, ` 947 SELECT ChannelMembers.UserId, ChannelMembers.NotifyProps 948 FROM Channels, ChannelMembers 949 WHERE Channels.Id = ChannelMembers.ChannelId AND ChannelMembers.ChannelId = :ChannelId`, map[string]interface{}{"ChannelId": channelId}) 950 951 if err != nil { 952 result.Err = model.NewAppError("SqlChannelStore.GetAllChannelMembersPropsForChannel", "store.sql_channel.get_members.app_error", nil, "channelId="+channelId+", err="+err.Error(), http.StatusInternalServerError) 953 } else { 954 955 props := make(map[string]model.StringMap) 956 for i := range data { 957 props[data[i].UserId] = data[i].NotifyProps 958 } 959 960 result.Data = props 961 962 allChannelMembersNotifyPropsForChannelCache.AddWithExpiresInSecs(channelId, props, ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SEC) 963 } 964 }) 965 } 966 967 func (us SqlChannelStore) InvalidateMemberCount(channelId string) { 968 channelMemberCountsCache.Remove(channelId) 969 } 970 971 func (s SqlChannelStore) GetMemberCountFromCache(channelId string) int64 { 972 if cacheItem, ok := channelMemberCountsCache.Get(channelId); ok { 973 if s.metrics != nil { 974 s.metrics.IncrementMemCacheHitCounter("Channel Member Counts") 975 } 976 return cacheItem.(int64) 977 } else { 978 if s.metrics != nil { 979 s.metrics.IncrementMemCacheMissCounter("Channel Member Counts") 980 } 981 } 982 983 if result := <-s.GetMemberCount(channelId, true); result.Err != nil { 984 return 0 985 } else { 986 return result.Data.(int64) 987 } 988 } 989 990 func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) store.StoreChannel { 991 return store.Do(func(result *store.StoreResult) { 992 if allowFromCache { 993 if cacheItem, ok := channelMemberCountsCache.Get(channelId); ok { 994 if s.metrics != nil { 995 s.metrics.IncrementMemCacheHitCounter("Channel Member Counts") 996 } 997 result.Data = cacheItem.(int64) 998 return 999 } else { 1000 if s.metrics != nil { 1001 s.metrics.IncrementMemCacheMissCounter("Channel Member Counts") 1002 } 1003 } 1004 } else { 1005 if s.metrics != nil { 1006 s.metrics.IncrementMemCacheMissCounter("Channel Member Counts") 1007 } 1008 } 1009 1010 count, err := s.GetReplica().SelectInt(` 1011 SELECT 1012 count(*) 1013 FROM 1014 ChannelMembers, 1015 Users 1016 WHERE 1017 ChannelMembers.UserId = Users.Id 1018 AND ChannelMembers.ChannelId = :ChannelId 1019 AND Users.DeleteAt = 0`, map[string]interface{}{"ChannelId": channelId}) 1020 if err != nil { 1021 result.Err = model.NewAppError("SqlChannelStore.GetMemberCount", "store.sql_channel.get_member_count.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 1022 } else { 1023 result.Data = count 1024 1025 if allowFromCache { 1026 channelMemberCountsCache.AddWithExpiresInSecs(channelId, count, CHANNEL_MEMBERS_COUNTS_CACHE_SEC) 1027 } 1028 } 1029 }) 1030 } 1031 1032 func (s SqlChannelStore) RemoveMember(channelId string, userId string) store.StoreChannel { 1033 return store.Do(func(result *store.StoreResult) { 1034 // Grab the channel we are saving this member to 1035 if cr := <-s.Get(channelId, true); cr.Err != nil { 1036 result.Err = cr.Err 1037 } else { 1038 channel := cr.Data.(*model.Channel) 1039 1040 _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE ChannelId = :ChannelId AND UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}) 1041 if err != nil { 1042 result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError) 1043 } else { 1044 // If sucessfull record members have changed in channel 1045 if mu := <-s.extraUpdated(channel); mu.Err != nil { 1046 result.Err = mu.Err 1047 } 1048 } 1049 } 1050 }) 1051 } 1052 1053 func (s SqlChannelStore) PermanentDeleteMembersByUser(userId string) store.StoreChannel { 1054 return store.Do(func(result *store.StoreResult) { 1055 if _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil { 1056 result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_channel.permanent_delete_members_by_user.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError) 1057 } 1058 }) 1059 } 1060 1061 func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string) store.StoreChannel { 1062 return store.Do(func(result *store.StoreResult) { 1063 props := make(map[string]interface{}) 1064 1065 updateIdQuery := "" 1066 for index, channelId := range channelIds { 1067 if len(updateIdQuery) > 0 { 1068 updateIdQuery += " OR " 1069 } 1070 1071 props["channelId"+strconv.Itoa(index)] = channelId 1072 updateIdQuery += "ChannelId = :channelId" + strconv.Itoa(index) 1073 } 1074 1075 selectIdQuery := strings.Replace(updateIdQuery, "ChannelId", "Id", -1) 1076 1077 var lastPostAtTimes []struct { 1078 Id string 1079 LastPostAt int64 1080 TotalMsgCount int64 1081 } 1082 1083 selectQuery := "SELECT Id, LastPostAt, TotalMsgCount FROM Channels WHERE (" + selectIdQuery + ")" 1084 1085 if _, err := s.GetMaster().Select(&lastPostAtTimes, selectQuery, props); err != nil { 1086 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) 1087 return 1088 } 1089 1090 times := map[string]int64{} 1091 msgCountQuery := "" 1092 lastViewedQuery := "" 1093 for index, t := range lastPostAtTimes { 1094 times[t.Id] = t.LastPostAt 1095 1096 props["msgCount"+strconv.Itoa(index)] = t.TotalMsgCount 1097 msgCountQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(MsgCount, :msgCount%d) ", index, index) 1098 1099 props["lastViewed"+strconv.Itoa(index)] = t.LastPostAt 1100 lastViewedQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(LastViewedAt, :lastViewed%d) ", index, index) 1101 1102 props["channelId"+strconv.Itoa(index)] = t.Id 1103 } 1104 1105 var updateQuery string 1106 1107 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 1108 updateQuery = `UPDATE 1109 ChannelMembers 1110 SET 1111 MentionCount = 0, 1112 MsgCount = CAST(CASE ChannelId ` + msgCountQuery + ` END AS BIGINT), 1113 LastViewedAt = CAST(CASE ChannelId ` + lastViewedQuery + ` END AS BIGINT), 1114 LastUpdateAt = CAST(CASE ChannelId ` + lastViewedQuery + ` END AS BIGINT) 1115 WHERE 1116 UserId = :UserId 1117 AND (` + updateIdQuery + `)` 1118 } else if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 1119 updateQuery = `UPDATE 1120 ChannelMembers 1121 SET 1122 MentionCount = 0, 1123 MsgCount = CASE ChannelId ` + msgCountQuery + ` END, 1124 LastViewedAt = CASE ChannelId ` + lastViewedQuery + ` END, 1125 LastUpdateAt = CASE ChannelId ` + lastViewedQuery + ` END 1126 WHERE 1127 UserId = :UserId 1128 AND (` + updateIdQuery + `)` 1129 } 1130 1131 props["UserId"] = userId 1132 1133 if _, err := s.GetMaster().Exec(updateQuery, props); err != nil { 1134 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) 1135 } else { 1136 result.Data = times 1137 } 1138 }) 1139 } 1140 1141 func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string) store.StoreChannel { 1142 return store.Do(func(result *store.StoreResult) { 1143 _, err := s.GetMaster().Exec( 1144 `UPDATE 1145 ChannelMembers 1146 SET 1147 MentionCount = MentionCount + 1, 1148 LastUpdateAt = :LastUpdateAt 1149 WHERE 1150 UserId = :UserId 1151 AND ChannelId = :ChannelId`, 1152 map[string]interface{}{"ChannelId": channelId, "UserId": userId, "LastUpdateAt": model.GetMillis()}) 1153 if err != nil { 1154 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) 1155 } 1156 }) 1157 } 1158 1159 func (s SqlChannelStore) GetAll(teamId string) store.StoreChannel { 1160 return store.Do(func(result *store.StoreResult) { 1161 var data []*model.Channel 1162 _, err := s.GetReplica().Select(&data, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Type != 'D' ORDER BY Name", map[string]interface{}{"TeamId": teamId}) 1163 1164 if err != nil { 1165 result.Err = model.NewAppError("SqlChannelStore.GetAll", "store.sql_channel.get_all.app_error", nil, "teamId="+teamId+", err="+err.Error(), http.StatusInternalServerError) 1166 } else { 1167 result.Data = data 1168 } 1169 }) 1170 } 1171 1172 func (s SqlChannelStore) GetForPost(postId string) store.StoreChannel { 1173 return store.Do(func(result *store.StoreResult) { 1174 channel := &model.Channel{} 1175 if err := s.GetReplica().SelectOne( 1176 channel, 1177 `SELECT 1178 Channels.* 1179 FROM 1180 Channels, 1181 Posts 1182 WHERE 1183 Channels.Id = Posts.ChannelId 1184 AND Posts.Id = :PostId`, map[string]interface{}{"PostId": postId}); err != nil { 1185 result.Err = model.NewAppError("SqlChannelStore.GetForPost", "store.sql_channel.get_for_post.app_error", nil, "postId="+postId+", err="+err.Error(), http.StatusInternalServerError) 1186 } else { 1187 result.Data = channel 1188 } 1189 }) 1190 } 1191 1192 func (s SqlChannelStore) AnalyticsTypeCount(teamId string, channelType string) store.StoreChannel { 1193 return store.Do(func(result *store.StoreResult) { 1194 query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType" 1195 1196 if len(teamId) > 0 { 1197 query += " AND TeamId = :TeamId" 1198 } 1199 1200 v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId, "ChannelType": channelType}) 1201 if err != nil { 1202 result.Err = model.NewAppError("SqlChannelStore.AnalyticsTypeCount", "store.sql_channel.analytics_type_count.app_error", nil, err.Error(), http.StatusInternalServerError) 1203 } else { 1204 result.Data = v 1205 } 1206 }) 1207 } 1208 1209 func (s SqlChannelStore) AnalyticsDeletedTypeCount(teamId string, channelType string) store.StoreChannel { 1210 return store.Do(func(result *store.StoreResult) { 1211 query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType AND DeleteAt > 0" 1212 1213 if len(teamId) > 0 { 1214 query += " AND TeamId = :TeamId" 1215 } 1216 1217 v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId, "ChannelType": channelType}) 1218 if err != nil { 1219 result.Err = model.NewAppError("SqlChannelStore.AnalyticsDeletedTypeCount", "store.sql_channel.analytics_deleted_type_count.app_error", nil, err.Error(), http.StatusInternalServerError) 1220 } else { 1221 result.Data = v 1222 } 1223 }) 1224 } 1225 1226 func (s SqlChannelStore) ExtraUpdateByUser(userId string, time int64) store.StoreChannel { 1227 return store.Do(func(result *store.StoreResult) { 1228 _, err := s.GetMaster().Exec( 1229 `UPDATE Channels SET ExtraUpdateAt = :Time 1230 WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId);`, 1231 map[string]interface{}{"UserId": userId, "Time": time}) 1232 1233 if err != nil { 1234 result.Err = model.NewAppError("SqlChannelStore.extraUpdated", "store.sql_channel.extra_updated.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError) 1235 } 1236 }) 1237 } 1238 1239 func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) store.StoreChannel { 1240 return store.Do(func(result *store.StoreResult) { 1241 members := &model.ChannelMembers{} 1242 _, err := s.GetReplica().Select(members, ` 1243 SELECT cm.* 1244 FROM ChannelMembers cm 1245 INNER JOIN Channels c 1246 ON c.Id = cm.ChannelId 1247 AND (c.TeamId = :TeamId OR c.TeamId = '') 1248 AND c.DeleteAt = 0 1249 WHERE cm.UserId = :UserId 1250 `, map[string]interface{}{"TeamId": teamId, "UserId": userId}) 1251 1252 if err != nil { 1253 result.Err = model.NewAppError("SqlChannelStore.GetMembersForUser", "store.sql_channel.get_members.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 1254 } else { 1255 result.Data = members 1256 } 1257 }) 1258 } 1259 1260 func (s SqlChannelStore) SearchInTeam(teamId string, term string) store.StoreChannel { 1261 return store.Do(func(result *store.StoreResult) { 1262 searchQuery := ` 1263 SELECT 1264 * 1265 FROM 1266 Channels 1267 WHERE 1268 TeamId = :TeamId 1269 AND Type = 'O' 1270 AND DeleteAt = 0 1271 SEARCH_CLAUSE 1272 ORDER BY DisplayName 1273 LIMIT 100` 1274 1275 *result = s.performSearch(searchQuery, term, map[string]interface{}{"TeamId": teamId}) 1276 }) 1277 } 1278 1279 func (s SqlChannelStore) SearchMore(userId string, teamId string, term string) store.StoreChannel { 1280 return store.Do(func(result *store.StoreResult) { 1281 searchQuery := ` 1282 SELECT 1283 * 1284 FROM 1285 Channels 1286 WHERE 1287 TeamId = :TeamId 1288 AND Type = 'O' 1289 AND DeleteAt = 0 1290 AND Id NOT IN (SELECT 1291 Channels.Id 1292 FROM 1293 Channels, 1294 ChannelMembers 1295 WHERE 1296 Id = ChannelId 1297 AND TeamId = :TeamId 1298 AND UserId = :UserId 1299 AND DeleteAt = 0) 1300 SEARCH_CLAUSE 1301 ORDER BY DisplayName 1302 LIMIT 100` 1303 1304 *result = s.performSearch(searchQuery, term, map[string]interface{}{"TeamId": teamId, "UserId": userId}) 1305 }) 1306 } 1307 1308 func (s SqlChannelStore) performSearch(searchQuery string, term string, parameters map[string]interface{}) store.StoreResult { 1309 result := store.StoreResult{} 1310 1311 // Copy the terms as we will need to prepare them differently for each search type. 1312 likeTerm := term 1313 fulltextTerm := term 1314 1315 searchColumns := "Name, DisplayName" 1316 1317 // These chars must be removed from the like query. 1318 for _, c := range ignoreLikeSearchChar { 1319 likeTerm = strings.Replace(likeTerm, c, "", -1) 1320 } 1321 1322 // These chars must be escaped in the like query. 1323 for _, c := range escapeLikeSearchChar { 1324 likeTerm = strings.Replace(likeTerm, c, "*"+c, -1) 1325 } 1326 1327 // These chars must be treated as spaces in the fulltext query. 1328 for _, c := range spaceFulltextSearchChar { 1329 fulltextTerm = strings.Replace(fulltextTerm, c, " ", -1) 1330 } 1331 1332 if likeTerm == "" { 1333 // If the likeTerm is empty after preparing, then don't bother searching. 1334 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1) 1335 } else { 1336 // Prepare the LIKE portion of the query. 1337 var searchFields []string 1338 for _, field := range strings.Split(searchColumns, ", ") { 1339 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 1340 searchFields = append(searchFields, fmt.Sprintf("lower(%s) LIKE lower(%s) escape '*'", field, ":LikeTerm")) 1341 } else { 1342 searchFields = append(searchFields, fmt.Sprintf("%s LIKE %s escape '*'", field, ":LikeTerm")) 1343 } 1344 } 1345 likeSearchClause := fmt.Sprintf("(%s)", strings.Join(searchFields, " OR ")) 1346 parameters["LikeTerm"] = fmt.Sprintf("%s%%", likeTerm) 1347 1348 // Prepare the FULLTEXT portion of the query. 1349 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 1350 splitTerm := strings.Fields(fulltextTerm) 1351 for i, t := range strings.Fields(fulltextTerm) { 1352 if i == len(splitTerm)-1 { 1353 splitTerm[i] = t + ":*" 1354 } else { 1355 splitTerm[i] = t + ":* &" 1356 } 1357 } 1358 1359 fulltextTerm = strings.Join(splitTerm, " ") 1360 1361 fulltextSearchClause := fmt.Sprintf("((%s) @@ to_tsquery(:FulltextTerm))", convertMySQLFullTextColumnsToPostgres(searchColumns)) 1362 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "AND ("+likeSearchClause+" OR "+fulltextSearchClause+")", 1) 1363 } else if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 1364 splitTerm := strings.Fields(fulltextTerm) 1365 for i, t := range strings.Fields(fulltextTerm) { 1366 splitTerm[i] = "+" + t + "*" 1367 } 1368 1369 fulltextTerm = strings.Join(splitTerm, " ") 1370 1371 fulltextSearchClause := fmt.Sprintf("MATCH(%s) AGAINST (:FulltextTerm IN BOOLEAN MODE)", searchColumns) 1372 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", fmt.Sprintf("AND (%s OR %s)", likeSearchClause, fulltextSearchClause), 1) 1373 } 1374 } 1375 1376 parameters["FulltextTerm"] = fulltextTerm 1377 1378 var channels model.ChannelList 1379 1380 if _, err := s.GetReplica().Select(&channels, searchQuery, parameters); err != nil { 1381 result.Err = model.NewAppError("SqlChannelStore.Search", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 1382 } else { 1383 result.Data = &channels 1384 } 1385 1386 return result 1387 } 1388 1389 func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) store.StoreChannel { 1390 return store.Do(func(result *store.StoreResult) { 1391 var members model.ChannelMembers 1392 props := make(map[string]interface{}) 1393 idQuery := "" 1394 1395 for index, userId := range userIds { 1396 if len(idQuery) > 0 { 1397 idQuery += ", " 1398 } 1399 1400 props["userId"+strconv.Itoa(index)] = userId 1401 idQuery += ":userId" + strconv.Itoa(index) 1402 } 1403 1404 props["ChannelId"] = channelId 1405 1406 if _, err := s.GetReplica().Select(&members, "SELECT * FROM ChannelMembers WHERE ChannelId = :ChannelId AND UserId IN ("+idQuery+")", props); err != nil { 1407 result.Err = model.NewAppError("SqlChannelStore.GetMembersByIds", "store.sql_channel.get_members_by_ids.app_error", nil, "channelId="+channelId+" "+err.Error(), http.StatusInternalServerError) 1408 } else { 1409 result.Data = &members 1410 1411 } 1412 }) 1413 }