github.com/lologarithm/mattermost-server@v5.3.2-0.20181002060438-c82a84ed765b+incompatible/store/sqlstore/channel_store.go (about)

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