github.com/qichengzx/mattermost-server@v4.5.1-0.20180604164826-2c75247c97d0+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_channels_txt", "Channels", "Name, DisplayName") 302 } 303 304 func (s SqlChannelStore) Save(channel *model.Channel, maxChannelsPerTeam int64) store.StoreChannel { 305 return store.Do(func(result *store.StoreResult) { 306 if channel.Type == model.CHANNEL_DIRECT { 307 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.direct_channel.app_error", nil, "", http.StatusBadRequest) 308 } else { 309 if transaction, err := s.GetMaster().Begin(); err != nil { 310 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 311 } else { 312 *result = s.saveChannelT(transaction, channel, maxChannelsPerTeam) 313 if result.Err != nil { 314 transaction.Rollback() 315 } else { 316 if err := transaction.Commit(); err != nil { 317 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 318 } 319 } 320 } 321 } 322 }) 323 } 324 325 func (s SqlChannelStore) CreateDirectChannel(userId string, otherUserId string) store.StoreChannel { 326 channel := new(model.Channel) 327 328 channel.DisplayName = "" 329 channel.Name = model.GetDMNameFromIds(otherUserId, userId) 330 331 channel.Header = "" 332 channel.Type = model.CHANNEL_DIRECT 333 334 cm1 := &model.ChannelMember{ 335 UserId: userId, 336 NotifyProps: model.GetDefaultChannelNotifyProps(), 337 SchemeUser: true, 338 } 339 cm2 := &model.ChannelMember{ 340 UserId: otherUserId, 341 NotifyProps: model.GetDefaultChannelNotifyProps(), 342 SchemeUser: true, 343 } 344 345 return s.SaveDirectChannel(channel, cm1, cm2) 346 } 347 348 func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1 *model.ChannelMember, member2 *model.ChannelMember) store.StoreChannel { 349 return store.Do(func(result *store.StoreResult) { 350 if directchannel.Type != model.CHANNEL_DIRECT { 351 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.not_direct.app_error", nil, "", http.StatusBadRequest) 352 } else { 353 if transaction, err := s.GetMaster().Begin(); err != nil { 354 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 355 } else { 356 directchannel.TeamId = "" 357 channelResult := s.saveChannelT(transaction, directchannel, 0) 358 359 if channelResult.Err != nil { 360 transaction.Rollback() 361 result.Err = channelResult.Err 362 result.Data = channelResult.Data 363 } else { 364 newChannel := channelResult.Data.(*model.Channel) 365 // Members need new channel ID 366 member1.ChannelId = newChannel.Id 367 member2.ChannelId = newChannel.Id 368 369 member1Result := s.saveMemberT(transaction, member1, newChannel) 370 member2Result := member1Result 371 if member1.UserId != member2.UserId { 372 member2Result = s.saveMemberT(transaction, member2, newChannel) 373 } 374 375 if member1Result.Err != nil || member2Result.Err != nil { 376 transaction.Rollback() 377 details := "" 378 if member1Result.Err != nil { 379 details += "Member1Err: " + member1Result.Err.Message 380 } 381 if member2Result.Err != nil { 382 details += "Member2Err: " + member2Result.Err.Message 383 } 384 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.add_members.app_error", nil, details, http.StatusInternalServerError) 385 } else { 386 if err := transaction.Commit(); err != nil { 387 result.Err = model.NewAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.commit.app_error", nil, err.Error(), http.StatusInternalServerError) 388 } else { 389 *result = channelResult 390 } 391 } 392 } 393 } 394 } 395 }) 396 } 397 398 func (s SqlChannelStore) saveChannelT(transaction *gorp.Transaction, channel *model.Channel, maxChannelsPerTeam int64) store.StoreResult { 399 result := store.StoreResult{} 400 401 if len(channel.Id) > 0 { 402 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.existing.app_error", nil, "id="+channel.Id, http.StatusBadRequest) 403 return result 404 } 405 406 channel.PreSave() 407 if result.Err = channel.IsValid(); result.Err != nil { 408 return result 409 } 410 411 if channel.Type != model.CHANNEL_DIRECT && channel.Type != model.CHANNEL_GROUP && maxChannelsPerTeam >= 0 { 412 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 { 413 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.current_count.app_error", nil, "teamId="+channel.TeamId+", "+err.Error(), http.StatusInternalServerError) 414 return result 415 } else if count >= maxChannelsPerTeam { 416 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.limit.app_error", nil, "teamId="+channel.TeamId, http.StatusBadRequest) 417 return result 418 } 419 } 420 421 if err := transaction.Insert(channel); err != nil { 422 if IsUniqueConstraintError(err, []string{"Name", "channels_name_teamid_key"}) { 423 dupChannel := model.Channel{} 424 s.GetMaster().SelectOne(&dupChannel, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name = :Name", map[string]interface{}{"TeamId": channel.TeamId, "Name": channel.Name}) 425 if dupChannel.DeleteAt > 0 { 426 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.previously.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 427 } else { 428 result.Err = model.NewAppError("SqlChannelStore.Save", store.CHANNEL_EXISTS_ERROR, nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 429 result.Data = &dupChannel 430 } 431 } else { 432 result.Err = model.NewAppError("SqlChannelStore.Save", "store.sql_channel.save_channel.save.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusInternalServerError) 433 } 434 } else { 435 result.Data = channel 436 } 437 438 return result 439 } 440 441 func (s SqlChannelStore) Update(channel *model.Channel) store.StoreChannel { 442 return store.Do(func(result *store.StoreResult) { 443 channel.PreUpdate() 444 445 if result.Err = channel.IsValid(); result.Err != nil { 446 return 447 } 448 449 if count, err := s.GetMaster().Update(channel); err != nil { 450 if IsUniqueConstraintError(err, []string{"Name", "channels_name_teamid_key"}) { 451 dupChannel := model.Channel{} 452 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}) 453 if dupChannel.DeleteAt > 0 { 454 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.previously.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 455 } else { 456 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.exists.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusBadRequest) 457 } 458 } else { 459 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.updating.app_error", nil, "id="+channel.Id+", "+err.Error(), http.StatusInternalServerError) 460 } 461 } else if count != 1 { 462 result.Err = model.NewAppError("SqlChannelStore.Update", "store.sql_channel.update.app_error", nil, "id="+channel.Id, http.StatusInternalServerError) 463 } else { 464 result.Data = channel 465 } 466 }) 467 } 468 469 func (s SqlChannelStore) GetChannelUnread(channelId, userId string) store.StoreChannel { 470 return store.Do(func(result *store.StoreResult) { 471 var unreadChannel model.ChannelUnread 472 err := s.GetReplica().SelectOne(&unreadChannel, 473 `SELECT 474 Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps 475 FROM 476 Channels, ChannelMembers 477 WHERE 478 Id = ChannelId 479 AND Id = :ChannelId 480 AND UserId = :UserId 481 AND DeleteAt = 0`, 482 map[string]interface{}{"ChannelId": channelId, "UserId": userId}) 483 484 if err != nil { 485 result.Err = model.NewAppError("SqlChannelStore.GetChannelUnread", "store.sql_channel.get_unread.app_error", nil, "channelId="+channelId+" "+err.Error(), http.StatusInternalServerError) 486 if err == sql.ErrNoRows { 487 result.Err.StatusCode = http.StatusNotFound 488 } 489 } else { 490 result.Data = &unreadChannel 491 } 492 }) 493 } 494 495 func (s SqlChannelStore) InvalidateChannel(id string) { 496 channelCache.Remove(id) 497 if s.metrics != nil { 498 s.metrics.IncrementMemCacheInvalidationCounter("Channel - Remove by ChannelId") 499 } 500 } 501 502 func (s SqlChannelStore) InvalidateChannelByName(teamId, name string) { 503 channelByNameCache.Remove(teamId + name) 504 if s.metrics != nil { 505 s.metrics.IncrementMemCacheInvalidationCounter("Channel by Name - Remove by TeamId and Name") 506 } 507 } 508 509 func (s SqlChannelStore) Get(id string, allowFromCache bool) store.StoreChannel { 510 return s.get(id, false, allowFromCache) 511 } 512 513 func (s SqlChannelStore) GetPinnedPosts(channelId string) store.StoreChannel { 514 return store.Do(func(result *store.StoreResult) { 515 pl := model.NewPostList() 516 517 var posts []*model.Post 518 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 { 519 result.Err = model.NewAppError("SqlPostStore.GetPinnedPosts", "store.sql_channel.pinned_posts.app_error", nil, err.Error(), http.StatusInternalServerError) 520 } else { 521 for _, post := range posts { 522 pl.AddPost(post) 523 pl.AddOrder(post.Id) 524 } 525 } 526 527 result.Data = pl 528 }) 529 } 530 531 func (s SqlChannelStore) GetFromMaster(id string) store.StoreChannel { 532 return s.get(id, true, false) 533 } 534 535 func (s SqlChannelStore) get(id string, master bool, allowFromCache bool) store.StoreChannel { 536 return store.Do(func(result *store.StoreResult) { 537 var db *gorp.DbMap 538 if master { 539 db = s.GetMaster() 540 } else { 541 db = s.GetReplica() 542 } 543 544 if allowFromCache { 545 if cacheItem, ok := channelCache.Get(id); ok { 546 if s.metrics != nil { 547 s.metrics.IncrementMemCacheHitCounter("Channel") 548 } 549 result.Data = (cacheItem.(*model.Channel)).DeepCopy() 550 return 551 } else { 552 if s.metrics != nil { 553 s.metrics.IncrementMemCacheMissCounter("Channel") 554 } 555 } 556 } else { 557 if s.metrics != nil { 558 s.metrics.IncrementMemCacheMissCounter("Channel") 559 } 560 } 561 562 if obj, err := db.Get(model.Channel{}, id); err != nil { 563 result.Err = model.NewAppError("SqlChannelStore.Get", "store.sql_channel.get.find.app_error", nil, "id="+id+", "+err.Error(), http.StatusInternalServerError) 564 } else if obj == nil { 565 result.Err = model.NewAppError("SqlChannelStore.Get", "store.sql_channel.get.existing.app_error", nil, "id="+id, http.StatusNotFound) 566 } else { 567 result.Data = obj.(*model.Channel) 568 channelCache.AddWithExpiresInSecs(id, obj.(*model.Channel), CHANNEL_CACHE_SEC) 569 } 570 }) 571 } 572 573 func (s SqlChannelStore) Delete(channelId string, time int64) store.StoreChannel { 574 return s.SetDeleteAt(channelId, time, time) 575 } 576 577 func (s SqlChannelStore) Restore(channelId string, time int64) store.StoreChannel { 578 return s.SetDeleteAt(channelId, 0, time) 579 } 580 581 func (s SqlChannelStore) SetDeleteAt(channelId string, deleteAt int64, updateAt int64) store.StoreChannel { 582 return store.Do(func(result *store.StoreResult) { 583 _, err := s.GetMaster().Exec("Update Channels SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt WHERE Id = :ChannelId", map[string]interface{}{"DeleteAt": deleteAt, "UpdateAt": updateAt, "ChannelId": channelId}) 584 if err != nil { 585 result.Err = model.NewAppError("SqlChannelStore.Delete", "store.sql_channel.delete.channel.app_error", nil, "id="+channelId+", err="+err.Error(), http.StatusInternalServerError) 586 } 587 }) 588 } 589 590 func (s SqlChannelStore) PermanentDeleteByTeam(teamId string) store.StoreChannel { 591 return store.Do(func(result *store.StoreResult) { 592 if _, err := s.GetMaster().Exec("DELETE FROM Channels WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil { 593 result.Err = model.NewAppError("SqlChannelStore.PermanentDeleteByTeam", "store.sql_channel.permanent_delete_by_team.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError) 594 } 595 }) 596 } 597 598 func (s SqlChannelStore) PermanentDelete(channelId string) store.StoreChannel { 599 return store.Do(func(result *store.StoreResult) { 600 if _, err := s.GetMaster().Exec("DELETE FROM Channels WHERE Id = :ChannelId", map[string]interface{}{"ChannelId": channelId}); err != nil { 601 result.Err = model.NewAppError("SqlChannelStore.PermanentDelete", "store.sql_channel.permanent_delete.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 602 } 603 }) 604 } 605 606 func (s SqlChannelStore) PermanentDeleteMembersByChannel(channelId string) store.StoreChannel { 607 return store.Do(func(result *store.StoreResult) { 608 _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelId}) 609 if err != nil { 610 result.Err = model.NewAppError("SqlChannelStore.RemoveAllMembersByChannel", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 611 } 612 }) 613 } 614 615 func (s SqlChannelStore) GetChannels(teamId string, userId string) store.StoreChannel { 616 return store.Do(func(result *store.StoreResult) { 617 data := &model.ChannelList{} 618 _, 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}) 619 620 if err != nil { 621 result.Err = model.NewAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 622 } else { 623 if len(*data) == 0 { 624 result.Err = model.NewAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.not_found.app_error", nil, "teamId="+teamId+", userId="+userId, http.StatusBadRequest) 625 } else { 626 result.Data = data 627 } 628 } 629 }) 630 } 631 632 func (s SqlChannelStore) GetMoreChannels(teamId string, userId string, offset int, limit int) store.StoreChannel { 633 return store.Do(func(result *store.StoreResult) { 634 data := &model.ChannelList{} 635 _, err := s.GetReplica().Select(data, 636 `SELECT 637 * 638 FROM 639 Channels 640 WHERE 641 TeamId = :TeamId1 642 AND Type IN ('O') 643 AND DeleteAt = 0 644 AND Id NOT IN (SELECT 645 Channels.Id 646 FROM 647 Channels, 648 ChannelMembers 649 WHERE 650 Id = ChannelId 651 AND TeamId = :TeamId2 652 AND UserId = :UserId 653 AND DeleteAt = 0) 654 ORDER BY DisplayName 655 LIMIT :Limit 656 OFFSET :Offset`, 657 map[string]interface{}{"TeamId1": teamId, "TeamId2": teamId, "UserId": userId, "Limit": limit, "Offset": offset}) 658 659 if err != nil { 660 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) 661 } else { 662 result.Data = data 663 } 664 }) 665 } 666 667 func (s SqlChannelStore) GetPublicChannelsForTeam(teamId string, offset int, limit int) store.StoreChannel { 668 return store.Do(func(result *store.StoreResult) { 669 data := &model.ChannelList{} 670 _, err := s.GetReplica().Select(data, 671 `SELECT 672 * 673 FROM 674 Channels 675 WHERE 676 TeamId = :TeamId 677 AND Type = 'O' 678 AND DeleteAt = 0 679 ORDER BY DisplayName 680 LIMIT :Limit 681 OFFSET :Offset`, 682 map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset}) 683 684 if err != nil { 685 result.Err = model.NewAppError("SqlChannelStore.GetPublicChannelsForTeam", "store.sql_channel.get_public_channels.get.app_error", nil, "teamId="+teamId+", err="+err.Error(), http.StatusInternalServerError) 686 } else { 687 result.Data = data 688 } 689 }) 690 } 691 692 func (s SqlChannelStore) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) store.StoreChannel { 693 return store.Do(func(result *store.StoreResult) { 694 props := make(map[string]interface{}) 695 props["teamId"] = teamId 696 697 idQuery := "" 698 699 for index, channelId := range channelIds { 700 if len(idQuery) > 0 { 701 idQuery += ", " 702 } 703 704 props["channelId"+strconv.Itoa(index)] = channelId 705 idQuery += ":channelId" + strconv.Itoa(index) 706 } 707 708 data := &model.ChannelList{} 709 _, err := s.GetReplica().Select(data, 710 `SELECT 711 * 712 FROM 713 Channels 714 WHERE 715 TeamId = :teamId 716 AND Type = 'O' 717 AND DeleteAt = 0 718 AND Id IN (`+idQuery+`) 719 ORDER BY DisplayName`, 720 props) 721 722 if err != nil { 723 result.Err = model.NewAppError("SqlChannelStore.GetPublicChannelsByIdsForTeam", "store.sql_channel.get_channels_by_ids.get.app_error", nil, err.Error(), http.StatusInternalServerError) 724 } 725 726 if len(*data) == 0 { 727 result.Err = model.NewAppError("SqlChannelStore.GetPublicChannelsByIdsForTeam", "store.sql_channel.get_channels_by_ids.not_found.app_error", nil, "", http.StatusNotFound) 728 } 729 730 result.Data = data 731 }) 732 } 733 734 type channelIdWithCountAndUpdateAt struct { 735 Id string 736 TotalMsgCount int64 737 UpdateAt int64 738 } 739 740 func (s SqlChannelStore) GetChannelCounts(teamId string, userId string) store.StoreChannel { 741 return store.Do(func(result *store.StoreResult) { 742 var data []channelIdWithCountAndUpdateAt 743 _, 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}) 744 745 if err != nil { 746 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) 747 } else { 748 counts := &model.ChannelCounts{Counts: make(map[string]int64), UpdateTimes: make(map[string]int64)} 749 for i := range data { 750 v := data[i] 751 counts.Counts[v.Id] = v.TotalMsgCount 752 counts.UpdateTimes[v.Id] = v.UpdateAt 753 } 754 755 result.Data = counts 756 } 757 }) 758 } 759 760 func (s SqlChannelStore) GetTeamChannels(teamId string) store.StoreChannel { 761 return store.Do(func(result *store.StoreResult) { 762 data := &model.ChannelList{} 763 _, err := s.GetReplica().Select(data, "SELECT * FROM Channels WHERE TeamId = :TeamId And Type != 'D' ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId}) 764 765 if err != nil { 766 result.Err = model.NewAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.get.app_error", nil, "teamId="+teamId+", err="+err.Error(), http.StatusInternalServerError) 767 } else { 768 if len(*data) == 0 { 769 result.Err = model.NewAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.not_found.app_error", nil, "teamId="+teamId, http.StatusNotFound) 770 } else { 771 result.Data = data 772 } 773 } 774 }) 775 } 776 777 func (s SqlChannelStore) GetByName(teamId string, name string, allowFromCache bool) store.StoreChannel { 778 return s.getByName(teamId, name, false, allowFromCache) 779 } 780 781 func (s SqlChannelStore) GetByNames(teamId string, names []string, allowFromCache bool) store.StoreChannel { 782 return store.Do(func(result *store.StoreResult) { 783 var channels []*model.Channel 784 785 if allowFromCache { 786 var misses []string 787 visited := make(map[string]struct{}) 788 for _, name := range names { 789 if _, ok := visited[name]; ok { 790 continue 791 } 792 visited[name] = struct{}{} 793 if cacheItem, ok := channelByNameCache.Get(teamId + name); ok { 794 if s.metrics != nil { 795 s.metrics.IncrementMemCacheHitCounter("Channel By Name") 796 } 797 channels = append(channels, cacheItem.(*model.Channel)) 798 } else { 799 if s.metrics != nil { 800 s.metrics.IncrementMemCacheMissCounter("Channel By Name") 801 } 802 misses = append(misses, name) 803 } 804 } 805 names = misses 806 } 807 808 if len(names) > 0 { 809 props := map[string]interface{}{} 810 var namePlaceholders []string 811 for _, name := range names { 812 key := fmt.Sprintf("Name%v", len(namePlaceholders)) 813 props[key] = name 814 namePlaceholders = append(namePlaceholders, ":"+key) 815 } 816 817 var query string 818 if teamId == "" { 819 query = `SELECT * FROM Channels WHERE Name IN (` + strings.Join(namePlaceholders, ", ") + `) AND DeleteAt = 0` 820 } else { 821 props["TeamId"] = teamId 822 query = `SELECT * FROM Channels WHERE Name IN (` + strings.Join(namePlaceholders, ", ") + `) AND TeamId = :TeamId AND DeleteAt = 0` 823 } 824 825 var dbChannels []*model.Channel 826 if _, err := s.GetReplica().Select(&dbChannels, query, props); err != nil && err != sql.ErrNoRows { 827 result.Err = model.NewAppError("SqlChannelStore.GetByName", "store.sql_channel.get_by_name.existing.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError) 828 return 829 } 830 for _, channel := range dbChannels { 831 channelByNameCache.AddWithExpiresInSecs(teamId+channel.Name, channel, CHANNEL_CACHE_SEC) 832 channels = append(channels, channel) 833 } 834 } 835 836 result.Data = channels 837 }) 838 } 839 840 func (s SqlChannelStore) GetByNameIncludeDeleted(teamId string, name string, allowFromCache bool) store.StoreChannel { 841 return s.getByName(teamId, name, true, allowFromCache) 842 } 843 844 func (s SqlChannelStore) getByName(teamId string, name string, includeDeleted bool, allowFromCache bool) store.StoreChannel { 845 var query string 846 if includeDeleted { 847 query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name" 848 } else { 849 query = "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name AND DeleteAt = 0" 850 } 851 return store.Do(func(result *store.StoreResult) { 852 channel := model.Channel{} 853 854 if allowFromCache { 855 if cacheItem, ok := channelByNameCache.Get(teamId + name); ok { 856 if s.metrics != nil { 857 s.metrics.IncrementMemCacheHitCounter("Channel By Name") 858 } 859 result.Data = cacheItem.(*model.Channel) 860 return 861 } else { 862 if s.metrics != nil { 863 s.metrics.IncrementMemCacheMissCounter("Channel By Name") 864 } 865 } 866 } 867 if err := s.GetReplica().SelectOne(&channel, query, map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil { 868 if err == sql.ErrNoRows { 869 result.Err = model.NewAppError("SqlChannelStore.GetByName", store.MISSING_CHANNEL_ERROR, nil, "teamId="+teamId+", "+"name="+name+", "+err.Error(), http.StatusNotFound) 870 } else { 871 result.Err = model.NewAppError("SqlChannelStore.GetByName", "store.sql_channel.get_by_name.existing.app_error", nil, "teamId="+teamId+", "+"name="+name+", "+err.Error(), http.StatusInternalServerError) 872 } 873 } else { 874 result.Data = &channel 875 channelByNameCache.AddWithExpiresInSecs(teamId+name, &channel, CHANNEL_CACHE_SEC) 876 } 877 }) 878 } 879 880 func (s SqlChannelStore) GetDeletedByName(teamId string, name string) store.StoreChannel { 881 return store.Do(func(result *store.StoreResult) { 882 channel := model.Channel{} 883 884 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 { 885 if err == sql.ErrNoRows { 886 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) 887 } else { 888 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) 889 } 890 } else { 891 result.Data = &channel 892 } 893 }) 894 } 895 896 func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int) store.StoreChannel { 897 return store.Do(func(result *store.StoreResult) { 898 channels := &model.ChannelList{} 899 900 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 { 901 if err == sql.ErrNoRows { 902 result.Err = model.NewAppError("SqlChannelStore.GetDeleted", "store.sql_channel.get_deleted.missing.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusNotFound) 903 } else { 904 result.Err = model.NewAppError("SqlChannelStore.GetDeleted", "store.sql_channel.get_deleted.existing.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError) 905 } 906 } else { 907 result.Data = channels 908 } 909 }) 910 } 911 912 var CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY = ` 913 SELECT 914 ChannelMembers.*, 915 TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole, 916 TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole, 917 ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole, 918 ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole 919 FROM 920 ChannelMembers 921 INNER JOIN 922 Channels ON ChannelMembers.ChannelId = Channels.Id 923 LEFT JOIN 924 Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id 925 LEFT JOIN 926 Teams ON Channels.TeamId = Teams.Id 927 LEFT JOIN 928 Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id 929 ` 930 931 func (s SqlChannelStore) SaveMember(member *model.ChannelMember) store.StoreChannel { 932 return store.Do(func(result *store.StoreResult) { 933 // Grab the channel we are saving this member to 934 if cr := <-s.GetFromMaster(member.ChannelId); cr.Err != nil { 935 result.Err = cr.Err 936 } else { 937 channel := cr.Data.(*model.Channel) 938 939 if transaction, err := s.GetMaster().Begin(); err != nil { 940 result.Err = model.NewAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 941 } else { 942 *result = s.saveMemberT(transaction, member, channel) 943 if result.Err != nil { 944 transaction.Rollback() 945 } else { 946 if err := transaction.Commit(); err != nil { 947 result.Err = model.NewAppError("SqlChannelStore.SaveMember", "store.sql_channel.save_member.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 948 } 949 } 950 } 951 } 952 953 s.InvalidateAllChannelMembersForUser(member.UserId) 954 }) 955 } 956 957 func (s SqlChannelStore) saveMemberT(transaction *gorp.Transaction, member *model.ChannelMember, channel *model.Channel) store.StoreResult { 958 result := store.StoreResult{} 959 960 member.PreSave() 961 if result.Err = member.IsValid(); result.Err != nil { 962 return result 963 } 964 965 dbMember := NewChannelMemberFromModel(member) 966 967 if err := transaction.Insert(dbMember); err != nil { 968 if IsUniqueConstraintError(err, []string{"ChannelId", "channelmembers_pkey"}) { 969 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) 970 } else { 971 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) 972 } 973 } else { 974 var retrievedMember channelMemberWithSchemeRoles 975 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 { 976 if err == sql.ErrNoRows { 977 result.Err = model.NewAppError("SqlChannelStore.GetMember", store.MISSING_CHANNEL_MEMBER_ERROR, nil, "channel_id="+dbMember.ChannelId+"user_id="+dbMember.UserId+","+err.Error(), http.StatusNotFound) 978 } else { 979 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) 980 } 981 } else { 982 result.Data = retrievedMember.ToModel() 983 } 984 } 985 986 return result 987 } 988 989 func (s SqlChannelStore) UpdateMember(member *model.ChannelMember) store.StoreChannel { 990 return store.Do(func(result *store.StoreResult) { 991 member.PreUpdate() 992 993 if result.Err = member.IsValid(); result.Err != nil { 994 return 995 } 996 997 if _, err := s.GetMaster().Update(NewChannelMemberFromModel(member)); err != nil { 998 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) 999 } else { 1000 var dbMember channelMemberWithSchemeRoles 1001 1002 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 { 1003 if err == sql.ErrNoRows { 1004 result.Err = model.NewAppError("SqlChannelStore.GetMember", store.MISSING_CHANNEL_MEMBER_ERROR, nil, "channel_id="+member.ChannelId+"user_id="+member.UserId+","+err.Error(), http.StatusNotFound) 1005 } else { 1006 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) 1007 } 1008 } else { 1009 result.Data = dbMember.ToModel() 1010 } 1011 } 1012 }) 1013 } 1014 1015 func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) store.StoreChannel { 1016 return store.Do(func(result *store.StoreResult) { 1017 var dbMembers channelMemberWithSchemeRolesList 1018 _, 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}) 1019 if err != nil { 1020 result.Err = model.NewAppError("SqlChannelStore.GetMembers", "store.sql_channel.get_members.app_error", nil, "channel_id="+channelId+err.Error(), http.StatusInternalServerError) 1021 } else { 1022 result.Data = dbMembers.ToModel() 1023 } 1024 }) 1025 } 1026 1027 func (s SqlChannelStore) GetMember(channelId string, userId string) store.StoreChannel { 1028 return store.Do(func(result *store.StoreResult) { 1029 var dbMember channelMemberWithSchemeRoles 1030 1031 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 { 1032 if err == sql.ErrNoRows { 1033 result.Err = model.NewAppError("SqlChannelStore.GetMember", store.MISSING_CHANNEL_MEMBER_ERROR, nil, "channel_id="+channelId+"user_id="+userId+","+err.Error(), http.StatusNotFound) 1034 } else { 1035 result.Err = model.NewAppError("SqlChannelStore.GetMember", "store.sql_channel.get_member.app_error", nil, "channel_id="+channelId+"user_id="+userId+","+err.Error(), http.StatusInternalServerError) 1036 } 1037 } else { 1038 result.Data = dbMember.ToModel() 1039 } 1040 }) 1041 } 1042 1043 func (s SqlChannelStore) InvalidateAllChannelMembersForUser(userId string) { 1044 allChannelMembersForUserCache.Remove(userId) 1045 if s.metrics != nil { 1046 s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members for User - Remove by UserId") 1047 } 1048 } 1049 1050 func (s SqlChannelStore) IsUserInChannelUseCache(userId string, channelId string) bool { 1051 if cacheItem, ok := allChannelMembersForUserCache.Get(userId); ok { 1052 if s.metrics != nil { 1053 s.metrics.IncrementMemCacheHitCounter("All Channel Members for User") 1054 } 1055 ids := cacheItem.(map[string]string) 1056 if _, ok := ids[channelId]; ok { 1057 return true 1058 } else { 1059 return false 1060 } 1061 } else { 1062 if s.metrics != nil { 1063 s.metrics.IncrementMemCacheMissCounter("All Channel Members for User") 1064 } 1065 } 1066 1067 if result := <-s.GetAllChannelMembersForUser(userId, true); result.Err != nil { 1068 mlog.Error("SqlChannelStore.IsUserInChannelUseCache: " + result.Err.Error()) 1069 return false 1070 } else { 1071 ids := result.Data.(map[string]string) 1072 if _, ok := ids[channelId]; ok { 1073 return true 1074 } else { 1075 return false 1076 } 1077 } 1078 } 1079 1080 func (s SqlChannelStore) GetMemberForPost(postId string, userId string) store.StoreChannel { 1081 return store.Do(func(result *store.StoreResult) { 1082 var dbMember channelMemberWithSchemeRoles 1083 if err := s.GetReplica().SelectOne(&dbMember, 1084 ` 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 Posts ON ChannelMembers.ChannelId = Posts.ChannelId 1095 INNER JOIN 1096 Channels ON ChannelMembers.ChannelId = Channels.Id 1097 LEFT JOIN 1098 Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id 1099 LEFT JOIN 1100 Teams ON Channels.TeamId = Teams.Id 1101 LEFT JOIN 1102 Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id 1103 WHERE 1104 ChannelMembers.UserId = :UserId 1105 AND Posts.Id = :PostId`, map[string]interface{}{"UserId": userId, "PostId": postId}); err != nil { 1106 result.Err = model.NewAppError("SqlChannelStore.GetMemberForPost", "store.sql_channel.get_member_for_post.app_error", nil, "postId="+postId+", err="+err.Error(), http.StatusInternalServerError) 1107 } else { 1108 result.Data = dbMember.ToModel() 1109 } 1110 }) 1111 } 1112 1113 func (s SqlChannelStore) GetAllChannelMembersForUser(userId string, allowFromCache bool) store.StoreChannel { 1114 return store.Do(func(result *store.StoreResult) { 1115 if allowFromCache { 1116 if cacheItem, ok := allChannelMembersForUserCache.Get(userId); ok { 1117 if s.metrics != nil { 1118 s.metrics.IncrementMemCacheHitCounter("All Channel Members for User") 1119 } 1120 result.Data = cacheItem.(map[string]string) 1121 return 1122 } else { 1123 if s.metrics != nil { 1124 s.metrics.IncrementMemCacheMissCounter("All Channel Members for User") 1125 } 1126 } 1127 } else { 1128 if s.metrics != nil { 1129 s.metrics.IncrementMemCacheMissCounter("All Channel Members for User") 1130 } 1131 } 1132 1133 var data allChannelMembers 1134 _, err := s.GetReplica().Select(&data, ` 1135 SELECT 1136 ChannelMembers.ChannelId, ChannelMembers.Roles, ChannelMembers.SchemeUser, ChannelMembers.SchemeAdmin, 1137 TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole, 1138 TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole, 1139 ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole, 1140 ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole 1141 FROM 1142 ChannelMembers 1143 INNER JOIN 1144 Channels ON ChannelMembers.ChannelId = Channels.Id 1145 LEFT JOIN 1146 Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id 1147 LEFT JOIN 1148 Teams ON Channels.TeamId = Teams.Id 1149 LEFT JOIN 1150 Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id 1151 WHERE 1152 Channels.DeleteAt = 0 1153 AND ChannelMembers.UserId = :UserId`, map[string]interface{}{"UserId": userId}) 1154 1155 if err != nil { 1156 result.Err = model.NewAppError("SqlChannelStore.GetAllChannelMembersForUser", "store.sql_channel.get_channels.get.app_error", nil, "userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 1157 } else { 1158 ids := data.ToMapStringString() 1159 1160 result.Data = ids 1161 1162 if allowFromCache { 1163 allChannelMembersForUserCache.AddWithExpiresInSecs(userId, ids, ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SEC) 1164 } 1165 } 1166 }) 1167 } 1168 1169 func (s SqlChannelStore) InvalidateCacheForChannelMembersNotifyProps(channelId string) { 1170 allChannelMembersNotifyPropsForChannelCache.Remove(channelId) 1171 if s.metrics != nil { 1172 s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members Notify Props for Channel - Remove by ChannelId") 1173 } 1174 } 1175 1176 type allChannelMemberNotifyProps struct { 1177 UserId string 1178 NotifyProps model.StringMap 1179 } 1180 1181 func (s SqlChannelStore) GetAllChannelMembersNotifyPropsForChannel(channelId string, allowFromCache bool) store.StoreChannel { 1182 return store.Do(func(result *store.StoreResult) { 1183 if allowFromCache { 1184 if cacheItem, ok := allChannelMembersNotifyPropsForChannelCache.Get(channelId); ok { 1185 if s.metrics != nil { 1186 s.metrics.IncrementMemCacheHitCounter("All Channel Members Notify Props for Channel") 1187 } 1188 result.Data = cacheItem.(map[string]model.StringMap) 1189 return 1190 } else { 1191 if s.metrics != nil { 1192 s.metrics.IncrementMemCacheMissCounter("All Channel Members Notify Props for Channel") 1193 } 1194 } 1195 } else { 1196 if s.metrics != nil { 1197 s.metrics.IncrementMemCacheMissCounter("All Channel Members Notify Props for Channel") 1198 } 1199 } 1200 1201 var data []allChannelMemberNotifyProps 1202 _, err := s.GetReplica().Select(&data, ` 1203 SELECT UserId, NotifyProps 1204 FROM ChannelMembers 1205 WHERE ChannelId = :ChannelId`, map[string]interface{}{"ChannelId": channelId}) 1206 1207 if err != nil { 1208 result.Err = model.NewAppError("SqlChannelStore.GetAllChannelMembersPropsForChannel", "store.sql_channel.get_members.app_error", nil, "channelId="+channelId+", err="+err.Error(), http.StatusInternalServerError) 1209 } else { 1210 1211 props := make(map[string]model.StringMap) 1212 for i := range data { 1213 props[data[i].UserId] = data[i].NotifyProps 1214 } 1215 1216 result.Data = props 1217 1218 allChannelMembersNotifyPropsForChannelCache.AddWithExpiresInSecs(channelId, props, ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SEC) 1219 } 1220 }) 1221 } 1222 1223 func (s SqlChannelStore) InvalidateMemberCount(channelId string) { 1224 channelMemberCountsCache.Remove(channelId) 1225 if s.metrics != nil { 1226 s.metrics.IncrementMemCacheInvalidationCounter("Channel Member Counts - Remove by ChannelId") 1227 } 1228 } 1229 1230 func (s SqlChannelStore) GetMemberCountFromCache(channelId string) int64 { 1231 if cacheItem, ok := channelMemberCountsCache.Get(channelId); ok { 1232 if s.metrics != nil { 1233 s.metrics.IncrementMemCacheHitCounter("Channel Member Counts") 1234 } 1235 return cacheItem.(int64) 1236 } else { 1237 if s.metrics != nil { 1238 s.metrics.IncrementMemCacheMissCounter("Channel Member Counts") 1239 } 1240 } 1241 1242 if result := <-s.GetMemberCount(channelId, true); result.Err != nil { 1243 return 0 1244 } else { 1245 return result.Data.(int64) 1246 } 1247 } 1248 1249 func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) store.StoreChannel { 1250 return store.Do(func(result *store.StoreResult) { 1251 if allowFromCache { 1252 if cacheItem, ok := channelMemberCountsCache.Get(channelId); ok { 1253 if s.metrics != nil { 1254 s.metrics.IncrementMemCacheHitCounter("Channel Member Counts") 1255 } 1256 result.Data = cacheItem.(int64) 1257 return 1258 } else { 1259 if s.metrics != nil { 1260 s.metrics.IncrementMemCacheMissCounter("Channel Member Counts") 1261 } 1262 } 1263 } else { 1264 if s.metrics != nil { 1265 s.metrics.IncrementMemCacheMissCounter("Channel Member Counts") 1266 } 1267 } 1268 1269 count, err := s.GetReplica().SelectInt(` 1270 SELECT 1271 count(*) 1272 FROM 1273 ChannelMembers, 1274 Users 1275 WHERE 1276 ChannelMembers.UserId = Users.Id 1277 AND ChannelMembers.ChannelId = :ChannelId 1278 AND Users.DeleteAt = 0`, map[string]interface{}{"ChannelId": channelId}) 1279 if err != nil { 1280 result.Err = model.NewAppError("SqlChannelStore.GetMemberCount", "store.sql_channel.get_member_count.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError) 1281 } else { 1282 result.Data = count 1283 1284 if allowFromCache { 1285 channelMemberCountsCache.AddWithExpiresInSecs(channelId, count, CHANNEL_MEMBERS_COUNTS_CACHE_SEC) 1286 } 1287 } 1288 }) 1289 } 1290 1291 func (s SqlChannelStore) RemoveMember(channelId string, userId string) store.StoreChannel { 1292 return store.Do(func(result *store.StoreResult) { 1293 _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE ChannelId = :ChannelId AND UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}) 1294 if err != nil { 1295 result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_channel.remove_member.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError) 1296 } 1297 }) 1298 } 1299 1300 func (s SqlChannelStore) PermanentDeleteMembersByUser(userId string) store.StoreChannel { 1301 return store.Do(func(result *store.StoreResult) { 1302 if _, err := s.GetMaster().Exec("DELETE FROM ChannelMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}); err != nil { 1303 result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_channel.permanent_delete_members_by_user.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError) 1304 } 1305 }) 1306 } 1307 1308 func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string) store.StoreChannel { 1309 return store.Do(func(result *store.StoreResult) { 1310 props := make(map[string]interface{}) 1311 1312 updateIdQuery := "" 1313 for index, channelId := range channelIds { 1314 if len(updateIdQuery) > 0 { 1315 updateIdQuery += " OR " 1316 } 1317 1318 props["channelId"+strconv.Itoa(index)] = channelId 1319 updateIdQuery += "ChannelId = :channelId" + strconv.Itoa(index) 1320 } 1321 1322 selectIdQuery := strings.Replace(updateIdQuery, "ChannelId", "Id", -1) 1323 1324 var lastPostAtTimes []struct { 1325 Id string 1326 LastPostAt int64 1327 TotalMsgCount int64 1328 } 1329 1330 selectQuery := "SELECT Id, LastPostAt, TotalMsgCount FROM Channels WHERE (" + selectIdQuery + ")" 1331 1332 if _, err := s.GetMaster().Select(&lastPostAtTimes, selectQuery, props); err != nil { 1333 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) 1334 return 1335 } 1336 1337 times := map[string]int64{} 1338 msgCountQuery := "" 1339 lastViewedQuery := "" 1340 for index, t := range lastPostAtTimes { 1341 times[t.Id] = t.LastPostAt 1342 1343 props["msgCount"+strconv.Itoa(index)] = t.TotalMsgCount 1344 msgCountQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(MsgCount, :msgCount%d) ", index, index) 1345 1346 props["lastViewed"+strconv.Itoa(index)] = t.LastPostAt 1347 lastViewedQuery += fmt.Sprintf("WHEN :channelId%d THEN GREATEST(LastViewedAt, :lastViewed%d) ", index, index) 1348 1349 props["channelId"+strconv.Itoa(index)] = t.Id 1350 } 1351 1352 var updateQuery string 1353 1354 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 1355 updateQuery = `UPDATE 1356 ChannelMembers 1357 SET 1358 MentionCount = 0, 1359 MsgCount = CAST(CASE ChannelId ` + msgCountQuery + ` END AS BIGINT), 1360 LastViewedAt = CAST(CASE ChannelId ` + lastViewedQuery + ` END AS BIGINT), 1361 LastUpdateAt = CAST(CASE ChannelId ` + lastViewedQuery + ` END AS BIGINT) 1362 WHERE 1363 UserId = :UserId 1364 AND (` + updateIdQuery + `)` 1365 } else if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 1366 updateQuery = `UPDATE 1367 ChannelMembers 1368 SET 1369 MentionCount = 0, 1370 MsgCount = CASE ChannelId ` + msgCountQuery + ` END, 1371 LastViewedAt = CASE ChannelId ` + lastViewedQuery + ` END, 1372 LastUpdateAt = CASE ChannelId ` + lastViewedQuery + ` END 1373 WHERE 1374 UserId = :UserId 1375 AND (` + updateIdQuery + `)` 1376 } 1377 1378 props["UserId"] = userId 1379 1380 if _, err := s.GetMaster().Exec(updateQuery, props); err != nil { 1381 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) 1382 } else { 1383 result.Data = times 1384 } 1385 }) 1386 } 1387 1388 func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string) store.StoreChannel { 1389 return store.Do(func(result *store.StoreResult) { 1390 _, err := s.GetMaster().Exec( 1391 `UPDATE 1392 ChannelMembers 1393 SET 1394 MentionCount = MentionCount + 1, 1395 LastUpdateAt = :LastUpdateAt 1396 WHERE 1397 UserId = :UserId 1398 AND ChannelId = :ChannelId`, 1399 map[string]interface{}{"ChannelId": channelId, "UserId": userId, "LastUpdateAt": model.GetMillis()}) 1400 if err != nil { 1401 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) 1402 } 1403 }) 1404 } 1405 1406 func (s SqlChannelStore) GetAll(teamId string) store.StoreChannel { 1407 return store.Do(func(result *store.StoreResult) { 1408 var data []*model.Channel 1409 _, err := s.GetReplica().Select(&data, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Type != 'D' ORDER BY Name", map[string]interface{}{"TeamId": teamId}) 1410 1411 if err != nil { 1412 result.Err = model.NewAppError("SqlChannelStore.GetAll", "store.sql_channel.get_all.app_error", nil, "teamId="+teamId+", err="+err.Error(), http.StatusInternalServerError) 1413 } else { 1414 result.Data = data 1415 } 1416 }) 1417 } 1418 1419 func (s SqlChannelStore) GetForPost(postId string) store.StoreChannel { 1420 return store.Do(func(result *store.StoreResult) { 1421 channel := &model.Channel{} 1422 if err := s.GetReplica().SelectOne( 1423 channel, 1424 `SELECT 1425 Channels.* 1426 FROM 1427 Channels, 1428 Posts 1429 WHERE 1430 Channels.Id = Posts.ChannelId 1431 AND Posts.Id = :PostId`, map[string]interface{}{"PostId": postId}); err != nil { 1432 result.Err = model.NewAppError("SqlChannelStore.GetForPost", "store.sql_channel.get_for_post.app_error", nil, "postId="+postId+", err="+err.Error(), http.StatusInternalServerError) 1433 } else { 1434 result.Data = channel 1435 } 1436 }) 1437 } 1438 1439 func (s SqlChannelStore) AnalyticsTypeCount(teamId string, channelType string) store.StoreChannel { 1440 return store.Do(func(result *store.StoreResult) { 1441 query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType" 1442 1443 if len(teamId) > 0 { 1444 query += " AND TeamId = :TeamId" 1445 } 1446 1447 v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId, "ChannelType": channelType}) 1448 if err != nil { 1449 result.Err = model.NewAppError("SqlChannelStore.AnalyticsTypeCount", "store.sql_channel.analytics_type_count.app_error", nil, err.Error(), http.StatusInternalServerError) 1450 } else { 1451 result.Data = v 1452 } 1453 }) 1454 } 1455 1456 func (s SqlChannelStore) AnalyticsDeletedTypeCount(teamId string, channelType string) store.StoreChannel { 1457 return store.Do(func(result *store.StoreResult) { 1458 query := "SELECT COUNT(Id) AS Value FROM Channels WHERE Type = :ChannelType AND DeleteAt > 0" 1459 1460 if len(teamId) > 0 { 1461 query += " AND TeamId = :TeamId" 1462 } 1463 1464 v, err := s.GetReplica().SelectInt(query, map[string]interface{}{"TeamId": teamId, "ChannelType": channelType}) 1465 if err != nil { 1466 result.Err = model.NewAppError("SqlChannelStore.AnalyticsDeletedTypeCount", "store.sql_channel.analytics_deleted_type_count.app_error", nil, err.Error(), http.StatusInternalServerError) 1467 } else { 1468 result.Data = v 1469 } 1470 }) 1471 } 1472 1473 func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) store.StoreChannel { 1474 return store.Do(func(result *store.StoreResult) { 1475 var dbMembers channelMemberWithSchemeRolesList 1476 _, err := s.GetReplica().Select(&dbMembers, CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE ChannelMembers.UserId = :UserId", map[string]interface{}{"TeamId": teamId, "UserId": userId}) 1477 1478 if err != nil { 1479 result.Err = model.NewAppError("SqlChannelStore.GetMembersForUser", "store.sql_channel.get_members.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error(), http.StatusInternalServerError) 1480 } else { 1481 result.Data = dbMembers.ToModel() 1482 } 1483 }) 1484 } 1485 1486 func (s SqlChannelStore) AutocompleteInTeam(teamId string, term string) store.StoreChannel { 1487 return store.Do(func(result *store.StoreResult) { 1488 queryFormat := ` 1489 SELECT 1490 * 1491 FROM 1492 Channels 1493 WHERE 1494 TeamId = :TeamId 1495 AND Type = 'O' 1496 AND DeleteAt = 0 1497 %v 1498 LIMIT 50` 1499 1500 var channels model.ChannelList 1501 1502 if likeClause, likeTerm := s.buildLIKEClause(term); likeClause == "" { 1503 if _, err := s.GetReplica().Select(&channels, fmt.Sprintf(queryFormat, ""), map[string]interface{}{"TeamId": teamId}); err != nil { 1504 result.Err = model.NewAppError("SqlChannelStore.AutocompleteInTeam", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 1505 } 1506 } else { 1507 // Using a UNION results in index_merge and fulltext queries and is much faster than the ref 1508 // query you would get using an OR of the LIKE and full-text clauses. 1509 fulltextClause, fulltextTerm := s.buildFulltextClause(term) 1510 likeQuery := fmt.Sprintf(queryFormat, "AND "+likeClause) 1511 fulltextQuery := fmt.Sprintf(queryFormat, "AND "+fulltextClause) 1512 query := fmt.Sprintf("(%v) UNION (%v) LIMIT 50", likeQuery, fulltextQuery) 1513 1514 if _, err := s.GetReplica().Select(&channels, query, map[string]interface{}{"TeamId": teamId, "LikeTerm": likeTerm, "FulltextTerm": fulltextTerm}); err != nil { 1515 result.Err = model.NewAppError("SqlChannelStore.AutocompleteInTeam", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 1516 } 1517 } 1518 1519 sort.Slice(channels, func(a, b int) bool { 1520 return strings.ToLower(channels[a].DisplayName) < strings.ToLower(channels[b].DisplayName) 1521 }) 1522 result.Data = &channels 1523 }) 1524 } 1525 1526 func (s SqlChannelStore) SearchInTeam(teamId string, term string) store.StoreChannel { 1527 return store.Do(func(result *store.StoreResult) { 1528 searchQuery := ` 1529 SELECT 1530 * 1531 FROM 1532 Channels 1533 WHERE 1534 TeamId = :TeamId 1535 AND Type = 'O' 1536 AND DeleteAt = 0 1537 SEARCH_CLAUSE 1538 ORDER BY DisplayName 1539 LIMIT 100` 1540 1541 *result = s.performSearch(searchQuery, term, map[string]interface{}{"TeamId": teamId}) 1542 }) 1543 } 1544 1545 func (s SqlChannelStore) SearchMore(userId string, teamId string, term string) store.StoreChannel { 1546 return store.Do(func(result *store.StoreResult) { 1547 searchQuery := ` 1548 SELECT 1549 * 1550 FROM 1551 Channels 1552 WHERE 1553 TeamId = :TeamId 1554 AND Type = 'O' 1555 AND DeleteAt = 0 1556 AND Id NOT IN (SELECT 1557 Channels.Id 1558 FROM 1559 Channels, 1560 ChannelMembers 1561 WHERE 1562 Id = ChannelId 1563 AND TeamId = :TeamId 1564 AND UserId = :UserId 1565 AND DeleteAt = 0) 1566 SEARCH_CLAUSE 1567 ORDER BY DisplayName 1568 LIMIT 100` 1569 1570 *result = s.performSearch(searchQuery, term, map[string]interface{}{"TeamId": teamId, "UserId": userId}) 1571 }) 1572 } 1573 1574 func (s SqlChannelStore) buildLIKEClause(term string) (likeClause, likeTerm string) { 1575 likeTerm = term 1576 searchColumns := "Name, DisplayName" 1577 1578 // These chars must be removed from the like query. 1579 for _, c := range ignoreLikeSearchChar { 1580 likeTerm = strings.Replace(likeTerm, c, "", -1) 1581 } 1582 1583 // These chars must be escaped in the like query. 1584 for _, c := range escapeLikeSearchChar { 1585 likeTerm = strings.Replace(likeTerm, c, "*"+c, -1) 1586 } 1587 1588 if likeTerm == "" { 1589 return 1590 } 1591 1592 // Prepare the LIKE portion of the query. 1593 var searchFields []string 1594 for _, field := range strings.Split(searchColumns, ", ") { 1595 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 1596 searchFields = append(searchFields, fmt.Sprintf("lower(%s) LIKE lower(%s) escape '*'", field, ":LikeTerm")) 1597 } else { 1598 searchFields = append(searchFields, fmt.Sprintf("%s LIKE %s escape '*'", field, ":LikeTerm")) 1599 } 1600 } 1601 1602 likeClause = fmt.Sprintf("(%s)", strings.Join(searchFields, " OR ")) 1603 likeTerm += "%" 1604 return 1605 } 1606 1607 func (s SqlChannelStore) buildFulltextClause(term string) (fulltextClause, fulltextTerm string) { 1608 // Copy the terms as we will need to prepare them differently for each search type. 1609 fulltextTerm = term 1610 1611 searchColumns := "Name, DisplayName" 1612 1613 // These chars must be treated as spaces in the fulltext query. 1614 for _, c := range spaceFulltextSearchChar { 1615 fulltextTerm = strings.Replace(fulltextTerm, c, " ", -1) 1616 } 1617 1618 // Prepare the FULLTEXT portion of the query. 1619 if s.DriverName() == model.DATABASE_DRIVER_POSTGRES { 1620 splitTerm := strings.Fields(fulltextTerm) 1621 for i, t := range strings.Fields(fulltextTerm) { 1622 if i == len(splitTerm)-1 { 1623 splitTerm[i] = t + ":*" 1624 } else { 1625 splitTerm[i] = t + ":* &" 1626 } 1627 } 1628 1629 fulltextTerm = strings.Join(splitTerm, " ") 1630 1631 fulltextClause = fmt.Sprintf("((%s) @@ to_tsquery(:FulltextTerm))", convertMySQLFullTextColumnsToPostgres(searchColumns)) 1632 } else if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 1633 splitTerm := strings.Fields(fulltextTerm) 1634 for i, t := range strings.Fields(fulltextTerm) { 1635 splitTerm[i] = "+" + t + "*" 1636 } 1637 1638 fulltextTerm = strings.Join(splitTerm, " ") 1639 1640 fulltextClause = fmt.Sprintf("MATCH(%s) AGAINST (:FulltextTerm IN BOOLEAN MODE)", searchColumns) 1641 } 1642 1643 return 1644 } 1645 1646 func (s SqlChannelStore) performSearch(searchQuery string, term string, parameters map[string]interface{}) store.StoreResult { 1647 result := store.StoreResult{} 1648 1649 likeClause, likeTerm := s.buildLIKEClause(term) 1650 if likeTerm == "" { 1651 // If the likeTerm is empty after preparing, then don't bother searching. 1652 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1) 1653 } else { 1654 parameters["LikeTerm"] = likeTerm 1655 fulltextClause, fulltextTerm := s.buildFulltextClause(term) 1656 parameters["FulltextTerm"] = fulltextTerm 1657 searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "AND ("+likeClause+" OR "+fulltextClause+")", 1) 1658 } 1659 1660 var channels model.ChannelList 1661 1662 if _, err := s.GetReplica().Select(&channels, searchQuery, parameters); err != nil { 1663 result.Err = model.NewAppError("SqlChannelStore.Search", "store.sql_channel.search.app_error", nil, "term="+term+", "+", "+err.Error(), http.StatusInternalServerError) 1664 } else { 1665 result.Data = &channels 1666 } 1667 1668 return result 1669 } 1670 1671 func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) store.StoreChannel { 1672 return store.Do(func(result *store.StoreResult) { 1673 var dbMembers channelMemberWithSchemeRolesList 1674 props := make(map[string]interface{}) 1675 idQuery := "" 1676 1677 for index, userId := range userIds { 1678 if len(idQuery) > 0 { 1679 idQuery += ", " 1680 } 1681 1682 props["userId"+strconv.Itoa(index)] = userId 1683 idQuery += ":userId" + strconv.Itoa(index) 1684 } 1685 1686 props["ChannelId"] = channelId 1687 1688 if _, err := s.GetReplica().Select(&dbMembers, CHANNEL_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId IN ("+idQuery+")", props); err != nil { 1689 result.Err = model.NewAppError("SqlChannelStore.GetMembersByIds", "store.sql_channel.get_members_by_ids.app_error", nil, "channelId="+channelId+" "+err.Error(), http.StatusInternalServerError) 1690 } else { 1691 result.Data = dbMembers.ToModel() 1692 } 1693 }) 1694 } 1695 1696 func (s SqlChannelStore) GetChannelsByScheme(schemeId string, offset int, limit int) store.StoreChannel { 1697 return store.Do(func(result *store.StoreResult) { 1698 var channels model.ChannelList 1699 _, 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}) 1700 if err != nil { 1701 result.Err = model.NewAppError("SqlChannelStore.GetChannelsByScheme", "store.sql_channel.get_by_scheme.app_error", nil, "schemeId="+schemeId+" "+err.Error(), http.StatusInternalServerError) 1702 } else { 1703 result.Data = channels 1704 } 1705 }) 1706 } 1707 1708 // This function does the Advanced Permissions Phase 2 migration for ChannelMember objects. It performs the migration 1709 // in batches as a single transaction per batch to ensure consistency but to also minimise execution time to avoid 1710 // causing unnecessary table locks. **THIS FUNCTION SHOULD NOT BE USED FOR ANY OTHER PURPOSE.** Executing this function 1711 // *after* the new Schemes functionality has been used on an installation will have unintended consequences. 1712 func (s SqlChannelStore) MigrateChannelMembers(fromChannelId string, fromUserId string) store.StoreChannel { 1713 return store.Do(func(result *store.StoreResult) { 1714 var transaction *gorp.Transaction 1715 var err error 1716 1717 if transaction, err = s.GetMaster().Begin(); err != nil { 1718 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 1719 return 1720 } 1721 1722 var channelMembers []channelMember 1723 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 { 1724 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.select.app_error", nil, err.Error(), http.StatusInternalServerError) 1725 return 1726 } 1727 1728 if len(channelMembers) == 0 { 1729 // No more channel members in query result means that the migration has finished. 1730 return 1731 } 1732 1733 for _, member := range channelMembers { 1734 roles := strings.Fields(member.Roles) 1735 var newRoles []string 1736 member.SchemeAdmin = sql.NullBool{Bool: false, Valid: true} 1737 member.SchemeUser = sql.NullBool{Bool: false, Valid: true} 1738 for _, role := range roles { 1739 if role == model.CHANNEL_ADMIN_ROLE_ID { 1740 member.SchemeAdmin = sql.NullBool{Bool: true, Valid: true} 1741 } else if role == model.CHANNEL_USER_ROLE_ID { 1742 member.SchemeUser = sql.NullBool{Bool: true, Valid: true} 1743 } else { 1744 newRoles = append(newRoles, role) 1745 } 1746 } 1747 member.Roles = strings.Join(newRoles, " ") 1748 1749 if _, err := transaction.Update(&member); err != nil { 1750 if err2 := transaction.Rollback(); err2 != nil { 1751 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError) 1752 return 1753 } 1754 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.update.app_error", nil, err.Error(), http.StatusInternalServerError) 1755 return 1756 } 1757 1758 } 1759 1760 if err := transaction.Commit(); err != nil { 1761 if err2 := transaction.Rollback(); err2 != nil { 1762 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError) 1763 return 1764 } 1765 result.Err = model.NewAppError("SqlChannelStore.MigrateChannelMembers", "store.sql_channel.migrate_channel_members.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError) 1766 return 1767 } 1768 1769 data := make(map[string]string) 1770 data["ChannelId"] = channelMembers[len(channelMembers)-1].ChannelId 1771 data["UserId"] = channelMembers[len(channelMembers)-1].UserId 1772 result.Data = data 1773 }) 1774 } 1775 1776 func (s SqlChannelStore) ResetAllChannelSchemes() store.StoreChannel { 1777 return store.Do(func(result *store.StoreResult) { 1778 if _, err := s.GetMaster().Exec("UPDATE Channels SET SchemeId=''"); err != nil { 1779 result.Err = model.NewAppError("SqlChannelStore.ResetAllChannelSchemes", "store.sql_channel.reset_all_channel_schemes.app_error", nil, err.Error(), http.StatusInternalServerError) 1780 } 1781 }) 1782 }