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