github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/store/sqlstore/team_store.go (about)

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