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  }