github.com/crspeller/mattermost-server@v0.0.0-20190328001957-a200beb3d111/store/sqlstore/team_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  	"net/http"
     9  	"strconv"
    10  	"strings"
    11  
    12  	"github.com/mattermost/gorp"
    13  	"github.com/crspeller/mattermost-server/model"
    14  	"github.com/crspeller/mattermost-server/store"
    15  )
    16  
    17  const (
    18  	TEAM_MEMBER_EXISTS_ERROR = "store.sql_team.save_member.exists.app_error"
    19  )
    20  
    21  type SqlTeamStore struct {
    22  	SqlStore
    23  }
    24  
    25  type teamMember struct {
    26  	TeamId      string
    27  	UserId      string
    28  	Roles       string
    29  	DeleteAt    int64
    30  	SchemeUser  sql.NullBool
    31  	SchemeAdmin sql.NullBool
    32  }
    33  
    34  func NewTeamMemberFromModel(tm *model.TeamMember) *teamMember {
    35  	return &teamMember{
    36  		TeamId:      tm.TeamId,
    37  		UserId:      tm.UserId,
    38  		Roles:       tm.ExplicitRoles,
    39  		DeleteAt:    tm.DeleteAt,
    40  		SchemeUser:  sql.NullBool{Valid: true, Bool: tm.SchemeUser},
    41  		SchemeAdmin: sql.NullBool{Valid: true, Bool: tm.SchemeAdmin},
    42  	}
    43  }
    44  
    45  type teamMemberWithSchemeRoles struct {
    46  	TeamId                     string
    47  	UserId                     string
    48  	Roles                      string
    49  	DeleteAt                   int64
    50  	SchemeUser                 sql.NullBool
    51  	SchemeAdmin                sql.NullBool
    52  	TeamSchemeDefaultUserRole  sql.NullString
    53  	TeamSchemeDefaultAdminRole sql.NullString
    54  }
    55  
    56  type teamMemberWithSchemeRolesList []teamMemberWithSchemeRoles
    57  
    58  func (db teamMemberWithSchemeRoles) ToModel() *model.TeamMember {
    59  	var roles []string
    60  	var explicitRoles []string
    61  
    62  	// Identify any scheme derived roles that are in "Roles" field due to not yet being migrated, and exclude
    63  	// them from ExplicitRoles field.
    64  	schemeUser := db.SchemeUser.Valid && db.SchemeUser.Bool
    65  	schemeAdmin := db.SchemeAdmin.Valid && db.SchemeAdmin.Bool
    66  	for _, role := range strings.Fields(db.Roles) {
    67  		isImplicit := false
    68  		if role == model.TEAM_USER_ROLE_ID {
    69  			// We have an implicit role via the system scheme. Override the "schemeUser" field to true.
    70  			schemeUser = true
    71  			isImplicit = true
    72  		} else if role == model.TEAM_ADMIN_ROLE_ID {
    73  			// We have an implicit role via the system scheme.
    74  			schemeAdmin = true
    75  			isImplicit = true
    76  		}
    77  
    78  		if !isImplicit {
    79  			explicitRoles = append(explicitRoles, role)
    80  		}
    81  		roles = append(roles, role)
    82  	}
    83  
    84  	// Add any scheme derived roles that are not in the Roles field due to being Implicit from the Scheme, and add
    85  	// them to the Roles field for backwards compatibility reasons.
    86  	var schemeImpliedRoles []string
    87  	if db.SchemeUser.Valid && db.SchemeUser.Bool {
    88  		if db.TeamSchemeDefaultUserRole.Valid && db.TeamSchemeDefaultUserRole.String != "" {
    89  			schemeImpliedRoles = append(schemeImpliedRoles, db.TeamSchemeDefaultUserRole.String)
    90  		} else {
    91  			schemeImpliedRoles = append(schemeImpliedRoles, model.TEAM_USER_ROLE_ID)
    92  		}
    93  	}
    94  	if db.SchemeAdmin.Valid && db.SchemeAdmin.Bool {
    95  		if db.TeamSchemeDefaultAdminRole.Valid && db.TeamSchemeDefaultAdminRole.String != "" {
    96  			schemeImpliedRoles = append(schemeImpliedRoles, db.TeamSchemeDefaultAdminRole.String)
    97  		} else {
    98  			schemeImpliedRoles = append(schemeImpliedRoles, model.TEAM_ADMIN_ROLE_ID)
    99  		}
   100  	}
   101  	for _, impliedRole := range schemeImpliedRoles {
   102  		alreadyThere := false
   103  		for _, role := range roles {
   104  			if role == impliedRole {
   105  				alreadyThere = true
   106  			}
   107  		}
   108  		if !alreadyThere {
   109  			roles = append(roles, impliedRole)
   110  		}
   111  	}
   112  
   113  	tm := &model.TeamMember{
   114  		TeamId:        db.TeamId,
   115  		UserId:        db.UserId,
   116  		Roles:         strings.Join(roles, " "),
   117  		DeleteAt:      db.DeleteAt,
   118  		SchemeUser:    schemeUser,
   119  		SchemeAdmin:   schemeAdmin,
   120  		ExplicitRoles: strings.Join(explicitRoles, " "),
   121  	}
   122  	return tm
   123  }
   124  
   125  func (db teamMemberWithSchemeRolesList) ToModel() []*model.TeamMember {
   126  	tms := make([]*model.TeamMember, 0)
   127  
   128  	for _, tm := range db {
   129  		tms = append(tms, tm.ToModel())
   130  	}
   131  
   132  	return tms
   133  }
   134  
   135  func NewSqlTeamStore(sqlStore SqlStore) store.TeamStore {
   136  	s := &SqlTeamStore{sqlStore}
   137  
   138  	for _, db := range sqlStore.GetAllConns() {
   139  		table := db.AddTableWithName(model.Team{}, "Teams").SetKeys(false, "Id")
   140  		table.ColMap("Id").SetMaxSize(26)
   141  		table.ColMap("DisplayName").SetMaxSize(64)
   142  		table.ColMap("Name").SetMaxSize(64).SetUnique(true)
   143  		table.ColMap("Description").SetMaxSize(255)
   144  		table.ColMap("Email").SetMaxSize(128)
   145  		table.ColMap("CompanyName").SetMaxSize(64)
   146  		table.ColMap("AllowedDomains").SetMaxSize(500)
   147  		table.ColMap("InviteId").SetMaxSize(32)
   148  
   149  		tablem := db.AddTableWithName(teamMember{}, "TeamMembers").SetKeys(false, "TeamId", "UserId")
   150  		tablem.ColMap("TeamId").SetMaxSize(26)
   151  		tablem.ColMap("UserId").SetMaxSize(26)
   152  		tablem.ColMap("Roles").SetMaxSize(64)
   153  	}
   154  
   155  	return s
   156  }
   157  
   158  func (s SqlTeamStore) CreateIndexesIfNotExists() {
   159  	s.CreateIndexIfNotExists("idx_teams_name", "Teams", "Name")
   160  	s.RemoveIndexIfExists("idx_teams_description", "Teams")
   161  	s.CreateIndexIfNotExists("idx_teams_invite_id", "Teams", "InviteId")
   162  	s.CreateIndexIfNotExists("idx_teams_update_at", "Teams", "UpdateAt")
   163  	s.CreateIndexIfNotExists("idx_teams_create_at", "Teams", "CreateAt")
   164  	s.CreateIndexIfNotExists("idx_teams_delete_at", "Teams", "DeleteAt")
   165  
   166  	s.CreateIndexIfNotExists("idx_teammembers_team_id", "TeamMembers", "TeamId")
   167  	s.CreateIndexIfNotExists("idx_teammembers_user_id", "TeamMembers", "UserId")
   168  	s.CreateIndexIfNotExists("idx_teammembers_delete_at", "TeamMembers", "DeleteAt")
   169  }
   170  
   171  func (s SqlTeamStore) Save(team *model.Team) store.StoreChannel {
   172  	return store.Do(func(result *store.StoreResult) {
   173  		if len(team.Id) > 0 {
   174  			result.Err = model.NewAppError("SqlTeamStore.Save",
   175  				"store.sql_team.save.existing.app_error", nil, "id="+team.Id, http.StatusBadRequest)
   176  			return
   177  		}
   178  
   179  		team.PreSave()
   180  
   181  		if result.Err = team.IsValid(); result.Err != nil {
   182  			return
   183  		}
   184  
   185  		if err := s.GetMaster().Insert(team); err != nil {
   186  			if IsUniqueConstraintError(err, []string{"Name", "teams_name_key"}) {
   187  				result.Err = model.NewAppError("SqlTeamStore.Save", "store.sql_team.save.domain_exists.app_error", nil, "id="+team.Id+", "+err.Error(), http.StatusBadRequest)
   188  				return
   189  			}
   190  			result.Err = model.NewAppError("SqlTeamStore.Save", "store.sql_team.save.app_error", nil, "id="+team.Id+", "+err.Error(), http.StatusInternalServerError)
   191  			return
   192  		}
   193  		result.Data = team
   194  	})
   195  }
   196  
   197  func (s SqlTeamStore) Update(team *model.Team) store.StoreChannel {
   198  	return store.Do(func(result *store.StoreResult) {
   199  		team.PreUpdate()
   200  
   201  		if result.Err = team.IsValid(); result.Err != nil {
   202  			return
   203  		}
   204  
   205  		oldResult, err := s.GetMaster().Get(model.Team{}, team.Id)
   206  		if err != nil {
   207  			result.Err = model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.finding.app_error", nil, "id="+team.Id+", "+err.Error(), http.StatusInternalServerError)
   208  			return
   209  		}
   210  
   211  		if oldResult == nil {
   212  			result.Err = model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.find.app_error", nil, "id="+team.Id, http.StatusBadRequest)
   213  			return
   214  		}
   215  
   216  		oldTeam := oldResult.(*model.Team)
   217  		team.CreateAt = oldTeam.CreateAt
   218  		team.UpdateAt = model.GetMillis()
   219  
   220  		count, err := s.GetMaster().Update(team)
   221  		if err != nil {
   222  			result.Err = model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.updating.app_error", nil, "id="+team.Id+", "+err.Error(), http.StatusInternalServerError)
   223  			return
   224  		}
   225  		if count != 1 {
   226  			result.Err = model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.app_error", nil, "id="+team.Id, http.StatusInternalServerError)
   227  			return
   228  		}
   229  
   230  		result.Data = team
   231  	})
   232  }
   233  
   234  func (s SqlTeamStore) UpdateDisplayName(name string, teamId string) store.StoreChannel {
   235  	return store.Do(func(result *store.StoreResult) {
   236  		if _, err := s.GetMaster().Exec("UPDATE Teams SET DisplayName = :Name WHERE Id = :Id", map[string]interface{}{"Name": name, "Id": teamId}); err != nil {
   237  			result.Err = model.NewAppError("SqlTeamStore.UpdateName", "store.sql_team.update_display_name.app_error", nil, "team_id="+teamId, http.StatusInternalServerError)
   238  			return
   239  		}
   240  
   241  		result.Data = teamId
   242  	})
   243  }
   244  
   245  func (s SqlTeamStore) Get(id string) store.StoreChannel {
   246  	return store.Do(func(result *store.StoreResult) {
   247  		obj, err := s.GetReplica().Get(model.Team{}, id)
   248  		if err != nil {
   249  			result.Err = model.NewAppError("SqlTeamStore.Get", "store.sql_team.get.finding.app_error", nil, "id="+id+", "+err.Error(), http.StatusInternalServerError)
   250  			return
   251  		}
   252  		if obj == nil {
   253  			result.Err = model.NewAppError("SqlTeamStore.Get", "store.sql_team.get.find.app_error", nil, "id="+id, http.StatusNotFound)
   254  			return
   255  		}
   256  
   257  		team := obj.(*model.Team)
   258  		if len(team.InviteId) == 0 {
   259  			team.InviteId = team.Id
   260  		}
   261  
   262  		result.Data = team
   263  	})
   264  }
   265  
   266  func (s SqlTeamStore) GetByInviteId(inviteId string) store.StoreChannel {
   267  	return store.Do(func(result *store.StoreResult) {
   268  		team := model.Team{}
   269  
   270  		if err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE Id = :InviteId OR InviteId = :InviteId", map[string]interface{}{"InviteId": inviteId}); err != nil {
   271  			result.Err = model.NewAppError("SqlTeamStore.GetByInviteId", "store.sql_team.get_by_invite_id.finding.app_error", nil, "inviteId="+inviteId+", "+err.Error(), http.StatusNotFound)
   272  			return
   273  		}
   274  
   275  		if len(team.InviteId) == 0 {
   276  			team.InviteId = team.Id
   277  		}
   278  
   279  		if len(inviteId) == 0 || team.InviteId != inviteId {
   280  			result.Err = model.NewAppError("SqlTeamStore.GetByInviteId", "store.sql_team.get_by_invite_id.find.app_error", nil, "inviteId="+inviteId, http.StatusNotFound)
   281  			return
   282  		}
   283  
   284  		result.Data = &team
   285  	})
   286  }
   287  
   288  func (s SqlTeamStore) GetByName(name string) store.StoreChannel {
   289  	return store.Do(func(result *store.StoreResult) {
   290  		team := model.Team{}
   291  
   292  		if err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE Name = :Name", map[string]interface{}{"Name": name}); err != nil {
   293  			result.Err = model.NewAppError("SqlTeamStore.GetByName", "store.sql_team.get_by_name.app_error", nil, "name="+name+", "+err.Error(), http.StatusInternalServerError)
   294  			return
   295  		}
   296  
   297  		if len(team.InviteId) == 0 {
   298  			team.InviteId = team.Id
   299  		}
   300  
   301  		result.Data = &team
   302  	})
   303  }
   304  
   305  func (s SqlTeamStore) SearchByName(name string) store.StoreChannel {
   306  	return store.Do(func(result *store.StoreResult) {
   307  		var teams []*model.Team
   308  
   309  		if _, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE Name LIKE :Name", map[string]interface{}{"Name": name + "%"}); err != nil {
   310  			result.Err = model.NewAppError("SqlTeamStore.SearchByName", "store.sql_team.get_by_name.app_error", nil, "name="+name+", "+err.Error(), http.StatusInternalServerError)
   311  			return
   312  		}
   313  
   314  		result.Data = teams
   315  	})
   316  }
   317  
   318  func (s SqlTeamStore) SearchAll(term string) store.StoreChannel {
   319  	return store.Do(func(result *store.StoreResult) {
   320  		var teams []*model.Team
   321  
   322  		if _, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE Name LIKE :Term OR DisplayName LIKE :Term", map[string]interface{}{"Term": term + "%"}); err != nil {
   323  			result.Err = model.NewAppError("SqlTeamStore.SearchAll", "store.sql_team.search_all_team.app_error", nil, "term="+term+", "+err.Error(), http.StatusInternalServerError)
   324  			return
   325  		}
   326  
   327  		result.Data = teams
   328  	})
   329  }
   330  
   331  func (s SqlTeamStore) SearchOpen(term string) store.StoreChannel {
   332  	return store.Do(func(result *store.StoreResult) {
   333  		var teams []*model.Team
   334  
   335  		if _, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE Type = 'O' AND AllowOpenInvite = true AND (Name LIKE :Term OR DisplayName LIKE :Term)", map[string]interface{}{"Term": term + "%"}); err != nil {
   336  			result.Err = model.NewAppError("SqlTeamStore.SearchOpen", "store.sql_team.search_open_team.app_error", nil, "term="+term+", "+err.Error(), http.StatusInternalServerError)
   337  			return
   338  		}
   339  
   340  		result.Data = teams
   341  	})
   342  }
   343  
   344  func (s SqlTeamStore) SearchPrivate(term string) store.StoreChannel {
   345  	return store.Do(func(result *store.StoreResult) {
   346  		var teams []*model.Team
   347  
   348  		if _, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE (Type != 'O' OR AllowOpenInvite = false) AND (Name LIKE :Term OR DisplayName LIKE :Term)", map[string]interface{}{"Term": term + "%"}); err != nil {
   349  			result.Err = model.NewAppError("SqlTeamStore.SearchPrivate", "store.sql_team.search_private_team.app_error", nil, "term="+term+", "+err.Error(), http.StatusInternalServerError)
   350  			return
   351  		}
   352  
   353  		result.Data = teams
   354  	})
   355  }
   356  
   357  func (s SqlTeamStore) GetAll() store.StoreChannel {
   358  	return store.Do(func(result *store.StoreResult) {
   359  		var data []*model.Team
   360  		if _, err := s.GetReplica().Select(&data, "SELECT * FROM Teams ORDER BY DisplayName"); err != nil {
   361  			result.Err = model.NewAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
   362  			return
   363  		}
   364  
   365  		for _, team := range data {
   366  			if len(team.InviteId) == 0 {
   367  				team.InviteId = team.Id
   368  			}
   369  		}
   370  
   371  		result.Data = data
   372  	})
   373  }
   374  
   375  func (s SqlTeamStore) GetAllPage(offset int, limit int) store.StoreChannel {
   376  	return store.Do(func(result *store.StoreResult) {
   377  		var data []*model.Team
   378  		if _, err := s.GetReplica().Select(&data, "SELECT * FROM Teams ORDER BY DisplayName LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
   379  			result.Err = model.NewAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
   380  			return
   381  		}
   382  
   383  		for _, team := range data {
   384  			if len(team.InviteId) == 0 {
   385  				team.InviteId = team.Id
   386  			}
   387  		}
   388  
   389  		result.Data = data
   390  	})
   391  }
   392  
   393  func (s SqlTeamStore) GetTeamsByUserId(userId string) store.StoreChannel {
   394  	return store.Do(func(result *store.StoreResult) {
   395  		var data []*model.Team
   396  		if _, err := s.GetReplica().Select(&data, "SELECT Teams.* FROM Teams, TeamMembers WHERE TeamMembers.TeamId = Teams.Id AND TeamMembers.UserId = :UserId AND TeamMembers.DeleteAt = 0 AND Teams.DeleteAt = 0", map[string]interface{}{"UserId": userId}); err != nil {
   397  			result.Err = model.NewAppError("SqlTeamStore.GetTeamsByUserId", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
   398  			return
   399  		}
   400  
   401  		for _, team := range data {
   402  			if len(team.InviteId) == 0 {
   403  				team.InviteId = team.Id
   404  			}
   405  		}
   406  
   407  		result.Data = data
   408  	})
   409  }
   410  
   411  func (s SqlTeamStore) GetAllPrivateTeamListing() store.StoreChannel {
   412  	return store.Do(func(result *store.StoreResult) {
   413  		query := "SELECT * FROM Teams WHERE AllowOpenInvite = 0 ORDER BY DisplayName"
   414  
   415  		if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   416  			query = "SELECT * FROM Teams WHERE AllowOpenInvite = false ORDER BY DisplayName"
   417  		}
   418  
   419  		var data []*model.Team
   420  		if _, err := s.GetReplica().Select(&data, query); err != nil {
   421  			result.Err = model.NewAppError("SqlTeamStore.GetAllPrivateTeamListing", "store.sql_team.get_all_private_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
   422  			return
   423  		}
   424  
   425  		for _, team := range data {
   426  			if len(team.InviteId) == 0 {
   427  				team.InviteId = team.Id
   428  			}
   429  		}
   430  
   431  		result.Data = data
   432  	})
   433  }
   434  
   435  func (s SqlTeamStore) GetAllPrivateTeamPageListing(offset int, limit int) store.StoreChannel {
   436  	return store.Do(func(result *store.StoreResult) {
   437  		query := "SELECT * FROM Teams WHERE AllowOpenInvite = 0 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
   438  
   439  		if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   440  			query = "SELECT * FROM Teams WHERE AllowOpenInvite = false ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
   441  		}
   442  
   443  		var data []*model.Team
   444  		if _, err := s.GetReplica().Select(&data, query, map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
   445  			result.Err = model.NewAppError("SqlTeamStore.GetAllPrivateTeamListing", "store.sql_team.get_all_private_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
   446  			return
   447  		}
   448  
   449  		for _, team := range data {
   450  			if len(team.InviteId) == 0 {
   451  				team.InviteId = team.Id
   452  			}
   453  		}
   454  
   455  		result.Data = data
   456  	})
   457  }
   458  
   459  func (s SqlTeamStore) GetAllTeamListing() store.StoreChannel {
   460  	return store.Do(func(result *store.StoreResult) {
   461  		query := "SELECT * FROM Teams WHERE AllowOpenInvite = 1 ORDER BY DisplayName"
   462  
   463  		if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   464  			query = "SELECT * FROM Teams WHERE AllowOpenInvite = true ORDER BY DisplayName"
   465  		}
   466  
   467  		var data []*model.Team
   468  		if _, err := s.GetReplica().Select(&data, query); err != nil {
   469  			result.Err = model.NewAppError("SqlTeamStore.GetAllTeamListing", "store.sql_team.get_all_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
   470  			return
   471  		}
   472  
   473  		for _, team := range data {
   474  			if len(team.InviteId) == 0 {
   475  				team.InviteId = team.Id
   476  			}
   477  		}
   478  
   479  		result.Data = data
   480  	})
   481  }
   482  
   483  func (s SqlTeamStore) GetAllTeamPageListing(offset int, limit int) store.StoreChannel {
   484  	return store.Do(func(result *store.StoreResult) {
   485  		query := "SELECT * FROM Teams WHERE AllowOpenInvite = 1 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
   486  
   487  		if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   488  			query = "SELECT * FROM Teams WHERE AllowOpenInvite = true ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
   489  		}
   490  
   491  		var data []*model.Team
   492  		if _, err := s.GetReplica().Select(&data, query, map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
   493  			result.Err = model.NewAppError("SqlTeamStore.GetAllTeamListing", "store.sql_team.get_all_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
   494  			return
   495  		}
   496  
   497  		for _, team := range data {
   498  			if len(team.InviteId) == 0 {
   499  				team.InviteId = team.Id
   500  			}
   501  		}
   502  
   503  		result.Data = data
   504  	})
   505  }
   506  
   507  func (s SqlTeamStore) PermanentDelete(teamId string) store.StoreChannel {
   508  	return store.Do(func(result *store.StoreResult) {
   509  		if _, err := s.GetMaster().Exec("DELETE FROM Teams WHERE Id = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil {
   510  			result.Err = model.NewAppError("SqlTeamStore.Delete", "store.sql_team.permanent_delete.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError)
   511  			return
   512  		}
   513  	})
   514  }
   515  
   516  func (s SqlTeamStore) AnalyticsTeamCount() store.StoreChannel {
   517  	return store.Do(func(result *store.StoreResult) {
   518  		c, err := s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0", map[string]interface{}{})
   519  		if err != nil {
   520  			result.Err = model.NewAppError("SqlTeamStore.AnalyticsTeamCount", "store.sql_team.analytics_team_count.app_error", nil, err.Error(), http.StatusInternalServerError)
   521  			return
   522  		}
   523  		result.Data = c
   524  	})
   525  }
   526  
   527  var TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY = `
   528  	SELECT
   529  		TeamMembers.*,
   530  		TeamScheme.DefaultTeamUserRole TeamSchemeDefaultUserRole,
   531  		TeamScheme.DefaultTeamAdminRole TeamSchemeDefaultAdminRole
   532  	FROM
   533  		TeamMembers
   534  	LEFT JOIN
   535  		Teams ON TeamMembers.TeamId = Teams.Id
   536  	LEFT JOIN
   537  		Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id
   538  `
   539  
   540  func (s SqlTeamStore) SaveMember(member *model.TeamMember, maxUsersPerTeam int) store.StoreChannel {
   541  	return store.Do(func(result *store.StoreResult) {
   542  		if result.Err = member.IsValid(); result.Err != nil {
   543  			return
   544  		}
   545  
   546  		dbMember := NewTeamMemberFromModel(member)
   547  
   548  		if maxUsersPerTeam >= 0 {
   549  			count, err := s.GetMaster().SelectInt(
   550  				`SELECT
   551  					COUNT(0)
   552  				FROM
   553  					TeamMembers
   554  				INNER JOIN
   555  					Users
   556  				ON
   557  					TeamMembers.UserId = Users.Id
   558  				WHERE
   559  					TeamId = :TeamId
   560  					AND TeamMembers.DeleteAt = 0
   561  					AND Users.DeleteAt = 0`, map[string]interface{}{"TeamId": member.TeamId})
   562  
   563  			if err != nil {
   564  				result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, "teamId="+member.TeamId+", "+err.Error(), http.StatusInternalServerError)
   565  				return
   566  			}
   567  
   568  			if count >= int64(maxUsersPerTeam) {
   569  				result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.max_accounts.app_error", nil, "teamId="+member.TeamId, http.StatusBadRequest)
   570  				return
   571  			}
   572  		}
   573  
   574  		if err := s.GetMaster().Insert(dbMember); err != nil {
   575  			if IsUniqueConstraintError(err, []string{"TeamId", "teammembers_pkey", "PRIMARY"}) {
   576  				result.Err = model.NewAppError("SqlTeamStore.SaveMember", TEAM_MEMBER_EXISTS_ERROR, nil, "team_id="+member.TeamId+", user_id="+member.UserId+", "+err.Error(), http.StatusBadRequest)
   577  				return
   578  			}
   579  			result.Err = model.NewAppError("SqlTeamStore.SaveMember", "store.sql_team.save_member.save.app_error", nil, "team_id="+member.TeamId+", user_id="+member.UserId+", "+err.Error(), http.StatusInternalServerError)
   580  			return
   581  		}
   582  
   583  		var retrievedMember teamMemberWithSchemeRoles
   584  		if err := s.GetMaster().SelectOne(&retrievedMember, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.TeamId = :TeamId AND TeamMembers.UserId = :UserId", map[string]interface{}{"TeamId": dbMember.TeamId, "UserId": dbMember.UserId}); err != nil {
   585  			if err == sql.ErrNoRows {
   586  				result.Err = model.NewAppError("SqlTeamStore.SaveMember", "store.sql_team.get_member.missing.app_error", nil, "team_id="+dbMember.TeamId+"user_id="+dbMember.UserId+","+err.Error(), http.StatusNotFound)
   587  				return
   588  			}
   589  			result.Err = model.NewAppError("SqlTeamStore.SaveMember", "store.sql_team.get_member.app_error", nil, "team_id="+dbMember.TeamId+"user_id="+dbMember.UserId+","+err.Error(), http.StatusInternalServerError)
   590  			return
   591  		}
   592  		result.Data = retrievedMember.ToModel()
   593  	})
   594  }
   595  
   596  func (s SqlTeamStore) UpdateMember(member *model.TeamMember) store.StoreChannel {
   597  	return store.Do(func(result *store.StoreResult) {
   598  		member.PreUpdate()
   599  
   600  		if result.Err = member.IsValid(); result.Err != nil {
   601  			return
   602  		}
   603  
   604  		if _, err := s.GetMaster().Update(NewTeamMemberFromModel(member)); err != nil {
   605  			result.Err = model.NewAppError("SqlTeamStore.UpdateMember", "store.sql_team.save_member.save.app_error", nil, err.Error(), http.StatusInternalServerError)
   606  			return
   607  		}
   608  
   609  		var retrievedMember teamMemberWithSchemeRoles
   610  		if err := s.GetMaster().SelectOne(&retrievedMember, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.TeamId = :TeamId AND TeamMembers.UserId = :UserId", map[string]interface{}{"TeamId": member.TeamId, "UserId": member.UserId}); err != nil {
   611  			if err == sql.ErrNoRows {
   612  				result.Err = model.NewAppError("SqlTeamStore.UpdateMember", "store.sql_team.get_member.missing.app_error", nil, "team_id="+member.TeamId+"user_id="+member.UserId+","+err.Error(), http.StatusNotFound)
   613  				return
   614  			}
   615  			result.Err = model.NewAppError("SqlTeamStore.UpdateMember", "store.sql_team.get_member.app_error", nil, "team_id="+member.TeamId+"user_id="+member.UserId+","+err.Error(), http.StatusInternalServerError)
   616  			return
   617  		}
   618  
   619  		result.Data = retrievedMember.ToModel()
   620  	})
   621  }
   622  
   623  func (s SqlTeamStore) GetMember(teamId string, userId string) store.StoreChannel {
   624  	return store.Do(func(result *store.StoreResult) {
   625  		var dbMember teamMemberWithSchemeRoles
   626  		err := s.GetReplica().SelectOne(&dbMember, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.TeamId = :TeamId AND TeamMembers.UserId = :UserId", map[string]interface{}{"TeamId": teamId, "UserId": userId})
   627  		if err != nil {
   628  			if err == sql.ErrNoRows {
   629  				result.Err = model.NewAppError("SqlTeamStore.GetMember", "store.sql_team.get_member.missing.app_error", nil, "teamId="+teamId+" userId="+userId+" "+err.Error(), http.StatusNotFound)
   630  				return
   631  			}
   632  			result.Err = model.NewAppError("SqlTeamStore.GetMember", "store.sql_team.get_member.app_error", nil, "teamId="+teamId+" userId="+userId+" "+err.Error(), http.StatusInternalServerError)
   633  			return
   634  		}
   635  		result.Data = dbMember.ToModel()
   636  	})
   637  }
   638  
   639  func (s SqlTeamStore) GetMembers(teamId string, offset int, limit int) store.StoreChannel {
   640  	return store.Do(func(result *store.StoreResult) {
   641  		var dbMembers teamMemberWithSchemeRolesList
   642  		_, err := s.GetReplica().Select(&dbMembers, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.TeamId = :TeamId AND TeamMembers.DeleteAt = 0 LIMIT :Limit OFFSET :Offset", map[string]interface{}{"TeamId": teamId, "Limit": limit, "Offset": offset})
   643  		if err != nil {
   644  			result.Err = model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
   645  			return
   646  		}
   647  
   648  		result.Data = dbMembers.ToModel()
   649  	})
   650  }
   651  
   652  func (s SqlTeamStore) GetTotalMemberCount(teamId string) store.StoreChannel {
   653  	return store.Do(func(result *store.StoreResult) {
   654  		count, err := s.GetReplica().SelectInt(`
   655  			SELECT
   656  				count(*)
   657  			FROM
   658  				TeamMembers,
   659  				Users
   660  			WHERE
   661  				TeamMembers.UserId = Users.Id
   662  				AND TeamMembers.TeamId = :TeamId
   663  				AND TeamMembers.DeleteAt = 0`, map[string]interface{}{"TeamId": teamId})
   664  		if err != nil {
   665  			result.Err = model.NewAppError("SqlTeamStore.GetTotalMemberCount", "store.sql_team.get_member_count.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
   666  			return
   667  		}
   668  
   669  		result.Data = count
   670  	})
   671  }
   672  
   673  func (s SqlTeamStore) GetActiveMemberCount(teamId string) store.StoreChannel {
   674  	return store.Do(func(result *store.StoreResult) {
   675  		count, err := s.GetReplica().SelectInt(`
   676  			SELECT
   677  				count(*)
   678  			FROM
   679  				TeamMembers,
   680  				Users
   681  			WHERE
   682  				TeamMembers.UserId = Users.Id
   683  				AND TeamMembers.TeamId = :TeamId
   684  				AND TeamMembers.DeleteAt = 0
   685  				AND Users.DeleteAt = 0`, map[string]interface{}{"TeamId": teamId})
   686  		if err != nil {
   687  			result.Err = model.NewAppError("SqlTeamStore.GetActiveMemberCount", "store.sql_team.get_member_count.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
   688  			return
   689  		}
   690  
   691  		result.Data = count
   692  	})
   693  }
   694  
   695  func (s SqlTeamStore) GetMembersByIds(teamId string, userIds []string) store.StoreChannel {
   696  	return store.Do(func(result *store.StoreResult) {
   697  		var dbMembers teamMemberWithSchemeRolesList
   698  		props := make(map[string]interface{})
   699  		idQuery := ""
   700  
   701  		for index, userId := range userIds {
   702  			if len(idQuery) > 0 {
   703  				idQuery += ", "
   704  			}
   705  
   706  			props["userId"+strconv.Itoa(index)] = userId
   707  			idQuery += ":userId" + strconv.Itoa(index)
   708  		}
   709  
   710  		props["TeamId"] = teamId
   711  
   712  		if _, err := s.GetReplica().Select(&dbMembers, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.TeamId = :TeamId AND TeamMembers.UserId IN ("+idQuery+") AND TeamMembers.DeleteAt = 0", props); err != nil {
   713  			result.Err = model.NewAppError("SqlTeamStore.GetMembersByIds", "store.sql_team.get_members_by_ids.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
   714  			return
   715  		}
   716  		result.Data = dbMembers.ToModel()
   717  	})
   718  }
   719  
   720  func (s SqlTeamStore) GetTeamsForUser(userId string) store.StoreChannel {
   721  	return store.Do(func(result *store.StoreResult) {
   722  		var dbMembers teamMemberWithSchemeRolesList
   723  		_, err := s.GetReplica().Select(&dbMembers, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.UserId = :UserId", map[string]interface{}{"UserId": userId})
   724  		if err != nil {
   725  			result.Err = model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
   726  			return
   727  		}
   728  
   729  		result.Data = dbMembers.ToModel()
   730  	})
   731  }
   732  
   733  func (s SqlTeamStore) GetTeamsForUserWithPagination(userId string, page, perPage int) store.StoreChannel {
   734  	return store.Do(func(result *store.StoreResult) {
   735  		var dbMembers teamMemberWithSchemeRolesList
   736  		offset := page * perPage
   737  		_, err := s.GetReplica().Select(&dbMembers, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.UserId = :UserId Limit :Limit Offset :Offset", map[string]interface{}{"UserId": userId, "Limit": perPage, "Offset": offset})
   738  		if err != nil {
   739  			result.Err = model.NewAppError("SqlTeamStore.GetTeamsForUserWithPagination", "store.sql_team.get_members.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
   740  			return
   741  		}
   742  
   743  		result.Data = dbMembers.ToModel()
   744  	})
   745  }
   746  
   747  func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string) store.StoreChannel {
   748  	return store.Do(func(result *store.StoreResult) {
   749  		var data []*model.ChannelUnread
   750  		_, err := s.GetReplica().Select(&data,
   751  			`SELECT
   752  				Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps
   753  			FROM
   754  				Channels, ChannelMembers
   755  			WHERE
   756  				Id = ChannelId
   757                  AND UserId = :UserId
   758                  AND DeleteAt = 0
   759                  AND TeamId != :TeamId`,
   760  			map[string]interface{}{"UserId": userId, "TeamId": excludeTeamId})
   761  
   762  		if err != nil {
   763  			result.Err = model.NewAppError("SqlTeamStore.GetChannelUnreadsForAllTeams", "store.sql_team.get_unread.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
   764  			return
   765  		}
   766  		result.Data = data
   767  	})
   768  }
   769  
   770  func (s SqlTeamStore) GetChannelUnreadsForTeam(teamId, userId string) store.StoreChannel {
   771  	return store.Do(func(result *store.StoreResult) {
   772  		var data []*model.ChannelUnread
   773  		_, err := s.GetReplica().Select(&data,
   774  			`SELECT
   775  				Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps
   776  			FROM
   777  				Channels, ChannelMembers
   778  			WHERE
   779  				Id = ChannelId
   780                  AND UserId = :UserId
   781                  AND TeamId = :TeamId
   782                  AND DeleteAt = 0`,
   783  			map[string]interface{}{"TeamId": teamId, "UserId": userId})
   784  
   785  		if err != nil {
   786  			result.Err = model.NewAppError("SqlTeamStore.GetChannelUnreadsForTeam", "store.sql_team.get_unread.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
   787  			return
   788  		}
   789  		result.Data = data
   790  	})
   791  }
   792  
   793  func (s SqlTeamStore) RemoveMember(teamId string, userId string) store.StoreChannel {
   794  	return store.Do(func(result *store.StoreResult) {
   795  		_, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE TeamId = :TeamId AND UserId = :UserId", map[string]interface{}{"TeamId": teamId, "UserId": userId})
   796  		if err != nil {
   797  			result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError)
   798  		}
   799  	})
   800  }
   801  
   802  func (s SqlTeamStore) RemoveAllMembersByTeam(teamId string) store.StoreChannel {
   803  	return store.Do(func(result *store.StoreResult) {
   804  		_, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId})
   805  		if err != nil {
   806  			result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", "+err.Error(), http.StatusInternalServerError)
   807  		}
   808  	})
   809  }
   810  
   811  func (s SqlTeamStore) RemoveAllMembersByUser(userId string) store.StoreChannel {
   812  	return store.Do(func(result *store.StoreResult) {
   813  		_, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId})
   814  		if err != nil {
   815  			result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError)
   816  		}
   817  	})
   818  }
   819  
   820  func (us SqlTeamStore) UpdateLastTeamIconUpdate(teamId string, curTime int64) store.StoreChannel {
   821  	return store.Do(func(result *store.StoreResult) {
   822  		if _, err := us.GetMaster().Exec("UPDATE Teams SET LastTeamIconUpdate = :Time, UpdateAt = :Time WHERE Id = :teamId", map[string]interface{}{"Time": curTime, "teamId": teamId}); err != nil {
   823  			result.Err = model.NewAppError("SqlTeamStore.UpdateLastTeamIconUpdate", "store.sql_team.update_last_team_icon_update.app_error", nil, "team_id="+teamId, http.StatusInternalServerError)
   824  			return
   825  		}
   826  		result.Data = teamId
   827  	})
   828  }
   829  
   830  func (s SqlTeamStore) GetTeamsByScheme(schemeId string, offset int, limit int) store.StoreChannel {
   831  	return store.Do(func(result *store.StoreResult) {
   832  		var teams []*model.Team
   833  		_, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE SchemeId = :SchemeId ORDER BY DisplayName LIMIT :Limit OFFSET :Offset", map[string]interface{}{"SchemeId": schemeId, "Offset": offset, "Limit": limit})
   834  		if err != nil {
   835  			result.Err = model.NewAppError("SqlTeamStore.GetTeamsByScheme", "store.sql_team.get_by_scheme.app_error", nil, "schemeId="+schemeId+" "+err.Error(), http.StatusInternalServerError)
   836  			return
   837  		}
   838  		result.Data = teams
   839  	})
   840  }
   841  
   842  // This function does the Advanced Permissions Phase 2 migration for TeamMember objects. It performs the migration
   843  // in batches as a single transaction per batch to ensure consistency but to also minimise execution time to avoid
   844  // causing unnecessary table locks. **THIS FUNCTION SHOULD NOT BE USED FOR ANY OTHER PURPOSE.** Executing this function
   845  // *after* the new Schemes functionality has been used on an installation will have unintended consequences.
   846  func (s SqlTeamStore) MigrateTeamMembers(fromTeamId string, fromUserId string) store.StoreChannel {
   847  	return store.Do(func(result *store.StoreResult) {
   848  		var transaction *gorp.Transaction
   849  		var err error
   850  
   851  		if transaction, err = s.GetMaster().Begin(); err != nil {
   852  			result.Err = model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
   853  			return
   854  		}
   855  		defer finalizeTransaction(transaction)
   856  
   857  		var teamMembers []teamMember
   858  		if _, err := transaction.Select(&teamMembers, "SELECT * from TeamMembers WHERE (TeamId, UserId) > (:FromTeamId, :FromUserId) ORDER BY TeamId, UserId LIMIT 100", map[string]interface{}{"FromTeamId": fromTeamId, "FromUserId": fromUserId}); err != nil {
   859  			result.Err = model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.select.app_error", nil, err.Error(), http.StatusInternalServerError)
   860  			return
   861  		}
   862  
   863  		if len(teamMembers) == 0 {
   864  			// No more team members in query result means that the migration has finished.
   865  			return
   866  		}
   867  
   868  		for _, member := range teamMembers {
   869  			roles := strings.Fields(member.Roles)
   870  			var newRoles []string
   871  			if !member.SchemeAdmin.Valid {
   872  				member.SchemeAdmin = sql.NullBool{Bool: false, Valid: true}
   873  			}
   874  			if !member.SchemeUser.Valid {
   875  				member.SchemeUser = sql.NullBool{Bool: false, Valid: true}
   876  			}
   877  			for _, role := range roles {
   878  				if role == model.TEAM_ADMIN_ROLE_ID {
   879  					member.SchemeAdmin = sql.NullBool{Bool: true, Valid: true}
   880  				} else if role == model.TEAM_USER_ROLE_ID {
   881  					member.SchemeUser = sql.NullBool{Bool: true, Valid: true}
   882  				} else {
   883  					newRoles = append(newRoles, role)
   884  				}
   885  			}
   886  			member.Roles = strings.Join(newRoles, " ")
   887  
   888  			if _, err := transaction.Update(&member); err != nil {
   889  				result.Err = model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.update.app_error", nil, err.Error(), http.StatusInternalServerError)
   890  				return
   891  			}
   892  
   893  		}
   894  
   895  		if err := transaction.Commit(); err != nil {
   896  			result.Err = model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
   897  			return
   898  		}
   899  
   900  		data := make(map[string]string)
   901  		data["TeamId"] = teamMembers[len(teamMembers)-1].TeamId
   902  		data["UserId"] = teamMembers[len(teamMembers)-1].UserId
   903  		result.Data = data
   904  	})
   905  }
   906  
   907  func (s SqlTeamStore) ResetAllTeamSchemes() store.StoreChannel {
   908  	return store.Do(func(result *store.StoreResult) {
   909  		if _, err := s.GetMaster().Exec("UPDATE Teams SET SchemeId=''"); err != nil {
   910  			result.Err = model.NewAppError("SqlTeamStore.ResetAllTeamSchemes", "store.sql_team.reset_all_team_schemes.app_error", nil, err.Error(), http.StatusInternalServerError)
   911  		}
   912  	})
   913  }
   914  
   915  func (s SqlTeamStore) ClearAllCustomRoleAssignments() store.StoreChannel {
   916  	return store.Do(func(result *store.StoreResult) {
   917  		builtInRoles := model.MakeDefaultRoles()
   918  		lastUserId := strings.Repeat("0", 26)
   919  		lastTeamId := strings.Repeat("0", 26)
   920  
   921  		for {
   922  			var transaction *gorp.Transaction
   923  			var err error
   924  
   925  			if transaction, err = s.GetMaster().Begin(); err != nil {
   926  				result.Err = model.NewAppError("SqlTeamStore.ClearAllCustomRoleAssignments", "store.sql_team.clear_all_custom_role_assignments.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
   927  				return
   928  			}
   929  			defer finalizeTransaction(transaction)
   930  
   931  			var teamMembers []*teamMember
   932  			if _, err := transaction.Select(&teamMembers, "SELECT * from TeamMembers WHERE (TeamId, UserId) > (:TeamId, :UserId) ORDER BY TeamId, UserId LIMIT 1000", map[string]interface{}{"TeamId": lastTeamId, "UserId": lastUserId}); err != nil {
   933  				result.Err = model.NewAppError("SqlTeamStore.ClearAllCustomRoleAssignments", "store.sql_team.clear_all_custom_role_assignments.select.app_error", nil, err.Error(), http.StatusInternalServerError)
   934  				return
   935  			}
   936  
   937  			if len(teamMembers) == 0 {
   938  				break
   939  			}
   940  
   941  			for _, member := range teamMembers {
   942  				lastUserId = member.UserId
   943  				lastTeamId = member.TeamId
   944  
   945  				var newRoles []string
   946  
   947  				for _, role := range strings.Fields(member.Roles) {
   948  					for name := range builtInRoles {
   949  						if name == role {
   950  							newRoles = append(newRoles, role)
   951  							break
   952  						}
   953  					}
   954  				}
   955  
   956  				newRolesString := strings.Join(newRoles, " ")
   957  				if newRolesString != member.Roles {
   958  					if _, err := transaction.Exec("UPDATE TeamMembers SET Roles = :Roles WHERE UserId = :UserId AND TeamId = :TeamId", map[string]interface{}{"Roles": newRolesString, "TeamId": member.TeamId, "UserId": member.UserId}); err != nil {
   959  						result.Err = model.NewAppError("SqlTeamStore.ClearAllCustomRoleAssignments", "store.sql_team.clear_all_custom_role_assignments.update.app_error", nil, err.Error(), http.StatusInternalServerError)
   960  						return
   961  					}
   962  				}
   963  			}
   964  
   965  			if err := transaction.Commit(); err != nil {
   966  				result.Err = model.NewAppError("SqlTeamStore.ClearAllCustomRoleAssignments", "store.sql_team.clear_all_custom_role_assignments.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
   967  				return
   968  			}
   969  		}
   970  	})
   971  }
   972  
   973  func (s SqlTeamStore) AnalyticsGetTeamCountForScheme(schemeId string) store.StoreChannel {
   974  	return store.Do(func(result *store.StoreResult) {
   975  		count, err := s.GetReplica().SelectInt("SELECT count(*) FROM Teams WHERE SchemeId = :SchemeId AND DeleteAt = 0", map[string]interface{}{"SchemeId": schemeId})
   976  		if err != nil {
   977  			result.Err = model.NewAppError("SqlTeamStore.AnalyticsGetTeamCountForScheme", "store.sql_team.analytics_get_team_count_for_scheme.app_error", nil, "schemeId="+schemeId+" "+err.Error(), http.StatusInternalServerError)
   978  			return
   979  		}
   980  		result.Data = count
   981  	})
   982  }
   983  
   984  func (s SqlTeamStore) GetAllForExportAfter(limit int, afterId string) store.StoreChannel {
   985  	return store.Do(func(result *store.StoreResult) {
   986  		var data []*model.TeamForExport
   987  		if _, err := s.GetReplica().Select(&data, `
   988  			SELECT
   989  				Teams.*,
   990  				Schemes.Name as SchemeName
   991  			FROM
   992  				Teams
   993  			LEFT JOIN
   994  				Schemes ON Teams.SchemeId = Schemes.Id
   995  			WHERE
   996  				Teams.Id > :AfterId
   997  			ORDER BY
   998  				Id
   999  			LIMIT
  1000  				:Limit`,
  1001  			map[string]interface{}{"AfterId": afterId, "Limit": limit}); err != nil {
  1002  			result.Err = model.NewAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
  1003  			return
  1004  		}
  1005  
  1006  		for _, team := range data {
  1007  			if len(team.InviteId) == 0 {
  1008  				team.InviteId = team.Id
  1009  			}
  1010  		}
  1011  
  1012  		result.Data = data
  1013  	})
  1014  }
  1015  
  1016  func (s SqlTeamStore) GetTeamMembersForExport(userId string) store.StoreChannel {
  1017  	return store.Do(func(result *store.StoreResult) {
  1018  		var members []*model.TeamMemberForExport
  1019  		_, err := s.GetReplica().Select(&members, `
  1020  	SELECT
  1021  		TeamMembers.*,
  1022  		Teams.Name as TeamName
  1023  	FROM
  1024  		TeamMembers
  1025  	INNER JOIN
  1026  		Teams ON TeamMembers.TeamId = Teams.Id
  1027  	WHERE
  1028  		TeamMembers.UserId = :UserId
  1029  		AND Teams.DeleteAt = 0`,
  1030  			map[string]interface{}{"UserId": userId})
  1031  		if err != nil {
  1032  			result.Err = model.NewAppError("SqlTeamStore.GetTeamMembersForExport", "store.sql_team.get_members.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
  1033  			return
  1034  		}
  1035  
  1036  		result.Data = members
  1037  	})
  1038  }