github.com/qichengzx/mattermost-server@v4.5.1-0.20180604164826-2c75247c97d0+incompatible/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/mattermost/mattermost-server/model"
    14  	"github.com/mattermost/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  			} else {
   189  				result.Err = model.NewAppError("SqlTeamStore.Save", "store.sql_team.save.app_error", nil, "id="+team.Id+", "+err.Error(), http.StatusInternalServerError)
   190  			}
   191  		} else {
   192  			result.Data = team
   193  		}
   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  		if oldResult, err := s.GetMaster().Get(model.Team{}, team.Id); err != nil {
   206  			result.Err = model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.finding.app_error", nil, "id="+team.Id+", "+err.Error(), http.StatusInternalServerError)
   207  		} else if oldResult == nil {
   208  			result.Err = model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.find.app_error", nil, "id="+team.Id, http.StatusBadRequest)
   209  		} else {
   210  			oldTeam := oldResult.(*model.Team)
   211  			team.CreateAt = oldTeam.CreateAt
   212  			team.UpdateAt = model.GetMillis()
   213  			team.Name = oldTeam.Name
   214  
   215  			if count, err := s.GetMaster().Update(team); err != nil {
   216  				result.Err = model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.updating.app_error", nil, "id="+team.Id+", "+err.Error(), http.StatusInternalServerError)
   217  			} else if count != 1 {
   218  				result.Err = model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.app_error", nil, "id="+team.Id, http.StatusInternalServerError)
   219  			} else {
   220  				result.Data = team
   221  			}
   222  		}
   223  	})
   224  }
   225  
   226  func (s SqlTeamStore) UpdateDisplayName(name string, teamId string) store.StoreChannel {
   227  	return store.Do(func(result *store.StoreResult) {
   228  		if _, err := s.GetMaster().Exec("UPDATE Teams SET DisplayName = :Name WHERE Id = :Id", map[string]interface{}{"Name": name, "Id": teamId}); err != nil {
   229  			result.Err = model.NewAppError("SqlTeamStore.UpdateName", "store.sql_team.update_display_name.app_error", nil, "team_id="+teamId, http.StatusInternalServerError)
   230  		} else {
   231  			result.Data = teamId
   232  		}
   233  	})
   234  }
   235  
   236  func (s SqlTeamStore) Get(id string) store.StoreChannel {
   237  	return store.Do(func(result *store.StoreResult) {
   238  		if obj, err := s.GetReplica().Get(model.Team{}, id); err != nil {
   239  			result.Err = model.NewAppError("SqlTeamStore.Get", "store.sql_team.get.finding.app_error", nil, "id="+id+", "+err.Error(), http.StatusInternalServerError)
   240  		} else if obj == nil {
   241  			result.Err = model.NewAppError("SqlTeamStore.Get", "store.sql_team.get.find.app_error", nil, "id="+id, http.StatusNotFound)
   242  		} else {
   243  			team := obj.(*model.Team)
   244  			if len(team.InviteId) == 0 {
   245  				team.InviteId = team.Id
   246  			}
   247  
   248  			result.Data = team
   249  		}
   250  	})
   251  }
   252  
   253  func (s SqlTeamStore) GetByInviteId(inviteId string) store.StoreChannel {
   254  	return store.Do(func(result *store.StoreResult) {
   255  		team := model.Team{}
   256  
   257  		if err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE Id = :InviteId OR InviteId = :InviteId", map[string]interface{}{"InviteId": inviteId}); err != nil {
   258  			result.Err = model.NewAppError("SqlTeamStore.GetByInviteId", "store.sql_team.get_by_invite_id.finding.app_error", nil, "inviteId="+inviteId+", "+err.Error(), http.StatusNotFound)
   259  		}
   260  
   261  		if len(team.InviteId) == 0 {
   262  			team.InviteId = team.Id
   263  		}
   264  
   265  		if len(inviteId) == 0 || team.InviteId != inviteId {
   266  			result.Err = model.NewAppError("SqlTeamStore.GetByInviteId", "store.sql_team.get_by_invite_id.find.app_error", nil, "inviteId="+inviteId, http.StatusNotFound)
   267  		}
   268  
   269  		result.Data = &team
   270  	})
   271  }
   272  
   273  func (s SqlTeamStore) GetByName(name string) store.StoreChannel {
   274  	return store.Do(func(result *store.StoreResult) {
   275  		team := model.Team{}
   276  
   277  		if err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE Name = :Name", map[string]interface{}{"Name": name}); err != nil {
   278  			result.Err = model.NewAppError("SqlTeamStore.GetByName", "store.sql_team.get_by_name.app_error", nil, "name="+name+", "+err.Error(), http.StatusInternalServerError)
   279  		}
   280  
   281  		if len(team.InviteId) == 0 {
   282  			team.InviteId = team.Id
   283  		}
   284  
   285  		result.Data = &team
   286  	})
   287  }
   288  
   289  func (s SqlTeamStore) SearchByName(name string) store.StoreChannel {
   290  	return store.Do(func(result *store.StoreResult) {
   291  		var teams []*model.Team
   292  
   293  		if _, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE Name LIKE :Name", map[string]interface{}{"Name": name + "%"}); err != nil {
   294  			result.Err = model.NewAppError("SqlTeamStore.SearchByName", "store.sql_team.get_by_name.app_error", nil, "name="+name+", "+err.Error(), http.StatusInternalServerError)
   295  		}
   296  
   297  		result.Data = teams
   298  	})
   299  }
   300  
   301  func (s SqlTeamStore) SearchAll(term string) store.StoreChannel {
   302  	return store.Do(func(result *store.StoreResult) {
   303  		var teams []*model.Team
   304  
   305  		if _, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE Name LIKE :Term OR DisplayName LIKE :Term", map[string]interface{}{"Term": term + "%"}); err != nil {
   306  			result.Err = model.NewAppError("SqlTeamStore.SearchAll", "store.sql_team.search_all_team.app_error", nil, "term="+term+", "+err.Error(), http.StatusInternalServerError)
   307  		}
   308  
   309  		result.Data = teams
   310  	})
   311  }
   312  
   313  func (s SqlTeamStore) SearchOpen(term string) store.StoreChannel {
   314  	return store.Do(func(result *store.StoreResult) {
   315  		var teams []*model.Team
   316  
   317  		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 {
   318  			result.Err = model.NewAppError("SqlTeamStore.SearchOpen", "store.sql_team.search_open_team.app_error", nil, "term="+term+", "+err.Error(), http.StatusInternalServerError)
   319  		}
   320  
   321  		result.Data = teams
   322  	})
   323  }
   324  
   325  func (s SqlTeamStore) GetAll() store.StoreChannel {
   326  	return store.Do(func(result *store.StoreResult) {
   327  		var data []*model.Team
   328  		if _, err := s.GetReplica().Select(&data, "SELECT * FROM Teams"); err != nil {
   329  			result.Err = model.NewAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
   330  		}
   331  
   332  		for _, team := range data {
   333  			if len(team.InviteId) == 0 {
   334  				team.InviteId = team.Id
   335  			}
   336  		}
   337  
   338  		result.Data = data
   339  	})
   340  }
   341  
   342  func (s SqlTeamStore) GetAllPage(offset int, limit int) store.StoreChannel {
   343  	return store.Do(func(result *store.StoreResult) {
   344  		var data []*model.Team
   345  		if _, err := s.GetReplica().Select(&data, "SELECT * FROM Teams LIMIT :Limit OFFSET :Offset", map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
   346  			result.Err = model.NewAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
   347  		}
   348  
   349  		for _, team := range data {
   350  			if len(team.InviteId) == 0 {
   351  				team.InviteId = team.Id
   352  			}
   353  		}
   354  
   355  		result.Data = data
   356  	})
   357  }
   358  
   359  func (s SqlTeamStore) GetTeamsByUserId(userId string) store.StoreChannel {
   360  	return store.Do(func(result *store.StoreResult) {
   361  		var data []*model.Team
   362  		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 {
   363  			result.Err = model.NewAppError("SqlTeamStore.GetTeamsByUserId", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
   364  		}
   365  
   366  		for _, team := range data {
   367  			if len(team.InviteId) == 0 {
   368  				team.InviteId = team.Id
   369  			}
   370  		}
   371  
   372  		result.Data = data
   373  	})
   374  }
   375  
   376  func (s SqlTeamStore) GetAllTeamListing() store.StoreChannel {
   377  	return store.Do(func(result *store.StoreResult) {
   378  		query := "SELECT * FROM Teams WHERE AllowOpenInvite = 1"
   379  
   380  		if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   381  			query = "SELECT * FROM Teams WHERE AllowOpenInvite = true"
   382  		}
   383  
   384  		var data []*model.Team
   385  		if _, err := s.GetReplica().Select(&data, query); err != nil {
   386  			result.Err = model.NewAppError("SqlTeamStore.GetAllTeamListing", "store.sql_team.get_all_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
   387  		}
   388  
   389  		for _, team := range data {
   390  			if len(team.InviteId) == 0 {
   391  				team.InviteId = team.Id
   392  			}
   393  		}
   394  
   395  		result.Data = data
   396  	})
   397  }
   398  
   399  func (s SqlTeamStore) GetAllTeamPageListing(offset int, limit int) store.StoreChannel {
   400  	return store.Do(func(result *store.StoreResult) {
   401  		query := "SELECT * FROM Teams WHERE AllowOpenInvite = 1 LIMIT :Limit OFFSET :Offset"
   402  
   403  		if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
   404  			query = "SELECT * FROM Teams WHERE AllowOpenInvite = true LIMIT :Limit OFFSET :Offset"
   405  		}
   406  
   407  		var data []*model.Team
   408  		if _, err := s.GetReplica().Select(&data, query, map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
   409  			result.Err = model.NewAppError("SqlTeamStore.GetAllTeamListing", "store.sql_team.get_all_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
   410  		}
   411  
   412  		for _, team := range data {
   413  			if len(team.InviteId) == 0 {
   414  				team.InviteId = team.Id
   415  			}
   416  		}
   417  
   418  		result.Data = data
   419  	})
   420  }
   421  
   422  func (s SqlTeamStore) PermanentDelete(teamId string) store.StoreChannel {
   423  	return store.Do(func(result *store.StoreResult) {
   424  		if _, err := s.GetMaster().Exec("DELETE FROM Teams WHERE Id = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil {
   425  			result.Err = model.NewAppError("SqlTeamStore.Delete", "store.sql_team.permanent_delete.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError)
   426  		}
   427  	})
   428  }
   429  
   430  func (s SqlTeamStore) AnalyticsTeamCount() store.StoreChannel {
   431  	return store.Do(func(result *store.StoreResult) {
   432  		if c, err := s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0", map[string]interface{}{}); err != nil {
   433  			result.Err = model.NewAppError("SqlTeamStore.AnalyticsTeamCount", "store.sql_team.analytics_team_count.app_error", nil, err.Error(), http.StatusInternalServerError)
   434  		} else {
   435  			result.Data = c
   436  		}
   437  	})
   438  }
   439  
   440  var TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY = `
   441  	SELECT
   442  		TeamMembers.*,
   443  		TeamScheme.DefaultTeamUserRole TeamSchemeDefaultUserRole,
   444  		TeamScheme.DefaultTeamAdminRole TeamSchemeDefaultAdminRole
   445  	FROM 
   446  		TeamMembers
   447  	LEFT JOIN
   448  		Teams ON TeamMembers.TeamId = Teams.Id
   449  	LEFT JOIN
   450  		Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id 
   451  `
   452  
   453  func (s SqlTeamStore) SaveMember(member *model.TeamMember, maxUsersPerTeam int) store.StoreChannel {
   454  	return store.Do(func(result *store.StoreResult) {
   455  		if result.Err = member.IsValid(); result.Err != nil {
   456  			return
   457  		}
   458  
   459  		dbMember := NewTeamMemberFromModel(member)
   460  
   461  		if maxUsersPerTeam >= 0 {
   462  			if count, err := s.GetMaster().SelectInt(
   463  				`SELECT
   464  					COUNT(0)
   465  				FROM
   466  					TeamMembers
   467  				INNER JOIN
   468  					Users
   469  				ON
   470  					TeamMembers.UserId = Users.Id
   471  				WHERE
   472  					TeamId = :TeamId
   473  					AND TeamMembers.DeleteAt = 0
   474  					AND Users.DeleteAt = 0`, map[string]interface{}{"TeamId": member.TeamId}); err != nil {
   475  				result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, "teamId="+member.TeamId+", "+err.Error(), http.StatusInternalServerError)
   476  				return
   477  			} else if count >= int64(maxUsersPerTeam) {
   478  				result.Err = model.NewAppError("SqlUserStore.Save", "store.sql_user.save.max_accounts.app_error", nil, "teamId="+member.TeamId, http.StatusBadRequest)
   479  				return
   480  			}
   481  		}
   482  
   483  		if err := s.GetMaster().Insert(dbMember); err != nil {
   484  			if IsUniqueConstraintError(err, []string{"TeamId", "teammembers_pkey", "PRIMARY"}) {
   485  				result.Err = model.NewAppError("SqlTeamStore.SaveMember", TEAM_MEMBER_EXISTS_ERROR, nil, "team_id="+member.TeamId+", user_id="+member.UserId+", "+err.Error(), http.StatusBadRequest)
   486  			} else {
   487  				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)
   488  			}
   489  		} else {
   490  			var retrievedMember teamMemberWithSchemeRoles
   491  			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 {
   492  				if err == sql.ErrNoRows {
   493  					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)
   494  				} else {
   495  					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)
   496  				}
   497  			} else {
   498  				result.Data = retrievedMember.ToModel()
   499  			}
   500  		}
   501  	})
   502  }
   503  
   504  func (s SqlTeamStore) UpdateMember(member *model.TeamMember) store.StoreChannel {
   505  	return store.Do(func(result *store.StoreResult) {
   506  		member.PreUpdate()
   507  
   508  		if result.Err = member.IsValid(); result.Err != nil {
   509  			return
   510  		}
   511  
   512  		if _, err := s.GetMaster().Update(NewTeamMemberFromModel(member)); err != nil {
   513  			result.Err = model.NewAppError("SqlTeamStore.UpdateMember", "store.sql_team.save_member.save.app_error", nil, err.Error(), http.StatusInternalServerError)
   514  		} else {
   515  			var retrievedMember teamMemberWithSchemeRoles
   516  			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 {
   517  				if err == sql.ErrNoRows {
   518  					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)
   519  				} else {
   520  					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)
   521  				}
   522  			} else {
   523  				result.Data = retrievedMember.ToModel()
   524  			}
   525  		}
   526  	})
   527  }
   528  
   529  func (s SqlTeamStore) GetMember(teamId string, userId string) store.StoreChannel {
   530  	return store.Do(func(result *store.StoreResult) {
   531  		var dbMember teamMemberWithSchemeRoles
   532  		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})
   533  		if err != nil {
   534  			if err == sql.ErrNoRows {
   535  				result.Err = model.NewAppError("SqlTeamStore.GetMember", "store.sql_team.get_member.missing.app_error", nil, "teamId="+teamId+" userId="+userId+" "+err.Error(), http.StatusNotFound)
   536  			} else {
   537  				result.Err = model.NewAppError("SqlTeamStore.GetMember", "store.sql_team.get_member.app_error", nil, "teamId="+teamId+" userId="+userId+" "+err.Error(), http.StatusInternalServerError)
   538  			}
   539  		} else {
   540  			result.Data = dbMember.ToModel()
   541  		}
   542  	})
   543  }
   544  
   545  func (s SqlTeamStore) GetMembers(teamId string, offset int, limit int) store.StoreChannel {
   546  	return store.Do(func(result *store.StoreResult) {
   547  		var dbMembers teamMemberWithSchemeRolesList
   548  		_, 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})
   549  		if err != nil {
   550  			result.Err = model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
   551  		} else {
   552  			result.Data = dbMembers.ToModel()
   553  		}
   554  	})
   555  }
   556  
   557  func (s SqlTeamStore) GetTotalMemberCount(teamId string) store.StoreChannel {
   558  	return store.Do(func(result *store.StoreResult) {
   559  		count, err := s.GetReplica().SelectInt(`
   560  			SELECT
   561  				count(*)
   562  			FROM
   563  				TeamMembers,
   564  				Users
   565  			WHERE
   566  				TeamMembers.UserId = Users.Id
   567  				AND TeamMembers.TeamId = :TeamId
   568  				AND TeamMembers.DeleteAt = 0`, map[string]interface{}{"TeamId": teamId})
   569  		if err != nil {
   570  			result.Err = model.NewAppError("SqlTeamStore.GetTotalMemberCount", "store.sql_team.get_member_count.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
   571  		} else {
   572  			result.Data = count
   573  		}
   574  	})
   575  }
   576  
   577  func (s SqlTeamStore) GetActiveMemberCount(teamId string) store.StoreChannel {
   578  	return store.Do(func(result *store.StoreResult) {
   579  		count, err := s.GetReplica().SelectInt(`
   580  			SELECT
   581  				count(*)
   582  			FROM
   583  				TeamMembers,
   584  				Users
   585  			WHERE
   586  				TeamMembers.UserId = Users.Id
   587  				AND TeamMembers.TeamId = :TeamId
   588  				AND TeamMembers.DeleteAt = 0
   589  				AND Users.DeleteAt = 0`, map[string]interface{}{"TeamId": teamId})
   590  		if err != nil {
   591  			result.Err = model.NewAppError("SqlTeamStore.GetActiveMemberCount", "store.sql_team.get_member_count.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
   592  		} else {
   593  			result.Data = count
   594  		}
   595  	})
   596  }
   597  
   598  func (s SqlTeamStore) GetMembersByIds(teamId string, userIds []string) store.StoreChannel {
   599  	return store.Do(func(result *store.StoreResult) {
   600  		var dbMembers teamMemberWithSchemeRolesList
   601  		props := make(map[string]interface{})
   602  		idQuery := ""
   603  
   604  		for index, userId := range userIds {
   605  			if len(idQuery) > 0 {
   606  				idQuery += ", "
   607  			}
   608  
   609  			props["userId"+strconv.Itoa(index)] = userId
   610  			idQuery += ":userId" + strconv.Itoa(index)
   611  		}
   612  
   613  		props["TeamId"] = teamId
   614  
   615  		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 {
   616  			result.Err = model.NewAppError("SqlTeamStore.GetMembersByIds", "store.sql_team.get_members_by_ids.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
   617  		} else {
   618  			result.Data = dbMembers.ToModel()
   619  		}
   620  	})
   621  }
   622  
   623  func (s SqlTeamStore) GetTeamsForUser(userId string) store.StoreChannel {
   624  	return store.Do(func(result *store.StoreResult) {
   625  		var dbMembers teamMemberWithSchemeRolesList
   626  		_, err := s.GetReplica().Select(&dbMembers, TEAM_MEMBERS_WITH_SCHEME_SELECT_QUERY+"WHERE TeamMembers.UserId = :UserId", map[string]interface{}{"UserId": userId})
   627  		if err != nil {
   628  			result.Err = model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
   629  		} else {
   630  			result.Data = dbMembers.ToModel()
   631  		}
   632  	})
   633  }
   634  
   635  func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string) store.StoreChannel {
   636  	return store.Do(func(result *store.StoreResult) {
   637  		var data []*model.ChannelUnread
   638  		_, err := s.GetReplica().Select(&data,
   639  			`SELECT
   640  				Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps
   641  			FROM
   642  				Channels, ChannelMembers
   643  			WHERE
   644  				Id = ChannelId
   645                  AND UserId = :UserId
   646                  AND DeleteAt = 0
   647                  AND TeamId != :TeamId`,
   648  			map[string]interface{}{"UserId": userId, "TeamId": excludeTeamId})
   649  
   650  		if err != nil {
   651  			result.Err = model.NewAppError("SqlTeamStore.GetChannelUnreadsForAllTeams", "store.sql_team.get_unread.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
   652  		} else {
   653  			result.Data = data
   654  		}
   655  	})
   656  }
   657  
   658  func (s SqlTeamStore) GetChannelUnreadsForTeam(teamId, userId string) store.StoreChannel {
   659  	return store.Do(func(result *store.StoreResult) {
   660  		var data []*model.ChannelUnread
   661  		_, err := s.GetReplica().Select(&data,
   662  			`SELECT
   663  				Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps
   664  			FROM
   665  				Channels, ChannelMembers
   666  			WHERE
   667  				Id = ChannelId
   668                  AND UserId = :UserId
   669                  AND TeamId = :TeamId
   670                  AND DeleteAt = 0`,
   671  			map[string]interface{}{"TeamId": teamId, "UserId": userId})
   672  
   673  		if err != nil {
   674  			result.Err = model.NewAppError("SqlTeamStore.GetChannelUnreadsForTeam", "store.sql_team.get_unread.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
   675  		} else {
   676  			result.Data = data
   677  		}
   678  	})
   679  }
   680  
   681  func (s SqlTeamStore) RemoveMember(teamId string, userId string) store.StoreChannel {
   682  	return store.Do(func(result *store.StoreResult) {
   683  		_, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE TeamId = :TeamId AND UserId = :UserId", map[string]interface{}{"TeamId": teamId, "UserId": userId})
   684  		if err != nil {
   685  			result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", user_id="+userId+", "+err.Error(), http.StatusInternalServerError)
   686  		}
   687  	})
   688  }
   689  
   690  func (s SqlTeamStore) RemoveAllMembersByTeam(teamId string) store.StoreChannel {
   691  	return store.Do(func(result *store.StoreResult) {
   692  		_, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId})
   693  		if err != nil {
   694  			result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", "+err.Error(), http.StatusInternalServerError)
   695  		}
   696  	})
   697  }
   698  
   699  func (s SqlTeamStore) RemoveAllMembersByUser(userId string) store.StoreChannel {
   700  	return store.Do(func(result *store.StoreResult) {
   701  		_, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId})
   702  		if err != nil {
   703  			result.Err = model.NewAppError("SqlChannelStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError)
   704  		}
   705  	})
   706  }
   707  
   708  func (us SqlTeamStore) UpdateLastTeamIconUpdate(teamId string, curTime int64) store.StoreChannel {
   709  	return store.Do(func(result *store.StoreResult) {
   710  		if _, err := us.GetMaster().Exec("UPDATE Teams SET LastTeamIconUpdate = :Time, UpdateAt = :Time WHERE Id = :teamId", map[string]interface{}{"Time": curTime, "teamId": teamId}); err != nil {
   711  			result.Err = model.NewAppError("SqlTeamStore.UpdateLastTeamIconUpdate", "store.sql_team.update_last_team_icon_update.app_error", nil, "team_id="+teamId, http.StatusInternalServerError)
   712  		} else {
   713  			result.Data = teamId
   714  		}
   715  	})
   716  }
   717  
   718  func (s SqlTeamStore) GetTeamsByScheme(schemeId string, offset int, limit int) store.StoreChannel {
   719  	return store.Do(func(result *store.StoreResult) {
   720  		var teams []*model.Team
   721  		_, 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})
   722  		if err != nil {
   723  			result.Err = model.NewAppError("SqlTeamStore.GetTeamsByScheme", "store.sql_team.get_by_scheme.app_error", nil, "schemeId="+schemeId+" "+err.Error(), http.StatusInternalServerError)
   724  		} else {
   725  			result.Data = teams
   726  		}
   727  	})
   728  }
   729  
   730  // This function does the Advanced Permissions Phase 2 migration for TeamMember objects. It performs the migration
   731  // in batches as a single transaction per batch to ensure consistency but to also minimise execution time to avoid
   732  // causing unnecessary table locks. **THIS FUNCTION SHOULD NOT BE USED FOR ANY OTHER PURPOSE.** Executing this function
   733  // *after* the new Schemes functionality has been used on an installation will have unintended consequences.
   734  func (s SqlTeamStore) MigrateTeamMembers(fromTeamId string, fromUserId string) store.StoreChannel {
   735  	return store.Do(func(result *store.StoreResult) {
   736  		var transaction *gorp.Transaction
   737  		var err error
   738  
   739  		if transaction, err = s.GetMaster().Begin(); err != nil {
   740  			result.Err = model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
   741  			return
   742  		}
   743  
   744  		var teamMembers []teamMember
   745  		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 {
   746  			result.Err = model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.select.app_error", nil, err.Error(), http.StatusInternalServerError)
   747  			return
   748  		}
   749  
   750  		if len(teamMembers) == 0 {
   751  			// No more team members in query result means that the migration has finished.
   752  			return
   753  		}
   754  
   755  		for _, member := range teamMembers {
   756  			roles := strings.Fields(member.Roles)
   757  			var newRoles []string
   758  			member.SchemeAdmin = sql.NullBool{Bool: false, Valid: true}
   759  			member.SchemeUser = sql.NullBool{Bool: false, Valid: true}
   760  			for _, role := range roles {
   761  				if role == model.TEAM_ADMIN_ROLE_ID {
   762  					member.SchemeAdmin = sql.NullBool{Bool: true, Valid: true}
   763  				} else if role == model.TEAM_USER_ROLE_ID {
   764  					member.SchemeUser = sql.NullBool{Bool: true, Valid: true}
   765  				} else {
   766  					newRoles = append(newRoles, role)
   767  				}
   768  			}
   769  			member.Roles = strings.Join(newRoles, " ")
   770  
   771  			if _, err := transaction.Update(&member); err != nil {
   772  				if err2 := transaction.Rollback(); err2 != nil {
   773  					result.Err = model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError)
   774  					return
   775  				}
   776  				result.Err = model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.update.app_error", nil, err.Error(), http.StatusInternalServerError)
   777  				return
   778  			}
   779  
   780  		}
   781  
   782  		if err := transaction.Commit(); err != nil {
   783  			if err2 := transaction.Rollback(); err2 != nil {
   784  				result.Err = model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.rollback_transaction.app_error", nil, err2.Error(), http.StatusInternalServerError)
   785  				return
   786  			}
   787  			result.Err = model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
   788  			return
   789  		}
   790  
   791  		data := make(map[string]string)
   792  		data["TeamId"] = teamMembers[len(teamMembers)-1].TeamId
   793  		data["UserId"] = teamMembers[len(teamMembers)-1].UserId
   794  		result.Data = data
   795  	})
   796  }
   797  
   798  func (s SqlTeamStore) ResetAllTeamSchemes() store.StoreChannel {
   799  	return store.Do(func(result *store.StoreResult) {
   800  		if _, err := s.GetMaster().Exec("UPDATE Teams SET SchemeId=''"); err != nil {
   801  			result.Err = model.NewAppError("SqlTeamStore.ResetAllTeamSchemes", "store.sql_team.reset_all_team_schemes.app_error", nil, err.Error(), http.StatusInternalServerError)
   802  		}
   803  	})
   804  }