mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
* Implement prefix/suffix search on teams page * Make Channel Page prefix/suffix search as well * address PR comments * add tests * fix styling * take postgres into account * add more api tests * update test * add team store test * write store test for team and channel * fix lint * update description * revert go mod Co-authored-by: mattermod <mattermod@users.noreply.github.com>
1480 lines
58 KiB
Go
1480 lines
58 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package sqlstore
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
sq "github.com/Masterminds/squirrel"
|
|
"github.com/mattermost/gorp"
|
|
"github.com/mattermost/mattermost-server/v5/model"
|
|
"github.com/mattermost/mattermost-server/v5/store"
|
|
"github.com/mattermost/mattermost-server/v5/utils"
|
|
)
|
|
|
|
const (
|
|
TEAM_MEMBER_EXISTS_ERROR = "store.sql_team.save_member.exists.app_error"
|
|
)
|
|
|
|
type SqlTeamStore struct {
|
|
SqlStore
|
|
}
|
|
|
|
type teamMember struct {
|
|
TeamId string
|
|
UserId string
|
|
Roles string
|
|
DeleteAt int64
|
|
SchemeUser sql.NullBool
|
|
SchemeAdmin sql.NullBool
|
|
SchemeGuest sql.NullBool
|
|
}
|
|
|
|
func NewTeamMemberFromModel(tm *model.TeamMember) *teamMember {
|
|
return &teamMember{
|
|
TeamId: tm.TeamId,
|
|
UserId: tm.UserId,
|
|
Roles: tm.ExplicitRoles,
|
|
DeleteAt: tm.DeleteAt,
|
|
SchemeGuest: sql.NullBool{Valid: true, Bool: tm.SchemeGuest},
|
|
SchemeUser: sql.NullBool{Valid: true, Bool: tm.SchemeUser},
|
|
SchemeAdmin: sql.NullBool{Valid: true, Bool: tm.SchemeAdmin},
|
|
}
|
|
}
|
|
|
|
type teamMemberWithSchemeRoles struct {
|
|
TeamId string
|
|
UserId string
|
|
Roles string
|
|
DeleteAt int64
|
|
SchemeGuest sql.NullBool
|
|
SchemeUser sql.NullBool
|
|
SchemeAdmin sql.NullBool
|
|
TeamSchemeDefaultGuestRole sql.NullString
|
|
TeamSchemeDefaultUserRole sql.NullString
|
|
TeamSchemeDefaultAdminRole sql.NullString
|
|
}
|
|
|
|
type teamMemberWithSchemeRolesList []teamMemberWithSchemeRoles
|
|
|
|
func teamMemberSliceColumns() []string {
|
|
return []string{"TeamId", "UserId", "Roles", "DeleteAt", "SchemeUser", "SchemeAdmin", "SchemeGuest"}
|
|
}
|
|
|
|
func teamMemberToSlice(member *model.TeamMember) []interface{} {
|
|
resultSlice := []interface{}{}
|
|
resultSlice = append(resultSlice, member.TeamId)
|
|
resultSlice = append(resultSlice, member.UserId)
|
|
resultSlice = append(resultSlice, member.ExplicitRoles)
|
|
resultSlice = append(resultSlice, member.DeleteAt)
|
|
resultSlice = append(resultSlice, member.SchemeUser)
|
|
resultSlice = append(resultSlice, member.SchemeAdmin)
|
|
resultSlice = append(resultSlice, member.SchemeGuest)
|
|
return resultSlice
|
|
}
|
|
|
|
func wildcardSearchTerm(term string) string {
|
|
return strings.ToLower("%" + term + "%")
|
|
}
|
|
|
|
type rolesInfo struct {
|
|
roles []string
|
|
explicitRoles []string
|
|
schemeGuest bool
|
|
schemeUser bool
|
|
schemeAdmin bool
|
|
}
|
|
|
|
func getTeamRoles(schemeGuest, schemeUser, schemeAdmin bool, defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole string, roles []string) rolesInfo {
|
|
result := rolesInfo{
|
|
roles: []string{},
|
|
explicitRoles: []string{},
|
|
schemeGuest: schemeGuest,
|
|
schemeUser: schemeUser,
|
|
schemeAdmin: schemeAdmin,
|
|
}
|
|
// Identify any scheme derived roles that are in "Roles" field due to not yet being migrated, and exclude
|
|
// them from ExplicitRoles field.
|
|
for _, role := range roles {
|
|
switch role {
|
|
case model.TEAM_GUEST_ROLE_ID:
|
|
result.schemeGuest = true
|
|
case model.TEAM_USER_ROLE_ID:
|
|
result.schemeUser = true
|
|
case model.TEAM_ADMIN_ROLE_ID:
|
|
result.schemeAdmin = true
|
|
default:
|
|
result.explicitRoles = append(result.explicitRoles, role)
|
|
result.roles = append(result.roles, role)
|
|
}
|
|
}
|
|
|
|
// Add any scheme derived roles that are not in the Roles field due to being Implicit from the Scheme, and add
|
|
// them to the Roles field for backwards compatibility reasons.
|
|
var schemeImpliedRoles []string
|
|
if result.schemeGuest {
|
|
if defaultTeamGuestRole != "" {
|
|
schemeImpliedRoles = append(schemeImpliedRoles, defaultTeamGuestRole)
|
|
} else {
|
|
schemeImpliedRoles = append(schemeImpliedRoles, model.TEAM_GUEST_ROLE_ID)
|
|
}
|
|
}
|
|
if result.schemeUser {
|
|
if defaultTeamUserRole != "" {
|
|
schemeImpliedRoles = append(schemeImpliedRoles, defaultTeamUserRole)
|
|
} else {
|
|
schemeImpliedRoles = append(schemeImpliedRoles, model.TEAM_USER_ROLE_ID)
|
|
}
|
|
}
|
|
if result.schemeAdmin {
|
|
if defaultTeamAdminRole != "" {
|
|
schemeImpliedRoles = append(schemeImpliedRoles, defaultTeamAdminRole)
|
|
} else {
|
|
schemeImpliedRoles = append(schemeImpliedRoles, model.TEAM_ADMIN_ROLE_ID)
|
|
}
|
|
}
|
|
for _, impliedRole := range schemeImpliedRoles {
|
|
alreadyThere := false
|
|
for _, role := range result.roles {
|
|
if role == impliedRole {
|
|
alreadyThere = true
|
|
}
|
|
}
|
|
if !alreadyThere {
|
|
result.roles = append(result.roles, impliedRole)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (db teamMemberWithSchemeRoles) ToModel() *model.TeamMember {
|
|
// Identify any scheme derived roles that are in "Roles" field due to not yet being migrated, and exclude
|
|
// them from ExplicitRoles field.
|
|
schemeGuest := db.SchemeGuest.Valid && db.SchemeGuest.Bool
|
|
schemeUser := db.SchemeUser.Valid && db.SchemeUser.Bool
|
|
schemeAdmin := db.SchemeAdmin.Valid && db.SchemeAdmin.Bool
|
|
|
|
defaultTeamGuestRole := ""
|
|
if db.TeamSchemeDefaultGuestRole.Valid {
|
|
defaultTeamGuestRole = db.TeamSchemeDefaultGuestRole.String
|
|
}
|
|
|
|
defaultTeamUserRole := ""
|
|
if db.TeamSchemeDefaultUserRole.Valid {
|
|
defaultTeamUserRole = db.TeamSchemeDefaultUserRole.String
|
|
}
|
|
|
|
defaultTeamAdminRole := ""
|
|
if db.TeamSchemeDefaultAdminRole.Valid {
|
|
defaultTeamAdminRole = db.TeamSchemeDefaultAdminRole.String
|
|
}
|
|
|
|
rolesResult := getTeamRoles(schemeGuest, schemeUser, schemeAdmin, defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole, strings.Fields(db.Roles))
|
|
|
|
tm := &model.TeamMember{
|
|
TeamId: db.TeamId,
|
|
UserId: db.UserId,
|
|
Roles: strings.Join(rolesResult.roles, " "),
|
|
DeleteAt: db.DeleteAt,
|
|
SchemeGuest: rolesResult.schemeGuest,
|
|
SchemeUser: rolesResult.schemeUser,
|
|
SchemeAdmin: rolesResult.schemeAdmin,
|
|
ExplicitRoles: strings.Join(rolesResult.explicitRoles, " "),
|
|
}
|
|
return tm
|
|
}
|
|
|
|
func (db teamMemberWithSchemeRolesList) ToModel() []*model.TeamMember {
|
|
tms := make([]*model.TeamMember, 0)
|
|
|
|
for _, tm := range db {
|
|
tms = append(tms, tm.ToModel())
|
|
}
|
|
|
|
return tms
|
|
}
|
|
|
|
func newSqlTeamStore(sqlStore SqlStore) store.TeamStore {
|
|
s := &SqlTeamStore{
|
|
sqlStore,
|
|
}
|
|
|
|
for _, db := range sqlStore.GetAllConns() {
|
|
table := db.AddTableWithName(model.Team{}, "Teams").SetKeys(false, "Id")
|
|
table.ColMap("Id").SetMaxSize(26)
|
|
table.ColMap("DisplayName").SetMaxSize(64)
|
|
table.ColMap("Name").SetMaxSize(64).SetUnique(true)
|
|
table.ColMap("Description").SetMaxSize(255)
|
|
table.ColMap("Email").SetMaxSize(128)
|
|
table.ColMap("CompanyName").SetMaxSize(64)
|
|
table.ColMap("AllowedDomains").SetMaxSize(1000)
|
|
table.ColMap("InviteId").SetMaxSize(32)
|
|
|
|
tablem := db.AddTableWithName(teamMember{}, "TeamMembers").SetKeys(false, "TeamId", "UserId")
|
|
tablem.ColMap("TeamId").SetMaxSize(26)
|
|
tablem.ColMap("UserId").SetMaxSize(26)
|
|
tablem.ColMap("Roles").SetMaxSize(64)
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
func (s SqlTeamStore) createIndexesIfNotExists() {
|
|
s.CreateIndexIfNotExists("idx_teams_name", "Teams", "Name")
|
|
s.RemoveIndexIfExists("idx_teams_description", "Teams")
|
|
s.CreateIndexIfNotExists("idx_teams_invite_id", "Teams", "InviteId")
|
|
s.CreateIndexIfNotExists("idx_teams_update_at", "Teams", "UpdateAt")
|
|
s.CreateIndexIfNotExists("idx_teams_create_at", "Teams", "CreateAt")
|
|
s.CreateIndexIfNotExists("idx_teams_delete_at", "Teams", "DeleteAt")
|
|
s.CreateIndexIfNotExists("idx_teams_scheme_id", "Teams", "SchemeId")
|
|
|
|
s.CreateIndexIfNotExists("idx_teammembers_team_id", "TeamMembers", "TeamId")
|
|
s.CreateIndexIfNotExists("idx_teammembers_user_id", "TeamMembers", "UserId")
|
|
s.CreateIndexIfNotExists("idx_teammembers_delete_at", "TeamMembers", "DeleteAt")
|
|
}
|
|
|
|
// Save adds the team to the database if a team with the same name does not already
|
|
// exist in the database. It returns the team added if the operation is successful.
|
|
func (s SqlTeamStore) Save(team *model.Team) (*model.Team, *model.AppError) {
|
|
if len(team.Id) > 0 {
|
|
return nil, model.NewAppError("SqlTeamStore.Save",
|
|
"store.sql_team.save.existing.app_error", nil, "id="+team.Id, http.StatusBadRequest)
|
|
}
|
|
|
|
team.PreSave()
|
|
|
|
if err := team.IsValid(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := s.GetMaster().Insert(team); err != nil {
|
|
if IsUniqueConstraintError(err, []string{"Name", "teams_name_key"}) {
|
|
return nil, model.NewAppError("SqlTeamStore.Save", "store.sql_team.save.domain_exists.app_error", nil, "id="+team.Id+", "+err.Error(), http.StatusBadRequest)
|
|
}
|
|
return nil, model.NewAppError("SqlTeamStore.Save", "store.sql_team.save.app_error", nil, "id="+team.Id+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return team, nil
|
|
}
|
|
|
|
// Update updates the details of the team passed as the parameter using the team Id
|
|
// if the team exists in the database.
|
|
// It returns the updated team if the operation is successful.
|
|
func (s SqlTeamStore) Update(team *model.Team) (*model.Team, *model.AppError) {
|
|
|
|
team.PreUpdate()
|
|
|
|
if err := team.IsValid(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
oldResult, err := s.GetMaster().Get(model.Team{}, team.Id)
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.finding.app_error", nil, "id="+team.Id+", "+err.Error(), http.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
if oldResult == nil {
|
|
return nil, model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.find.app_error", nil, "id="+team.Id, http.StatusBadRequest)
|
|
}
|
|
|
|
oldTeam := oldResult.(*model.Team)
|
|
team.CreateAt = oldTeam.CreateAt
|
|
team.UpdateAt = model.GetMillis()
|
|
|
|
count, err := s.GetMaster().Update(team)
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.updating.app_error", nil, "id="+team.Id+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
if count != 1 {
|
|
return nil, model.NewAppError("SqlTeamStore.Update", "store.sql_team.update.app_error", nil, "id="+team.Id, http.StatusInternalServerError)
|
|
}
|
|
|
|
return team, nil
|
|
}
|
|
|
|
// Get returns from the database the team that matches the id provided as parameter.
|
|
// If the team doesn't exist it returns a model.AppError with a
|
|
// http.StatusNotFound in the StatusCode field.
|
|
func (s SqlTeamStore) Get(id string) (*model.Team, *model.AppError) {
|
|
obj, err := s.GetReplica().Get(model.Team{}, id)
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.Get", "store.sql_team.get.finding.app_error", nil, "id="+id+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
if obj == nil {
|
|
return nil, model.NewAppError("SqlTeamStore.Get", "store.sql_team.get.find.app_error", nil, "id="+id, http.StatusNotFound)
|
|
}
|
|
|
|
return obj.(*model.Team), nil
|
|
}
|
|
|
|
// GetByInviteId returns from the database the team that matches the inviteId provided as parameter.
|
|
// If the parameter provided is empty or if there is no match in the database, it returns a model.AppError
|
|
// with a http.StatusNotFound in the StatusCode field.
|
|
func (s SqlTeamStore) GetByInviteId(inviteId string) (*model.Team, *model.AppError) {
|
|
team := model.Team{}
|
|
|
|
err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE InviteId = :InviteId", map[string]interface{}{"InviteId": inviteId})
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetByInviteId", "store.sql_team.get_by_invite_id.finding.app_error", nil, "inviteId="+inviteId+", "+err.Error(), http.StatusNotFound)
|
|
}
|
|
|
|
if len(inviteId) == 0 || team.InviteId != inviteId {
|
|
return nil, model.NewAppError("SqlTeamStore.GetByInviteId", "store.sql_team.get_by_invite_id.find.app_error", nil, "inviteId="+inviteId, http.StatusNotFound)
|
|
}
|
|
return &team, nil
|
|
}
|
|
|
|
// GetByName returns from the database the team that matches the name provided as parameter.
|
|
// If there is no match in the database, it returns a model.AppError with a
|
|
// http.StatusNotFound in the StatusCode field.
|
|
func (s SqlTeamStore) GetByName(name string) (*model.Team, *model.AppError) {
|
|
|
|
team := model.Team{}
|
|
|
|
err := s.GetReplica().SelectOne(&team, "SELECT * FROM Teams WHERE Name = :Name", map[string]interface{}{"Name": name})
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return nil, model.NewAppError("SqlTeamStore.GetByName", "store.sql_team.get_by_name.missing.app_error", nil, "name="+name+","+err.Error(), http.StatusNotFound)
|
|
}
|
|
return nil, model.NewAppError("SqlTeamStore.GetByName", "store.sql_team.get_by_name.app_error", nil, "name="+name+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return &team, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) GetByNames(names []string) ([]*model.Team, *model.AppError) {
|
|
uniqueNames := utils.RemoveDuplicatesFromStringArray(names)
|
|
|
|
query := s.getQueryBuilder().
|
|
Select("*").
|
|
From("Teams").
|
|
Where(sq.Eq{"Name": uniqueNames})
|
|
|
|
queryString, args, err := query.ToSql()
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetByNames", "store.sql_team.get_by_names.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
teams := []*model.Team{}
|
|
_, err = s.GetReplica().Select(&teams, queryString, args...)
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return nil, model.NewAppError("SqlTeamStore.GetByNames", "store.sql_team.get_by_names.missing.app_error", nil, err.Error(), http.StatusNotFound)
|
|
}
|
|
return nil, model.NewAppError("SqlTeamStore.GetByNames", "store.sql_team.get_by_names.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
if len(teams) != len(uniqueNames) {
|
|
return nil, model.NewAppError("SqlTeamStore.GetByNames", "store.sql_team.get_by_names.missing.app_error", nil, "", http.StatusNotFound)
|
|
}
|
|
return teams, nil
|
|
}
|
|
|
|
// SearchAll returns from the database a list of teams that match the Name or DisplayName
|
|
// passed as the term search parameter.
|
|
func (s SqlTeamStore) SearchAll(term string) ([]*model.Team, *model.AppError) {
|
|
var teams []*model.Team
|
|
|
|
term = sanitizeSearchTerm(term, "\\")
|
|
term = wildcardSearchTerm(term)
|
|
|
|
operatorKeyword := "ILIKE"
|
|
if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
|
operatorKeyword = "LIKE"
|
|
}
|
|
queryString := fmt.Sprintf("SELECT * FROM Teams WHERE Name %[1]s :Term OR DisplayName %[1]s :Term", operatorKeyword)
|
|
if _, err := s.GetReplica().Select(&teams, queryString, map[string]interface{}{"Term": term}); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.SearchAll", "store.sql_team.search_all_team.app_error", nil, "term="+term+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return teams, nil
|
|
}
|
|
|
|
// SearchAllPaged returns a teams list and the total count of teams that matched the search.
|
|
func (s SqlTeamStore) SearchAllPaged(term string, page int, perPage int) ([]*model.Team, int64, *model.AppError) {
|
|
var teams []*model.Team
|
|
var totalCount int64
|
|
offset := page * perPage
|
|
|
|
term = sanitizeSearchTerm(term, "\\")
|
|
term = wildcardSearchTerm(term)
|
|
operatorKeyword := "ILIKE"
|
|
if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
|
operatorKeyword = "LIKE"
|
|
}
|
|
queryString := fmt.Sprintf("SELECT * FROM Teams WHERE Name %[1]s :Term OR DisplayName %[1]s :Term ORDER BY DisplayName, Name LIMIT :Limit OFFSET :Offset", operatorKeyword)
|
|
if _, err := s.GetReplica().Select(&teams, queryString, map[string]interface{}{"Term": term, "Limit": perPage, "Offset": offset}); err != nil {
|
|
return nil, 0, model.NewAppError("SqlTeamStore.SearchAllPage", "store.sql_team.search_all_team.app_error", nil, "term="+term+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
queryString = fmt.Sprintf("SELECT COUNT(*) FROM Teams WHERE Name %[1]s :Term OR DisplayName %[1]s :Term", operatorKeyword)
|
|
totalCount, err := s.GetReplica().SelectInt(queryString, map[string]interface{}{"Term": term})
|
|
if err != nil {
|
|
return nil, 0, model.NewAppError("SqlTeamStore.SearchAllPage", "store.sql_team.search_all_team.app_error", nil, "term="+term+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return teams, totalCount, nil
|
|
}
|
|
|
|
// SearchOpen returns from the database a list of public teams that match the Name or DisplayName
|
|
// passed as the term search parameter.
|
|
func (s SqlTeamStore) SearchOpen(term string) ([]*model.Team, *model.AppError) {
|
|
var teams []*model.Team
|
|
|
|
term = sanitizeSearchTerm(term, "\\")
|
|
term = wildcardSearchTerm(term)
|
|
operatorKeyword := "ILIKE"
|
|
if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
|
operatorKeyword = "LIKE"
|
|
}
|
|
queryString := fmt.Sprintf("SELECT * FROM Teams WHERE Type = 'O' AND AllowOpenInvite = true AND (Name %[1]s :Term OR DisplayName %[1]s :Term)", operatorKeyword)
|
|
if _, err := s.GetReplica().Select(&teams, queryString, map[string]interface{}{"Term": term}); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.SearchOpen", "store.sql_team.search_open_team.app_error", nil, "term="+term+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return teams, nil
|
|
}
|
|
|
|
// SearchPrivate returns from the database a list of private teams that match the Name or DisplayName
|
|
// passed as the term search parameter.
|
|
func (s SqlTeamStore) SearchPrivate(term string) ([]*model.Team, *model.AppError) {
|
|
var teams []*model.Team
|
|
|
|
term = sanitizeSearchTerm(term, "\\")
|
|
term = wildcardSearchTerm(term)
|
|
operatorKeyword := "ILIKE"
|
|
if s.DriverName() == model.DATABASE_DRIVER_MYSQL {
|
|
operatorKeyword = "LIKE"
|
|
}
|
|
query := fmt.Sprintf(`
|
|
SELECT *
|
|
FROM
|
|
Teams
|
|
WHERE
|
|
(Type != 'O' OR AllowOpenInvite = false) AND
|
|
(Name %[1]s :Term OR DisplayName %[1]s :Term)`, operatorKeyword)
|
|
if _, err := s.GetReplica().Select(&teams, query, map[string]interface{}{"Term": term}); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.SearchPrivate", "store.sql_team.search_private_team.app_error", nil, "term="+term+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return teams, nil
|
|
}
|
|
|
|
// GetAll returns all teams
|
|
func (s SqlTeamStore) GetAll() ([]*model.Team, *model.AppError) {
|
|
var teams []*model.Team
|
|
|
|
_, err := s.GetReplica().Select(&teams, "SELECT * FROM Teams ORDER BY DisplayName")
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return teams, nil
|
|
}
|
|
|
|
// GetAllPage returns teams, up to a total limit passed as parameter and paginated by offset number passed as parameter.
|
|
func (s SqlTeamStore) GetAllPage(offset int, limit int) ([]*model.Team, *model.AppError) {
|
|
var teams []*model.Team
|
|
|
|
if _, err := s.GetReplica().Select(&teams,
|
|
`SELECT
|
|
*
|
|
FROM
|
|
Teams
|
|
ORDER BY
|
|
DisplayName
|
|
LIMIT
|
|
:Limit
|
|
OFFSET
|
|
:Offset`, map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetAllTeams",
|
|
"store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return teams, nil
|
|
}
|
|
|
|
// GetTeamsByUserId returns from the database all teams that userId belongs to.
|
|
func (s SqlTeamStore) GetTeamsByUserId(userId string) ([]*model.Team, *model.AppError) {
|
|
var teams []*model.Team
|
|
if _, err := s.GetReplica().Select(&teams, "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 {
|
|
return nil, model.NewAppError("SqlTeamStore.GetTeamsByUserId", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return teams, nil
|
|
}
|
|
|
|
// GetAllPrivateTeamListing returns all private teams.
|
|
func (s SqlTeamStore) GetAllPrivateTeamListing() ([]*model.Team, *model.AppError) {
|
|
query := "SELECT * FROM Teams WHERE AllowOpenInvite = 0 ORDER BY DisplayName"
|
|
|
|
if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
|
query = "SELECT * FROM Teams WHERE AllowOpenInvite = false ORDER BY DisplayName"
|
|
}
|
|
|
|
var data []*model.Team
|
|
if _, err := s.GetReplica().Select(&data, query); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetAllPrivateTeamListing", "store.sql_team.get_all_private_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
// GetAllPublicTeamPageListing returns public teams, up to a total limit passed as parameter and paginated by offset number passed as parameter.
|
|
func (s SqlTeamStore) GetAllPublicTeamPageListing(offset int, limit int) ([]*model.Team, *model.AppError) {
|
|
query := "SELECT * FROM Teams WHERE AllowOpenInvite = 1 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
|
|
|
|
if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
|
query = "SELECT * FROM Teams WHERE AllowOpenInvite = true ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
|
|
}
|
|
|
|
var data []*model.Team
|
|
if _, err := s.GetReplica().Select(&data, query, map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetAllPrivateTeamListing", "store.sql_team.get_all_private_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
// GetAllPrivateTeamPageListing returns private teams, up to a total limit passed as paramater and paginated by offset number passed as parameter.
|
|
func (s SqlTeamStore) GetAllPrivateTeamPageListing(offset int, limit int) ([]*model.Team, *model.AppError) {
|
|
query := "SELECT * FROM Teams WHERE AllowOpenInvite = 0 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
|
|
|
|
if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
|
query = "SELECT * FROM Teams WHERE AllowOpenInvite = false ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
|
|
}
|
|
|
|
var data []*model.Team
|
|
if _, err := s.GetReplica().Select(&data, query, map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetAllPrivateTeamListing", "store.sql_team.get_all_private_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
// GetAllTeamListing returns all public teams.
|
|
func (s SqlTeamStore) GetAllTeamListing() ([]*model.Team, *model.AppError) {
|
|
query := "SELECT * FROM Teams WHERE AllowOpenInvite = 1 ORDER BY DisplayName"
|
|
|
|
if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
|
query = "SELECT * FROM Teams WHERE AllowOpenInvite = true ORDER BY DisplayName"
|
|
}
|
|
|
|
var data []*model.Team
|
|
if _, err := s.GetReplica().Select(&data, query); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetAllTeamListing", "store.sql_team.get_all_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
// GetAllTeamPageListing returns public teams, up to a total limit passed as parameter and paginated by offset number passed as parameter.
|
|
func (s SqlTeamStore) GetAllTeamPageListing(offset int, limit int) ([]*model.Team, *model.AppError) {
|
|
query := "SELECT * FROM Teams WHERE AllowOpenInvite = 1 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
|
|
|
|
if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
|
query = "SELECT * FROM Teams WHERE AllowOpenInvite = true ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
|
|
}
|
|
|
|
var teams []*model.Team
|
|
if _, err := s.GetReplica().Select(&teams, query, map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetAllTeamListing", "store.sql_team.get_all_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return teams, nil
|
|
}
|
|
|
|
// PermanentDelete permanently deletes from the database the team entry that matches the teamId passed as parameter.
|
|
// To soft-delete the team you can Update it with the DeleteAt field set to the current millisecond using model.GetMillis()
|
|
func (s SqlTeamStore) PermanentDelete(teamId string) *model.AppError {
|
|
if _, err := s.GetMaster().Exec("DELETE FROM Teams WHERE Id = :TeamId", map[string]interface{}{"TeamId": teamId}); err != nil {
|
|
return model.NewAppError("SqlTeamStore.Delete", "store.sql_team.permanent_delete.app_error", nil, "teamId="+teamId+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AnalyticsPublicTeamCount returns the number of active public teams.
|
|
func (s SqlTeamStore) AnalyticsPublicTeamCount() (int64, *model.AppError) {
|
|
|
|
c, err := s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0 AND AllowOpenInvite = 1", map[string]interface{}{})
|
|
|
|
if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
|
c, err = s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0 AND AllowOpenInvite = true", map[string]interface{}{})
|
|
}
|
|
|
|
if err != nil {
|
|
return int64(0), model.NewAppError("SqlTeamStore.AnalyticsPublicTeamCount", "store.sql_team.analytics_public_team_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// AnalyticsPrivateTeamCount returns the number of active private teams.
|
|
func (s SqlTeamStore) AnalyticsPrivateTeamCount() (int64, *model.AppError) {
|
|
c, err := s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0 AND AllowOpenInvite = 0", map[string]interface{}{})
|
|
|
|
if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
|
|
c, err = s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0 AND AllowOpenInvite = false", map[string]interface{}{})
|
|
}
|
|
|
|
if err != nil {
|
|
return int64(0), model.NewAppError("SqlTeamStore.AnalyticsPrivateTeamCount", "store.sql_team.analytics_private_team_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// AnalyticsTeamCount returns the total number of teams including deleted teams if parameter passed is set to 'true'.
|
|
func (s SqlTeamStore) AnalyticsTeamCount(includeDeleted bool) (int64, *model.AppError) {
|
|
query := s.getQueryBuilder().Select("COUNT(*) FROM Teams")
|
|
if !includeDeleted {
|
|
query = query.Where(sq.Eq{"DeleteAt": 0})
|
|
}
|
|
|
|
queryString, args, err := query.ToSql()
|
|
if err != nil {
|
|
return 0, model.NewAppError("SqlTeamStore.AnalyticsTeamCount", "store.sql_team.analytics_team_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
c, err := s.GetReplica().SelectInt(queryString, args...)
|
|
|
|
if err != nil {
|
|
return int64(0), model.NewAppError("SqlTeamStore.AnalyticsTeamCount", "store.sql_team.analytics_team_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) getTeamMembersWithSchemeSelectQuery() sq.SelectBuilder {
|
|
return s.getQueryBuilder().
|
|
Select(
|
|
"TeamMembers.*",
|
|
"TeamScheme.DefaultTeamGuestRole TeamSchemeDefaultGuestRole",
|
|
"TeamScheme.DefaultTeamUserRole TeamSchemeDefaultUserRole",
|
|
"TeamScheme.DefaultTeamAdminRole TeamSchemeDefaultAdminRole",
|
|
).
|
|
From("TeamMembers").
|
|
LeftJoin("Teams ON TeamMembers.TeamId = Teams.Id").
|
|
LeftJoin("Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id")
|
|
}
|
|
|
|
func (s SqlTeamStore) SaveMultipleMembers(members []*model.TeamMember, maxUsersPerTeam int) ([]*model.TeamMember, *model.AppError) {
|
|
newTeamMembers := map[string]int{}
|
|
users := map[string]bool{}
|
|
for _, member := range members {
|
|
newTeamMembers[member.TeamId] = 0
|
|
}
|
|
|
|
for _, member := range members {
|
|
newTeamMembers[member.TeamId]++
|
|
users[member.UserId] = true
|
|
|
|
if err := member.IsValid(); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
teams := []string{}
|
|
for team := range newTeamMembers {
|
|
teams = append(teams, team)
|
|
}
|
|
|
|
defaultTeamRolesByTeam := map[string]struct {
|
|
Id string
|
|
Guest sql.NullString
|
|
User sql.NullString
|
|
Admin sql.NullString
|
|
}{}
|
|
|
|
queryRoles := s.getQueryBuilder().
|
|
Select(
|
|
"Teams.Id as Id",
|
|
"TeamScheme.DefaultTeamGuestRole as Guest",
|
|
"TeamScheme.DefaultTeamUserRole as User",
|
|
"TeamScheme.DefaultTeamAdminRole as Admin",
|
|
).
|
|
From("Teams").
|
|
LeftJoin("Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id").
|
|
Where(sq.Eq{"Teams.Id": teams})
|
|
|
|
sqlRolesQuery, argsRoles, err := queryRoles.ToSql()
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
var defaultTeamsRoles []struct {
|
|
Id string
|
|
Guest sql.NullString
|
|
User sql.NullString
|
|
Admin sql.NullString
|
|
}
|
|
_, err = s.GetMaster().Select(&defaultTeamsRoles, sqlRolesQuery, argsRoles...)
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
for _, defaultRoles := range defaultTeamsRoles {
|
|
defaultTeamRolesByTeam[defaultRoles.Id] = defaultRoles
|
|
}
|
|
|
|
if maxUsersPerTeam >= 0 {
|
|
queryCount := s.getQueryBuilder().
|
|
Select(
|
|
"COUNT(0) as Count, TeamMembers.TeamId as TeamId",
|
|
).
|
|
From("TeamMembers").
|
|
Join("Users ON TeamMembers.UserId = Users.Id").
|
|
Where(sq.Eq{"TeamMembers.TeamId": teams}).
|
|
Where(sq.Eq{"TeamMembers.DeleteAt": 0}).
|
|
Where(sq.Eq{"Users.DeleteAt": 0}).
|
|
GroupBy("TeamMembers.TeamId")
|
|
|
|
sqlCountQuery, argsCount, errCount := queryCount.ToSql()
|
|
if errCount != nil {
|
|
return nil, model.NewAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, errCount.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
var counters []struct {
|
|
Count int `db:"Count"`
|
|
TeamId string `db:"TeamId"`
|
|
}
|
|
|
|
_, err = s.GetMaster().Select(&counters, sqlCountQuery, argsCount...)
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
for teamId, newMembers := range newTeamMembers {
|
|
existingMembers := 0
|
|
for _, counter := range counters {
|
|
if counter.TeamId == teamId {
|
|
existingMembers = counter.Count
|
|
}
|
|
}
|
|
if existingMembers+newMembers > maxUsersPerTeam {
|
|
return nil, model.NewAppError("SqlUserStore.Save", "store.sql_user.save.max_accounts.app_error", nil, "", http.StatusBadRequest)
|
|
}
|
|
}
|
|
}
|
|
|
|
query := s.getQueryBuilder().Insert("TeamMembers").Columns(teamMemberSliceColumns()...)
|
|
for _, member := range members {
|
|
query = query.Values(teamMemberToSlice(member)...)
|
|
}
|
|
|
|
sql, args, err := query.ToSql()
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.SaveMember", "store.sql_team.save_member.save.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
if _, err := s.GetMaster().Exec(sql, args...); err != nil {
|
|
if IsUniqueConstraintError(err, []string{"TeamId", "teammembers_pkey", "PRIMARY"}) {
|
|
return nil, model.NewAppError("SqlTeamStore.SaveMember", TEAM_MEMBER_EXISTS_ERROR, nil, err.Error(), http.StatusBadRequest)
|
|
}
|
|
return nil, model.NewAppError("SqlTeamStore.SaveMember", "store.sql_team.save_member.save.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
newMembers := []*model.TeamMember{}
|
|
for _, member := range members {
|
|
s.InvalidateAllTeamIdsForUser(member.UserId)
|
|
defaultTeamGuestRole := defaultTeamRolesByTeam[member.TeamId].Guest.String
|
|
defaultTeamUserRole := defaultTeamRolesByTeam[member.TeamId].User.String
|
|
defaultTeamAdminRole := defaultTeamRolesByTeam[member.TeamId].Admin.String
|
|
rolesResult := getTeamRoles(member.SchemeGuest, member.SchemeUser, member.SchemeAdmin, defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole, strings.Fields(member.ExplicitRoles))
|
|
newMember := *member
|
|
newMember.SchemeGuest = rolesResult.schemeGuest
|
|
newMember.SchemeUser = rolesResult.schemeUser
|
|
newMember.SchemeAdmin = rolesResult.schemeAdmin
|
|
newMember.Roles = strings.Join(rolesResult.roles, " ")
|
|
newMember.ExplicitRoles = strings.Join(rolesResult.explicitRoles, " ")
|
|
newMembers = append(newMembers, &newMember)
|
|
}
|
|
|
|
return newMembers, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) SaveMember(member *model.TeamMember, maxUsersPerTeam int) (*model.TeamMember, *model.AppError) {
|
|
members, err := s.SaveMultipleMembers([]*model.TeamMember{member}, maxUsersPerTeam)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return members[0], nil
|
|
}
|
|
|
|
func (s SqlTeamStore) UpdateMultipleMembers(members []*model.TeamMember) ([]*model.TeamMember, *model.AppError) {
|
|
teams := []string{}
|
|
for _, member := range members {
|
|
member.PreUpdate()
|
|
|
|
if err := member.IsValid(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if _, err := s.GetMaster().Update(NewTeamMemberFromModel(member)); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.UpdateMember", "store.sql_team.save_member.save.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
teams = append(teams, member.TeamId)
|
|
}
|
|
|
|
query := s.getQueryBuilder().
|
|
Select(
|
|
"Teams.Id as Id",
|
|
"TeamScheme.DefaultTeamGuestRole as Guest",
|
|
"TeamScheme.DefaultTeamUserRole as User",
|
|
"TeamScheme.DefaultTeamAdminRole as Admin",
|
|
).
|
|
From("Teams").
|
|
LeftJoin("Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id").
|
|
Where(sq.Eq{"Teams.Id": teams})
|
|
|
|
sqlQuery, args, err := query.ToSql()
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
var defaultTeamsRoles []struct {
|
|
Id string
|
|
Guest sql.NullString
|
|
User sql.NullString
|
|
Admin sql.NullString
|
|
}
|
|
_, err = s.GetMaster().Select(&defaultTeamsRoles, sqlQuery, args...)
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlUserStore.Save", "store.sql_user.save.member_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
defaultTeamRolesByTeam := map[string]struct {
|
|
Id string
|
|
Guest sql.NullString
|
|
User sql.NullString
|
|
Admin sql.NullString
|
|
}{}
|
|
for _, defaultRoles := range defaultTeamsRoles {
|
|
defaultTeamRolesByTeam[defaultRoles.Id] = defaultRoles
|
|
}
|
|
|
|
updatedMembers := []*model.TeamMember{}
|
|
for _, member := range members {
|
|
s.InvalidateAllTeamIdsForUser(member.UserId)
|
|
defaultTeamGuestRole := defaultTeamRolesByTeam[member.TeamId].Guest.String
|
|
defaultTeamUserRole := defaultTeamRolesByTeam[member.TeamId].User.String
|
|
defaultTeamAdminRole := defaultTeamRolesByTeam[member.TeamId].Admin.String
|
|
rolesResult := getTeamRoles(member.SchemeGuest, member.SchemeUser, member.SchemeAdmin, defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole, strings.Fields(member.ExplicitRoles))
|
|
updatedMember := *member
|
|
updatedMember.SchemeGuest = rolesResult.schemeGuest
|
|
updatedMember.SchemeUser = rolesResult.schemeUser
|
|
updatedMember.SchemeAdmin = rolesResult.schemeAdmin
|
|
updatedMember.Roles = strings.Join(rolesResult.roles, " ")
|
|
updatedMember.ExplicitRoles = strings.Join(rolesResult.explicitRoles, " ")
|
|
updatedMembers = append(updatedMembers, &updatedMember)
|
|
}
|
|
|
|
return updatedMembers, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) UpdateMember(member *model.TeamMember) (*model.TeamMember, *model.AppError) {
|
|
members, err := s.UpdateMultipleMembers([]*model.TeamMember{member})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return members[0], nil
|
|
}
|
|
|
|
func (s SqlTeamStore) GetMember(teamId string, userId string) (*model.TeamMember, *model.AppError) {
|
|
query := s.getTeamMembersWithSchemeSelectQuery().
|
|
Where(sq.Eq{"TeamMembers.TeamId": teamId}).
|
|
Where(sq.Eq{"TeamMembers.UserId": userId})
|
|
|
|
queryString, args, err := query.ToSql()
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetMember", "store.sql_team.get_member.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
var dbMember teamMemberWithSchemeRoles
|
|
err = s.GetReplica().SelectOne(&dbMember, queryString, args...)
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
return nil, model.NewAppError("SqlTeamStore.GetMember", "store.sql_team.get_member.missing.app_error", nil, "teamId="+teamId+" userId="+userId+" "+err.Error(), http.StatusNotFound)
|
|
}
|
|
return nil, model.NewAppError("SqlTeamStore.GetMember", "store.sql_team.get_member.app_error", nil, "teamId="+teamId+" userId="+userId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return dbMember.ToModel(), nil
|
|
}
|
|
|
|
func (s SqlTeamStore) GetMembers(teamId string, offset int, limit int, teamMembersGetOptions *model.TeamMembersGetOptions) ([]*model.TeamMember, *model.AppError) {
|
|
query := s.getTeamMembersWithSchemeSelectQuery().
|
|
Where(sq.Eq{"TeamMembers.TeamId": teamId}).
|
|
Where(sq.Eq{"TeamMembers.DeleteAt": 0}).
|
|
Limit(uint64(limit)).
|
|
Offset(uint64(offset))
|
|
|
|
if teamMembersGetOptions == nil || teamMembersGetOptions.Sort == "" {
|
|
query = query.OrderBy("UserId")
|
|
}
|
|
|
|
if teamMembersGetOptions != nil {
|
|
if teamMembersGetOptions.Sort == model.USERNAME || teamMembersGetOptions.ExcludeDeletedUsers {
|
|
query = query.LeftJoin("Users ON TeamMembers.UserId = Users.Id")
|
|
}
|
|
|
|
if teamMembersGetOptions.ExcludeDeletedUsers {
|
|
query = query.Where(sq.Eq{"Users.DeleteAt": 0})
|
|
}
|
|
|
|
if teamMembersGetOptions.Sort == model.USERNAME {
|
|
query = query.OrderBy(model.USERNAME)
|
|
}
|
|
|
|
query = applyTeamMemberViewRestrictionsFilter(query, teamId, teamMembersGetOptions.ViewRestrictions)
|
|
}
|
|
|
|
queryString, args, err := query.ToSql()
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
var dbMembers teamMemberWithSchemeRolesList
|
|
_, err = s.GetReplica().Select(&dbMembers, queryString, args...)
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return dbMembers.ToModel(), nil
|
|
}
|
|
|
|
func (s SqlTeamStore) GetTotalMemberCount(teamId string, restrictions *model.ViewUsersRestrictions) (int64, *model.AppError) {
|
|
query := s.getQueryBuilder().
|
|
Select("count(DISTINCT TeamMembers.UserId)").
|
|
From("TeamMembers, Users").
|
|
Where("TeamMembers.DeleteAt = 0").
|
|
Where("TeamMembers.UserId = Users.Id").
|
|
Where(sq.Eq{"TeamMembers.TeamId": teamId})
|
|
|
|
query = applyTeamMemberViewRestrictionsFilterForStats(query, teamId, restrictions)
|
|
queryString, args, err := query.ToSql()
|
|
if err != nil {
|
|
return int64(0), model.NewAppError("SqlTeamStore.GetTotalMemberCount", "store.sql_team.get_member_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
count, err := s.GetReplica().SelectInt(queryString, args...)
|
|
if err != nil {
|
|
return int64(0), model.NewAppError("SqlTeamStore.GetTotalMemberCount", "store.sql_team.get_member_count.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) GetActiveMemberCount(teamId string, restrictions *model.ViewUsersRestrictions) (int64, *model.AppError) {
|
|
query := s.getQueryBuilder().
|
|
Select("count(DISTINCT TeamMembers.UserId)").
|
|
From("TeamMembers, Users").
|
|
Where("TeamMembers.DeleteAt = 0").
|
|
Where("TeamMembers.UserId = Users.Id").
|
|
Where("Users.DeleteAt = 0").
|
|
Where(sq.Eq{"TeamMembers.TeamId": teamId})
|
|
|
|
query = applyTeamMemberViewRestrictionsFilterForStats(query, teamId, restrictions)
|
|
queryString, args, err := query.ToSql()
|
|
if err != nil {
|
|
return 0, model.NewAppError("SqlTeamStore.GetActiveMemberCount", "store.sql_team.get_active_member_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
count, err := s.GetReplica().SelectInt(queryString, args...)
|
|
if err != nil {
|
|
return 0, model.NewAppError("SqlTeamStore.GetActiveMemberCount", "store.sql_team.get_active_member_count.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) GetMembersByIds(teamId string, userIds []string, restrictions *model.ViewUsersRestrictions) ([]*model.TeamMember, *model.AppError) {
|
|
if len(userIds) == 0 {
|
|
return nil, model.NewAppError("SqlTeamStore.GetMembersByIds", "store.sql_team.get_members_by_ids.app_error", nil, "Invalid list of user ids", http.StatusInternalServerError)
|
|
}
|
|
|
|
query := s.getTeamMembersWithSchemeSelectQuery().
|
|
Where(sq.Eq{"TeamMembers.TeamId": teamId}).
|
|
Where(sq.Eq{"TeamMembers.UserId": userIds}).
|
|
Where(sq.Eq{"TeamMembers.DeleteAt": 0})
|
|
|
|
query = applyTeamMemberViewRestrictionsFilter(query, teamId, restrictions)
|
|
|
|
queryString, args, err := query.ToSql()
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetMembersByIds", "store.sql_team.get_members_by_ids.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
var dbMembers teamMemberWithSchemeRolesList
|
|
if _, err := s.GetReplica().Select(&dbMembers, queryString, args...); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetMembersByIds", "store.sql_team.get_members_by_ids.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return dbMembers.ToModel(), nil
|
|
}
|
|
|
|
func (s SqlTeamStore) GetTeamsForUser(userId string) ([]*model.TeamMember, *model.AppError) {
|
|
query := s.getTeamMembersWithSchemeSelectQuery().
|
|
Where(sq.Eq{"TeamMembers.UserId": userId})
|
|
|
|
queryString, args, err := query.ToSql()
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
var dbMembers teamMemberWithSchemeRolesList
|
|
_, err = s.GetReplica().Select(&dbMembers, queryString, args...)
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetMembers", "store.sql_team.get_members.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return dbMembers.ToModel(), nil
|
|
}
|
|
|
|
func (s SqlTeamStore) GetTeamsForUserWithPagination(userId string, page, perPage int) ([]*model.TeamMember, *model.AppError) {
|
|
query := s.getTeamMembersWithSchemeSelectQuery().
|
|
Where(sq.Eq{"TeamMembers.UserId": userId}).
|
|
Limit(uint64(perPage)).
|
|
Offset(uint64(page * perPage))
|
|
|
|
queryString, args, err := query.ToSql()
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetTeamsForUserWithPagination", "store.sql_team.get_members.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
var dbMembers teamMemberWithSchemeRolesList
|
|
_, err = s.GetReplica().Select(&dbMembers, queryString, args...)
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetTeamsForUserWithPagination", "store.sql_team.get_members.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return dbMembers.ToModel(), nil
|
|
}
|
|
|
|
func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string) ([]*model.ChannelUnread, *model.AppError) {
|
|
var data []*model.ChannelUnread
|
|
_, err := s.GetReplica().Select(&data,
|
|
`SELECT
|
|
Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps
|
|
FROM
|
|
Channels, ChannelMembers
|
|
WHERE
|
|
Id = ChannelId
|
|
AND UserId = :UserId
|
|
AND DeleteAt = 0
|
|
AND TeamId != :TeamId`,
|
|
map[string]interface{}{"UserId": userId, "TeamId": excludeTeamId})
|
|
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetChannelUnreadsForAllTeams", "store.sql_team.get_unread.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) GetChannelUnreadsForTeam(teamId, userId string) ([]*model.ChannelUnread, *model.AppError) {
|
|
query := `
|
|
SELECT
|
|
Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps
|
|
FROM
|
|
Channels, ChannelMembers
|
|
WHERE
|
|
Id = ChannelId
|
|
AND UserId = :UserId
|
|
AND TeamId = :TeamId
|
|
AND DeleteAt = 0`
|
|
|
|
var channels []*model.ChannelUnread
|
|
_, err := s.GetReplica().Select(&channels, query, map[string]interface{}{"TeamId": teamId, "UserId": userId})
|
|
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetChannelUnreadsForTeam", "store.sql_team.get_unread.app_error", nil, "teamId="+teamId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return channels, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) RemoveMembers(teamId string, userIds []string) *model.AppError {
|
|
query := s.getQueryBuilder().
|
|
Delete("TeamMembers").
|
|
Where(sq.Eq{"TeamId": teamId}).
|
|
Where(sq.Eq{"UserId": userIds})
|
|
|
|
sql, args, err := query.ToSql()
|
|
if err != nil {
|
|
return model.NewAppError("SqlTeamStore.RemoveMembers", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
_, err = s.GetMaster().Exec(sql, args...)
|
|
if err != nil {
|
|
return model.NewAppError("SqlTeamStore.RemoveMembers", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RemoveMember remove from the database the team members that match the userId and teamId passed as parameter.
|
|
func (s SqlTeamStore) RemoveMember(teamId string, userId string) *model.AppError {
|
|
return s.RemoveMembers(teamId, []string{userId})
|
|
}
|
|
|
|
// RemoveAllMembersByTeam removes from the database the team members that belong to the teamId passed as parameter.
|
|
func (s SqlTeamStore) RemoveAllMembersByTeam(teamId string) *model.AppError {
|
|
_, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE TeamId = :TeamId", map[string]interface{}{"TeamId": teamId})
|
|
if err != nil {
|
|
return model.NewAppError("SqlTeamStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "team_id="+teamId+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RemoveAllMembersByUser removes from the database the team members that match the userId passed as parameter.
|
|
func (s SqlTeamStore) RemoveAllMembersByUser(userId string) *model.AppError {
|
|
_, err := s.GetMaster().Exec("DELETE FROM TeamMembers WHERE UserId = :UserId", map[string]interface{}{"UserId": userId})
|
|
if err != nil {
|
|
return model.NewAppError("SqlTeamStore.RemoveMember", "store.sql_team.remove_member.app_error", nil, "user_id="+userId+", "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s SqlTeamStore) UpdateLastTeamIconUpdate(teamId string, curTime int64) *model.AppError {
|
|
if _, err := s.GetMaster().Exec("UPDATE Teams SET LastTeamIconUpdate = :Time, UpdateAt = :Time WHERE Id = :teamId", map[string]interface{}{"Time": curTime, "teamId": teamId}); err != nil {
|
|
return model.NewAppError("SqlTeamStore.UpdateLastTeamIconUpdate", "store.sql_team.update_last_team_icon_update.app_error", nil, "team_id="+teamId, http.StatusInternalServerError)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetTeamsByScheme returns from the database all teams that match the schemeId provided as parameter, up to
|
|
// a total limit passed as paramater and paginated by offset number passed as parameter.
|
|
func (s SqlTeamStore) GetTeamsByScheme(schemeId string, offset int, limit int) ([]*model.Team, *model.AppError) {
|
|
var teams []*model.Team
|
|
_, 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})
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetTeamsByScheme", "store.sql_team.get_by_scheme.app_error", nil, "schemeId="+schemeId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return teams, nil
|
|
}
|
|
|
|
// This function does the Advanced Permissions Phase 2 migration for TeamMember objects. It performs the migration
|
|
// in batches as a single transaction per batch to ensure consistency but to also minimise execution time to avoid
|
|
// causing unnecessary table locks. **THIS FUNCTION SHOULD NOT BE USED FOR ANY OTHER PURPOSE.** Executing this function
|
|
// *after* the new Schemes functionality has been used on an installation will have unintended consequences.
|
|
func (s SqlTeamStore) MigrateTeamMembers(fromTeamId string, fromUserId string) (map[string]string, *model.AppError) {
|
|
var transaction *gorp.Transaction
|
|
var err error
|
|
|
|
if transaction, err = s.GetMaster().Begin(); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
defer finalizeTransaction(transaction)
|
|
|
|
var teamMembers []teamMember
|
|
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 {
|
|
return nil, model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.select.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
if len(teamMembers) == 0 {
|
|
// No more team members in query result means that the migration has finished.
|
|
return nil, nil
|
|
}
|
|
|
|
for i := range teamMembers {
|
|
member := teamMembers[i]
|
|
roles := strings.Fields(member.Roles)
|
|
var newRoles []string
|
|
if !member.SchemeAdmin.Valid {
|
|
member.SchemeAdmin = sql.NullBool{Bool: false, Valid: true}
|
|
}
|
|
if !member.SchemeUser.Valid {
|
|
member.SchemeUser = sql.NullBool{Bool: false, Valid: true}
|
|
}
|
|
if !member.SchemeGuest.Valid {
|
|
member.SchemeGuest = sql.NullBool{Bool: false, Valid: true}
|
|
}
|
|
for _, role := range roles {
|
|
if role == model.TEAM_ADMIN_ROLE_ID {
|
|
member.SchemeAdmin = sql.NullBool{Bool: true, Valid: true}
|
|
} else if role == model.TEAM_USER_ROLE_ID {
|
|
member.SchemeUser = sql.NullBool{Bool: true, Valid: true}
|
|
} else if role == model.TEAM_GUEST_ROLE_ID {
|
|
member.SchemeGuest = sql.NullBool{Bool: true, Valid: true}
|
|
} else {
|
|
newRoles = append(newRoles, role)
|
|
}
|
|
}
|
|
member.Roles = strings.Join(newRoles, " ")
|
|
|
|
if _, err := transaction.Update(&member); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.update.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
}
|
|
|
|
if err := transaction.Commit(); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.MigrateTeamMembers", "store.sql_team.migrate_team_members.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
data := make(map[string]string)
|
|
data["TeamId"] = teamMembers[len(teamMembers)-1].TeamId
|
|
data["UserId"] = teamMembers[len(teamMembers)-1].UserId
|
|
|
|
return data, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) ResetAllTeamSchemes() *model.AppError {
|
|
if _, err := s.GetMaster().Exec("UPDATE Teams SET SchemeId=''"); err != nil {
|
|
return model.NewAppError("SqlTeamStore.ResetAllTeamSchemes", "store.sql_team.reset_all_team_schemes.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s SqlTeamStore) ClearCaches() {}
|
|
|
|
func (s SqlTeamStore) InvalidateAllTeamIdsForUser(userId string) {}
|
|
|
|
func (s SqlTeamStore) ClearAllCustomRoleAssignments() *model.AppError {
|
|
|
|
builtInRoles := model.MakeDefaultRoles()
|
|
lastUserId := strings.Repeat("0", 26)
|
|
lastTeamId := strings.Repeat("0", 26)
|
|
|
|
for {
|
|
var transaction *gorp.Transaction
|
|
var err error
|
|
|
|
if transaction, err = s.GetMaster().Begin(); err != nil {
|
|
return model.NewAppError("SqlTeamStore.ClearAllCustomRoleAssignments", "store.sql_team.clear_all_custom_role_assignments.open_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
defer finalizeTransaction(transaction)
|
|
|
|
var teamMembers []*teamMember
|
|
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 {
|
|
return model.NewAppError("SqlTeamStore.ClearAllCustomRoleAssignments", "store.sql_team.clear_all_custom_role_assignments.select.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
if len(teamMembers) == 0 {
|
|
break
|
|
}
|
|
|
|
for _, member := range teamMembers {
|
|
lastUserId = member.UserId
|
|
lastTeamId = member.TeamId
|
|
|
|
var newRoles []string
|
|
|
|
for _, role := range strings.Fields(member.Roles) {
|
|
for name := range builtInRoles {
|
|
if name == role {
|
|
newRoles = append(newRoles, role)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
newRolesString := strings.Join(newRoles, " ")
|
|
if newRolesString != member.Roles {
|
|
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 {
|
|
return model.NewAppError("SqlTeamStore.ClearAllCustomRoleAssignments", "store.sql_team.clear_all_custom_role_assignments.update.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
}
|
|
}
|
|
|
|
if err := transaction.Commit(); err != nil {
|
|
return model.NewAppError("SqlTeamStore.ClearAllCustomRoleAssignments", "store.sql_team.clear_all_custom_role_assignments.commit_transaction.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AnalyticsGetTeamCountForScheme returns the number of active teams that match the schemeId passed as parameter.
|
|
func (s SqlTeamStore) AnalyticsGetTeamCountForScheme(schemeId string) (int64, *model.AppError) {
|
|
count, err := s.GetReplica().SelectInt("SELECT count(*) FROM Teams WHERE SchemeId = :SchemeId AND DeleteAt = 0", map[string]interface{}{"SchemeId": schemeId})
|
|
if err != nil {
|
|
return 0, model.NewAppError("SqlTeamStore.AnalyticsGetTeamCountForScheme", "store.sql_team.analytics_get_team_count_for_scheme.app_error", nil, "schemeId="+schemeId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
// GetAllForExportAfter returns teams for export, up to a total limit passed as paramater where Teams.Id is greater than the afterId passed as parameter.
|
|
func (s SqlTeamStore) GetAllForExportAfter(limit int, afterId string) ([]*model.TeamForExport, *model.AppError) {
|
|
var data []*model.TeamForExport
|
|
if _, err := s.GetReplica().Select(&data, `
|
|
SELECT
|
|
Teams.*,
|
|
Schemes.Name as SchemeName
|
|
FROM
|
|
Teams
|
|
LEFT JOIN
|
|
Schemes ON Teams.SchemeId = Schemes.Id
|
|
WHERE
|
|
Teams.Id > :AfterId
|
|
ORDER BY
|
|
Id
|
|
LIMIT
|
|
:Limit`,
|
|
map[string]interface{}{"AfterId": afterId, "Limit": limit}); err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetAllTeams", "store.sql_team.get_all.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
// GetUserTeamIds get the team ids to which the user belongs to. allowFromCache parameter does not have any effect in this Store
|
|
func (s SqlTeamStore) GetUserTeamIds(userID string, allowFromCache bool) ([]string, *model.AppError) {
|
|
var teamIds []string
|
|
_, err := s.GetReplica().Select(&teamIds,
|
|
`SELECT
|
|
TeamId
|
|
FROM
|
|
TeamMembers
|
|
INNER JOIN
|
|
Teams ON TeamMembers.TeamId = Teams.Id
|
|
WHERE
|
|
TeamMembers.UserId = :UserId
|
|
AND TeamMembers.DeleteAt = 0
|
|
AND Teams.DeleteAt = 0`,
|
|
map[string]interface{}{"UserId": userID})
|
|
if err != nil {
|
|
return []string{}, model.NewAppError("SqlTeamStore.GetUserTeamIds", "store.sql_team.get_user_team_ids.app_error", nil, "userID="+userID+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return teamIds, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) GetTeamMembersForExport(userId string) ([]*model.TeamMemberForExport, *model.AppError) {
|
|
var members []*model.TeamMemberForExport
|
|
_, err := s.GetReplica().Select(&members, `
|
|
SELECT
|
|
TeamMembers.TeamId,
|
|
TeamMembers.UserId,
|
|
TeamMembers.Roles,
|
|
TeamMembers.DeleteAt,
|
|
(TeamMembers.SchemeGuest IS NOT NULL AND TeamMembers.SchemeGuest) as SchemeGuest,
|
|
TeamMembers.SchemeUser,
|
|
TeamMembers.SchemeAdmin,
|
|
Teams.Name as TeamName
|
|
FROM
|
|
TeamMembers
|
|
INNER JOIN
|
|
Teams ON TeamMembers.TeamId = Teams.Id
|
|
WHERE
|
|
TeamMembers.UserId = :UserId
|
|
AND Teams.DeleteAt = 0`,
|
|
map[string]interface{}{"UserId": userId})
|
|
if err != nil {
|
|
return nil, model.NewAppError("SqlTeamStore.GetTeamMembersForExport", "store.sql_team.get_members.app_error", nil, "userId="+userId+" "+err.Error(), http.StatusInternalServerError)
|
|
}
|
|
return members, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) UserBelongsToTeams(userId string, teamIds []string) (bool, *model.AppError) {
|
|
idQuery := sq.Eq{
|
|
"UserId": userId,
|
|
"TeamId": teamIds,
|
|
"DeleteAt": 0,
|
|
}
|
|
|
|
query, params, err := s.getQueryBuilder().Select("Count(*)").From("TeamMembers").Where(idQuery).ToSql()
|
|
if err != nil {
|
|
return false, model.NewAppError("SqlTeamStore.UserBelongsToTeams", "store.sql_team.user_belongs_to_teams.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
c, err := s.GetReplica().SelectInt(query, params...)
|
|
if err != nil {
|
|
return false, model.NewAppError("SqlTeamStore.UserBelongsToTeams", "store.sql_team.user_belongs_to_teams.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return c > 0, nil
|
|
}
|
|
|
|
func (s SqlTeamStore) UpdateMembersRole(teamID string, userIDs []string) *model.AppError {
|
|
sql := fmt.Sprintf(`
|
|
UPDATE
|
|
TeamMembers
|
|
SET
|
|
SchemeAdmin = CASE WHEN UserId IN ('%s') THEN
|
|
TRUE
|
|
ELSE
|
|
FALSE
|
|
END
|
|
WHERE
|
|
TeamId = :TeamId
|
|
AND (SchemeGuest = false OR SchemeGuest IS NULL)
|
|
AND DeleteAt = 0`, strings.Join(userIDs, "', '"))
|
|
|
|
if _, err := s.GetMaster().Exec(sql, map[string]interface{}{"TeamId": teamID}); err != nil {
|
|
return model.NewAppError("SqlTeamStore.UpdateMembersRole", "store.update_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func applyTeamMemberViewRestrictionsFilter(query sq.SelectBuilder, teamId string, restrictions *model.ViewUsersRestrictions) sq.SelectBuilder {
|
|
if restrictions == nil {
|
|
return query
|
|
}
|
|
|
|
// If you have no access to teams or channels, return and empty result.
|
|
if restrictions.Teams != nil && len(restrictions.Teams) == 0 && restrictions.Channels != nil && len(restrictions.Channels) == 0 {
|
|
return query.Where("1 = 0")
|
|
}
|
|
|
|
teams := make([]interface{}, len(restrictions.Teams))
|
|
for i, v := range restrictions.Teams {
|
|
teams[i] = v
|
|
}
|
|
channels := make([]interface{}, len(restrictions.Channels))
|
|
for i, v := range restrictions.Channels {
|
|
channels[i] = v
|
|
}
|
|
|
|
resultQuery := query.Join("Users ru ON (TeamMembers.UserId = ru.Id)")
|
|
if restrictions.Teams != nil && len(restrictions.Teams) > 0 {
|
|
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...)
|
|
}
|
|
if restrictions.Channels != nil && len(restrictions.Channels) > 0 {
|
|
resultQuery = resultQuery.Join(fmt.Sprintf("ChannelMembers rcm ON ( rcm.UserId = ru.Id AND rcm.ChannelId IN (%s))", sq.Placeholders(len(channels))), channels...)
|
|
}
|
|
|
|
return resultQuery.Distinct()
|
|
}
|
|
|
|
func applyTeamMemberViewRestrictionsFilterForStats(query sq.SelectBuilder, teamId string, restrictions *model.ViewUsersRestrictions) sq.SelectBuilder {
|
|
if restrictions == nil {
|
|
return query
|
|
}
|
|
|
|
// If you have no access to teams or channels, return and empty result.
|
|
if restrictions.Teams != nil && len(restrictions.Teams) == 0 && restrictions.Channels != nil && len(restrictions.Channels) == 0 {
|
|
return query.Where("1 = 0")
|
|
}
|
|
|
|
teams := make([]interface{}, len(restrictions.Teams))
|
|
for i, v := range restrictions.Teams {
|
|
teams[i] = v
|
|
}
|
|
channels := make([]interface{}, len(restrictions.Channels))
|
|
for i, v := range restrictions.Channels {
|
|
channels[i] = v
|
|
}
|
|
|
|
resultQuery := query
|
|
if restrictions.Teams != nil && len(restrictions.Teams) > 0 {
|
|
resultQuery = resultQuery.Join(fmt.Sprintf("TeamMembers rtm ON ( rtm.UserId = Users.Id AND rtm.DeleteAt = 0 AND rtm.TeamId IN (%s))", sq.Placeholders(len(teams))), teams...)
|
|
}
|
|
if restrictions.Channels != nil && len(restrictions.Channels) > 0 {
|
|
resultQuery = resultQuery.Join(fmt.Sprintf("ChannelMembers rcm ON ( rcm.UserId = Users.Id AND rcm.ChannelId IN (%s))", sq.Placeholders(len(channels))), channels...)
|
|
}
|
|
|
|
return resultQuery
|
|
}
|
|
|
|
func (s SqlTeamStore) GroupSyncedTeamCount() (int64, *model.AppError) {
|
|
query := s.getQueryBuilder().Select("COUNT(*)").From("Teams").Where(sq.Eq{"GroupConstrained": true, "DeleteAt": 0})
|
|
|
|
sql, args, err := query.ToSql()
|
|
if err != nil {
|
|
return 0, model.NewAppError("SqlTeamStore.GroupSyncedTeamCount", "store.sql_group.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
count, err := s.GetReplica().SelectInt(sql, args...)
|
|
if err != nil {
|
|
return 0, model.NewAppError("SqlTeamStore.GroupSyncedTeamCount", "store.select_error", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
return count, nil
|
|
}
|