github.com/mattermost/mattermost-server/v5@v5.39.3/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 "context" 8 "database/sql" 9 "fmt" 10 "strings" 11 12 sq "github.com/Masterminds/squirrel" 13 "github.com/mattermost/gorp" 14 "github.com/pkg/errors" 15 16 "github.com/mattermost/mattermost-server/v5/model" 17 "github.com/mattermost/mattermost-server/v5/store" 18 "github.com/mattermost/mattermost-server/v5/utils" 19 ) 20 21 const ( 22 TeamMemberExistsError = "store.sql_team.save_member.exists.app_error" 23 ) 24 25 type SqlTeamStore struct { 26 *SqlStore 27 28 teamsQuery sq.SelectBuilder 29 } 30 31 type teamMember struct { 32 TeamId string 33 UserId string 34 Roles string 35 DeleteAt int64 36 SchemeUser sql.NullBool 37 SchemeAdmin sql.NullBool 38 SchemeGuest sql.NullBool 39 } 40 41 func NewTeamMemberFromModel(tm *model.TeamMember) *teamMember { 42 return &teamMember{ 43 TeamId: tm.TeamId, 44 UserId: tm.UserId, 45 Roles: tm.ExplicitRoles, 46 DeleteAt: tm.DeleteAt, 47 SchemeGuest: sql.NullBool{Valid: true, Bool: tm.SchemeGuest}, 48 SchemeUser: sql.NullBool{Valid: true, Bool: tm.SchemeUser}, 49 SchemeAdmin: sql.NullBool{Valid: true, Bool: tm.SchemeAdmin}, 50 } 51 } 52 53 type teamMemberWithSchemeRoles struct { 54 TeamId string 55 UserId string 56 Roles string 57 DeleteAt int64 58 SchemeGuest sql.NullBool 59 SchemeUser sql.NullBool 60 SchemeAdmin sql.NullBool 61 TeamSchemeDefaultGuestRole sql.NullString 62 TeamSchemeDefaultUserRole sql.NullString 63 TeamSchemeDefaultAdminRole sql.NullString 64 } 65 66 type teamMemberWithSchemeRolesList []teamMemberWithSchemeRoles 67 68 func teamMemberSliceColumns() []string { 69 return []string{"TeamId", "UserId", "Roles", "DeleteAt", "SchemeUser", "SchemeAdmin", "SchemeGuest"} 70 } 71 72 func teamMemberToSlice(member *model.TeamMember) []interface{} { 73 resultSlice := []interface{}{} 74 resultSlice = append(resultSlice, member.TeamId) 75 resultSlice = append(resultSlice, member.UserId) 76 resultSlice = append(resultSlice, member.ExplicitRoles) 77 resultSlice = append(resultSlice, member.DeleteAt) 78 resultSlice = append(resultSlice, member.SchemeUser) 79 resultSlice = append(resultSlice, member.SchemeAdmin) 80 resultSlice = append(resultSlice, member.SchemeGuest) 81 return resultSlice 82 } 83 84 func wildcardSearchTerm(term string) string { 85 return strings.ToLower("%" + term + "%") 86 } 87 88 type rolesInfo struct { 89 roles []string 90 explicitRoles []string 91 schemeGuest bool 92 schemeUser bool 93 schemeAdmin bool 94 } 95 96 func getTeamRoles(schemeGuest, schemeUser, schemeAdmin bool, defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole string, roles []string) rolesInfo { 97 result := rolesInfo{ 98 roles: []string{}, 99 explicitRoles: []string{}, 100 schemeGuest: schemeGuest, 101 schemeUser: schemeUser, 102 schemeAdmin: schemeAdmin, 103 } 104 // Identify any scheme derived roles that are in "Roles" field due to not yet being migrated, and exclude 105 // them from ExplicitRoles field. 106 for _, role := range roles { 107 switch role { 108 case model.TEAM_GUEST_ROLE_ID: 109 result.schemeGuest = true 110 case model.TEAM_USER_ROLE_ID: 111 result.schemeUser = true 112 case model.TEAM_ADMIN_ROLE_ID: 113 result.schemeAdmin = true 114 default: 115 result.explicitRoles = append(result.explicitRoles, role) 116 result.roles = append(result.roles, role) 117 } 118 } 119 120 // Add any scheme derived roles that are not in the Roles field due to being Implicit from the Scheme, and add 121 // them to the Roles field for backwards compatibility reasons. 122 var schemeImpliedRoles []string 123 if result.schemeGuest { 124 if defaultTeamGuestRole != "" { 125 schemeImpliedRoles = append(schemeImpliedRoles, defaultTeamGuestRole) 126 } else { 127 schemeImpliedRoles = append(schemeImpliedRoles, model.TEAM_GUEST_ROLE_ID) 128 } 129 } 130 if result.schemeUser { 131 if defaultTeamUserRole != "" { 132 schemeImpliedRoles = append(schemeImpliedRoles, defaultTeamUserRole) 133 } else { 134 schemeImpliedRoles = append(schemeImpliedRoles, model.TEAM_USER_ROLE_ID) 135 } 136 } 137 if result.schemeAdmin { 138 if defaultTeamAdminRole != "" { 139 schemeImpliedRoles = append(schemeImpliedRoles, defaultTeamAdminRole) 140 } else { 141 schemeImpliedRoles = append(schemeImpliedRoles, model.TEAM_ADMIN_ROLE_ID) 142 } 143 } 144 for _, impliedRole := range schemeImpliedRoles { 145 alreadyThere := false 146 for _, role := range result.roles { 147 if role == impliedRole { 148 alreadyThere = true 149 } 150 } 151 if !alreadyThere { 152 result.roles = append(result.roles, impliedRole) 153 } 154 } 155 return result 156 } 157 158 func (db teamMemberWithSchemeRoles) ToModel() *model.TeamMember { 159 // Identify any scheme derived roles that are in "Roles" field due to not yet being migrated, and exclude 160 // them from ExplicitRoles field. 161 schemeGuest := db.SchemeGuest.Valid && db.SchemeGuest.Bool 162 schemeUser := db.SchemeUser.Valid && db.SchemeUser.Bool 163 schemeAdmin := db.SchemeAdmin.Valid && db.SchemeAdmin.Bool 164 165 defaultTeamGuestRole := "" 166 if db.TeamSchemeDefaultGuestRole.Valid { 167 defaultTeamGuestRole = db.TeamSchemeDefaultGuestRole.String 168 } 169 170 defaultTeamUserRole := "" 171 if db.TeamSchemeDefaultUserRole.Valid { 172 defaultTeamUserRole = db.TeamSchemeDefaultUserRole.String 173 } 174 175 defaultTeamAdminRole := "" 176 if db.TeamSchemeDefaultAdminRole.Valid { 177 defaultTeamAdminRole = db.TeamSchemeDefaultAdminRole.String 178 } 179 180 rolesResult := getTeamRoles(schemeGuest, schemeUser, schemeAdmin, defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole, strings.Fields(db.Roles)) 181 182 tm := &model.TeamMember{ 183 TeamId: db.TeamId, 184 UserId: db.UserId, 185 Roles: strings.Join(rolesResult.roles, " "), 186 DeleteAt: db.DeleteAt, 187 SchemeGuest: rolesResult.schemeGuest, 188 SchemeUser: rolesResult.schemeUser, 189 SchemeAdmin: rolesResult.schemeAdmin, 190 ExplicitRoles: strings.Join(rolesResult.explicitRoles, " "), 191 } 192 return tm 193 } 194 195 func (db teamMemberWithSchemeRolesList) ToModel() []*model.TeamMember { 196 tms := make([]*model.TeamMember, 0) 197 198 for _, tm := range db { 199 tms = append(tms, tm.ToModel()) 200 } 201 202 return tms 203 } 204 205 func newSqlTeamStore(sqlStore *SqlStore) store.TeamStore { 206 s := &SqlTeamStore{ 207 SqlStore: sqlStore, 208 } 209 210 s.teamsQuery = s.getQueryBuilder(). 211 Select("Teams.*"). 212 From("Teams") 213 214 for _, db := range sqlStore.GetAllConns() { 215 table := db.AddTableWithName(model.Team{}, "Teams").SetKeys(false, "Id") 216 table.ColMap("Id").SetMaxSize(26) 217 table.ColMap("DisplayName").SetMaxSize(64) 218 table.ColMap("Name").SetMaxSize(64).SetUnique(true) 219 table.ColMap("Description").SetMaxSize(255) 220 table.ColMap("Type").SetMaxSize(255) 221 table.ColMap("Email").SetMaxSize(128) 222 table.ColMap("CompanyName").SetMaxSize(64) 223 table.ColMap("AllowedDomains").SetMaxSize(1000) 224 table.ColMap("InviteId").SetMaxSize(32) 225 table.ColMap("SchemeId").SetMaxSize(26) 226 227 tablem := db.AddTableWithName(teamMember{}, "TeamMembers").SetKeys(false, "TeamId", "UserId") 228 tablem.ColMap("TeamId").SetMaxSize(26) 229 tablem.ColMap("UserId").SetMaxSize(26) 230 tablem.ColMap("Roles").SetMaxSize(64) 231 } 232 233 return s 234 } 235 236 // Save adds the team to the database if a team with the same name does not already 237 // exist in the database. It returns the team added if the operation is successful. 238 func (s SqlTeamStore) Save(team *model.Team) (*model.Team, error) { 239 if team.Id != "" { 240 return nil, store.NewErrInvalidInput("Team", "id", team.Id) 241 } 242 243 team.PreSave() 244 245 if err := team.IsValid(); err != nil { 246 return nil, err 247 } 248 249 if err := s.GetMaster().Insert(team); err != nil { 250 if IsUniqueConstraintError(err, []string{"Name", "teams_name_key"}) { 251 return nil, store.NewErrInvalidInput("Team", "id", team.Id) 252 } 253 return nil, errors.Wrapf(err, "failed to save Team with id=%s", team.Id) 254 } 255 return team, nil 256 } 257 258 // Update updates the details of the team passed as the parameter using the team Id 259 // if the team exists in the database. 260 // It returns the updated team if the operation is successful. 261 func (s SqlTeamStore) Update(team *model.Team) (*model.Team, error) { 262 263 team.PreUpdate() 264 265 if err := team.IsValid(); err != nil { 266 return nil, err 267 } 268 269 oldResult, err := s.GetMaster().Get(model.Team{}, team.Id) 270 if err != nil { 271 return nil, errors.Wrapf(err, "failed to get Team with id=%s", team.Id) 272 273 } 274 275 if oldResult == nil { 276 return nil, store.NewErrInvalidInput("Team", "id", team.Id) 277 } 278 279 oldTeam := oldResult.(*model.Team) 280 team.CreateAt = oldTeam.CreateAt 281 team.UpdateAt = model.GetMillis() 282 283 count, err := s.GetMaster().Update(team) 284 if err != nil { 285 return nil, errors.Wrapf(err, "failed to update Team with id=%s", team.Id) 286 } 287 if count > 1 { 288 return nil, errors.Wrapf(err, "multiple Teams updated with id=%s", team.Id) 289 } 290 291 return team, nil 292 } 293 294 // Get returns from the database the team that matches the id provided as parameter. 295 // If the team doesn't exist it returns a model.AppError with a 296 // http.StatusNotFound in the StatusCode field. 297 func (s SqlTeamStore) Get(id string) (*model.Team, error) { 298 obj, err := s.GetReplica().Get(model.Team{}, id) 299 if err != nil { 300 return nil, errors.Wrapf(err, "failed to get Team with id=%s", id) 301 } 302 if obj == nil { 303 return nil, store.NewErrNotFound("Team", id) 304 } 305 306 return obj.(*model.Team), nil 307 } 308 309 // GetByInviteId returns from the database the team that matches the inviteId provided as parameter. 310 // If the parameter provided is empty or if there is no match in the database, it returns a model.AppError 311 // with a http.StatusNotFound in the StatusCode field. 312 func (s SqlTeamStore) GetByInviteId(inviteId string) (*model.Team, error) { 313 team := model.Team{} 314 315 query, args, err := s.teamsQuery.Where(sq.Eq{"InviteId": inviteId}).ToSql() 316 if err != nil { 317 return nil, errors.Wrap(err, "team_tosql") 318 } 319 err = s.GetReplica().SelectOne(&team, query, args...) 320 if err != nil { 321 return nil, store.NewErrNotFound("Team", fmt.Sprintf("inviteId=%s", inviteId)) 322 } 323 324 if inviteId == "" || team.InviteId != inviteId { 325 return nil, store.NewErrNotFound("Team", fmt.Sprintf("inviteId=%s", inviteId)) 326 } 327 return &team, nil 328 } 329 330 // GetByName returns from the database the team that matches the name provided as parameter. 331 // If there is no match in the database, it returns a model.AppError with a 332 // http.StatusNotFound in the StatusCode field. 333 func (s SqlTeamStore) GetByName(name string) (*model.Team, error) { 334 335 team := model.Team{} 336 query, args, err := s.teamsQuery.Where(sq.Eq{"Name": name}).ToSql() 337 if err != nil { 338 return nil, errors.Wrap(err, "team_tosql") 339 } 340 err = s.GetReplica().SelectOne(&team, query, args...) 341 if err != nil { 342 if err == sql.ErrNoRows { 343 return nil, store.NewErrNotFound("Team", fmt.Sprintf("name=%s", name)) 344 } 345 return nil, errors.Wrapf(err, "failed to find Team with name=%s", name) 346 } 347 return &team, nil 348 } 349 350 func (s SqlTeamStore) GetByNames(names []string) ([]*model.Team, error) { 351 uniqueNames := utils.RemoveDuplicatesFromStringArray(names) 352 353 query, args, err := s.teamsQuery.Where(sq.Eq{"Name": uniqueNames}).ToSql() 354 355 if err != nil { 356 return nil, errors.Wrap(err, "team_tosql") 357 } 358 359 teams := []*model.Team{} 360 _, err = s.GetReplica().Select(&teams, query, args...) 361 if err != nil { 362 if err == sql.ErrNoRows { 363 return nil, store.NewErrNotFound("Team", fmt.Sprintf("nameIn=%v", names)) 364 } 365 return nil, errors.Wrap(err, "failed to find Teams") 366 } 367 if len(teams) != len(uniqueNames) { 368 return nil, store.NewErrNotFound("Team", fmt.Sprintf("nameIn=%v", names)) 369 } 370 return teams, nil 371 } 372 373 func (s SqlTeamStore) teamSearchQuery(opts *model.TeamSearch, countQuery bool) sq.SelectBuilder { 374 var selectStr string 375 if countQuery { 376 selectStr = "count(*)" 377 } else { 378 selectStr = "t.*" 379 if opts.IncludePolicyID != nil && *opts.IncludePolicyID { 380 selectStr += ", RetentionPoliciesTeams.PolicyId" 381 } 382 } 383 384 query := s.getQueryBuilder(). 385 Select(selectStr). 386 From("Teams as t") 387 388 // Don't order or limit if getting count 389 if !countQuery { 390 query = query.OrderBy("t.DisplayName") 391 392 if opts.IsPaginated() { 393 query = query.Limit(uint64(*opts.PerPage)).Offset(uint64(*opts.Page * *opts.PerPage)) 394 } 395 } 396 397 term := opts.Term 398 if term != "" { 399 term = sanitizeSearchTerm(term, "\\") 400 term = wildcardSearchTerm(term) 401 402 operatorKeyword := "ILIKE" 403 if s.DriverName() == model.DATABASE_DRIVER_MYSQL { 404 operatorKeyword = "LIKE" 405 } 406 407 query = query.Where(fmt.Sprintf("(Name %[1]s ? OR DisplayName %[1]s ?)", operatorKeyword), term, term) 408 } 409 410 if opts.PolicyID != nil && *opts.PolicyID != "" { 411 query = query. 412 InnerJoin("RetentionPoliciesTeams ON t.Id = RetentionPoliciesTeams.TeamId"). 413 Where(sq.Eq{"RetentionPoliciesTeams.PolicyId": *opts.PolicyID}) 414 } else if opts.ExcludePolicyConstrained != nil && *opts.ExcludePolicyConstrained { 415 query = query. 416 LeftJoin("RetentionPoliciesTeams ON t.Id = RetentionPoliciesTeams.TeamId"). 417 Where("RetentionPoliciesTeams.TeamId IS NULL") 418 } else if opts.IncludePolicyID != nil && *opts.IncludePolicyID { 419 query = query. 420 LeftJoin("RetentionPoliciesTeams ON t.Id = RetentionPoliciesTeams.TeamId") 421 } 422 423 var teamFilters sq.Sqlizer 424 var openInviteFilter sq.Sqlizer 425 if opts.AllowOpenInvite != nil { 426 if *opts.AllowOpenInvite { 427 openInviteFilter = sq.Eq{"AllowOpenInvite": true} 428 } else { 429 openInviteFilter = sq.And{ 430 sq.Or{ 431 sq.NotEq{"AllowOpenInvite": true}, 432 sq.Eq{"AllowOpenInvite": nil}, 433 }, 434 sq.Or{ 435 sq.NotEq{"GroupConstrained": true}, 436 sq.Eq{"GroupConstrained": nil}, 437 }, 438 } 439 } 440 441 teamFilters = openInviteFilter 442 } 443 444 var groupConstrainedFilter sq.Sqlizer 445 if opts.GroupConstrained != nil { 446 if *opts.GroupConstrained { 447 groupConstrainedFilter = sq.Eq{"GroupConstrained": true} 448 } else { 449 groupConstrainedFilter = sq.Or{ 450 sq.NotEq{"GroupConstrained": true}, 451 sq.Eq{"GroupConstrained": nil}, 452 } 453 } 454 455 if teamFilters == nil { 456 teamFilters = groupConstrainedFilter 457 } else { 458 teamFilters = sq.Or{teamFilters, groupConstrainedFilter} 459 } 460 } 461 462 if opts.TeamType != nil { 463 teamTypeFilter := sq.Eq{"Type": *opts.TeamType} 464 teamFilters = sq.And{teamFilters, teamTypeFilter} 465 } 466 467 query = query.Where(teamFilters) 468 469 return query 470 } 471 472 // SearchAll returns from the database a list of teams that match the Name or DisplayName 473 // passed as the term search parameter. 474 func (s SqlTeamStore) SearchAll(opts *model.TeamSearch) ([]*model.Team, error) { 475 var teams []*model.Team 476 477 queryString, args, err := s.teamSearchQuery(opts, false).ToSql() 478 if err != nil { 479 return nil, errors.Wrap(err, "team_tosql") 480 } 481 482 if _, err = s.GetReplica().Select(&teams, queryString, args...); err != nil { 483 return nil, errors.Wrapf(err, "failed to find Teams with term=%s", opts.Term) 484 } 485 486 return teams, nil 487 } 488 489 // SearchAllPaged returns a teams list and the total count of teams that matched the search. 490 func (s SqlTeamStore) SearchAllPaged(opts *model.TeamSearch) ([]*model.Team, int64, error) { 491 var teams []*model.Team 492 var totalCount int64 493 494 queryString, args, err := s.teamSearchQuery(opts, false).ToSql() 495 if err != nil { 496 return nil, 0, errors.Wrap(err, "team_tosql") 497 } 498 if _, err = s.GetReplica().Select(&teams, queryString, args...); err != nil { 499 return nil, 0, errors.Wrapf(err, "failed to find Teams with term=%s", opts.Term) 500 } 501 502 queryString, args, err = s.teamSearchQuery(opts, true).ToSql() 503 if err != nil { 504 return nil, 0, errors.Wrap(err, "team_tosql") 505 } 506 totalCount, err = s.GetReplica().SelectInt(queryString, args...) 507 if err != nil { 508 return nil, 0, errors.Wrapf(err, "failed to count Teams with term=%s", opts.Term) 509 } 510 511 return teams, totalCount, nil 512 } 513 514 // SearchOpen returns from the database a list of public teams that match the Name or DisplayName 515 // passed as the term search parameter. 516 func (s SqlTeamStore) SearchOpen(opts *model.TeamSearch) ([]*model.Team, error) { 517 opts.TeamType = model.NewString("O") 518 opts.AllowOpenInvite = model.NewBool(true) 519 return s.SearchAll(opts) 520 } 521 522 // SearchPrivate returns from the database a list of private teams that match the Name or DisplayName 523 // passed as the term search parameter. 524 func (s SqlTeamStore) SearchPrivate(opts *model.TeamSearch) ([]*model.Team, error) { 525 opts.TeamType = model.NewString("O") 526 opts.AllowOpenInvite = model.NewBool(false) 527 return s.SearchAll(opts) 528 } 529 530 // GetAll returns all teams 531 func (s SqlTeamStore) GetAll() ([]*model.Team, error) { 532 var teams []*model.Team 533 534 query, args, err := s.teamsQuery.OrderBy("DisplayName").ToSql() 535 536 if err != nil { 537 return nil, errors.Wrap(err, "team_tosql") 538 } 539 540 _, err = s.GetReplica().Select(&teams, query, args...) 541 if err != nil { 542 return nil, errors.Wrap(err, "failed to find Teams") 543 } 544 return teams, nil 545 } 546 547 // GetAllPage returns teams, up to a total limit passed as parameter and paginated by offset number passed as parameter. 548 func (s SqlTeamStore) GetAllPage(offset int, limit int, opts *model.TeamSearch) ([]*model.Team, error) { 549 var teams []*model.Team 550 551 selectString := "Teams.*" 552 if opts != nil && opts.IncludePolicyID != nil && *opts.IncludePolicyID { 553 selectString += ", RetentionPoliciesTeams.PolicyId" 554 } 555 556 builder := s.getQueryBuilder(). 557 Select(selectString). 558 From("Teams"). 559 OrderBy("DisplayName"). 560 Limit(uint64(limit)). 561 Offset(uint64(offset)) 562 563 if opts != nil { 564 if (opts.ExcludePolicyConstrained != nil && *opts.ExcludePolicyConstrained) || 565 (opts.IncludePolicyID != nil && *opts.IncludePolicyID) { 566 builder = builder.LeftJoin("RetentionPoliciesTeams ON Teams.Id = RetentionPoliciesTeams.TeamId") 567 } 568 if opts.ExcludePolicyConstrained != nil && *opts.ExcludePolicyConstrained { 569 builder = builder.Where("RetentionPoliciesTeams.TeamId IS NULL") 570 } 571 if opts.AllowOpenInvite != nil { 572 builder = builder.Where(sq.Eq{"AllowOpenInvite": *opts.AllowOpenInvite}) 573 } 574 } 575 576 query, args, err := builder.ToSql() 577 578 if err != nil { 579 return nil, errors.Wrap(err, "team_tosql") 580 } 581 if _, err = s.GetReplica().Select(&teams, query, args...); err != nil { 582 return nil, errors.Wrap(err, "failed to find Teams") 583 } 584 585 return teams, nil 586 } 587 588 // GetTeamsByUserId returns from the database all teams that userId belongs to. 589 func (s SqlTeamStore) GetTeamsByUserId(userId string) ([]*model.Team, error) { 590 var teams []*model.Team 591 query, args, err := s.teamsQuery. 592 Join("TeamMembers ON TeamMembers.TeamId = Teams.Id"). 593 Where(sq.Eq{"TeamMembers.UserId": userId, "TeamMembers.DeleteAt": 0, "Teams.DeleteAt": 0}).ToSql() 594 595 if err != nil { 596 return nil, errors.Wrap(err, "team_tosql") 597 } 598 599 if _, err = s.GetReplica().Select(&teams, query, args...); err != nil { 600 return nil, errors.Wrap(err, "failed to find Teams") 601 } 602 603 return teams, nil 604 } 605 606 // GetAllPrivateTeamListing returns all private teams. 607 func (s SqlTeamStore) GetAllPrivateTeamListing() ([]*model.Team, error) { 608 query, args, err := s.teamsQuery.Where(sq.Eq{"AllowOpenInvite": false}). 609 OrderBy("DisplayName").ToSql() 610 if err != nil { 611 return nil, errors.Wrap(err, "team_tosql") 612 } 613 var data []*model.Team 614 if _, err = s.GetReplica().Select(&data, query, args...); err != nil { 615 return nil, errors.Wrap(err, "failed to find Teams") 616 } 617 return data, nil 618 } 619 620 // GetAllTeamListing returns all public teams. 621 func (s SqlTeamStore) GetAllTeamListing() ([]*model.Team, error) { 622 query, args, err := s.teamsQuery.Where(sq.Eq{"AllowOpenInvite": true}). 623 OrderBy("DisplayName").ToSql() 624 625 if err != nil { 626 return nil, errors.Wrap(err, "team_tosql") 627 } 628 629 var data []*model.Team 630 if _, err = s.GetReplica().Select(&data, query, args...); err != nil { 631 return nil, errors.Wrap(err, "failed to find Teams") 632 } 633 634 return data, nil 635 } 636 637 // PermanentDelete permanently deletes from the database the team entry that matches the teamId passed as parameter. 638 // To soft-delete the team you can Update it with the DeleteAt field set to the current millisecond using model.GetMillis() 639 func (s SqlTeamStore) PermanentDelete(teamId string) error { 640 sql, args, err := s.getQueryBuilder(). 641 Delete("Teams"). 642 Where(sq.Eq{"Id": teamId}).ToSql() 643 if err != nil { 644 return errors.Wrap(err, "team_tosql") 645 } 646 if _, err = s.GetMaster().Exec(sql, args...); err != nil { 647 return errors.Wrapf(err, "failed to delete Team with id=%s", teamId) 648 } 649 return nil 650 } 651 652 // AnalyticsTeamCount returns the total number of teams. 653 func (s SqlTeamStore) AnalyticsTeamCount(opts *model.TeamSearch) (int64, error) { 654 query := s.getQueryBuilder().Select("COUNT(*) FROM Teams") 655 if opts == nil || (opts.IncludeDeleted != nil && !*opts.IncludeDeleted) { 656 query = query.Where(sq.Eq{"DeleteAt": 0}) 657 } 658 if opts != nil && opts.AllowOpenInvite != nil { 659 query = query.Where(sq.Eq{"AllowOpenInvite": *opts.AllowOpenInvite}) 660 } 661 662 queryString, args, err := query.ToSql() 663 if err != nil { 664 return 0, errors.Wrap(err, "team_tosql") 665 } 666 667 c, err := s.GetReplica().SelectInt(queryString, args...) 668 669 if err != nil { 670 return int64(0), errors.Wrap(err, "failed to count Teams") 671 } 672 673 return c, nil 674 } 675 676 func (s SqlTeamStore) getTeamMembersWithSchemeSelectQuery() sq.SelectBuilder { 677 return s.getQueryBuilder(). 678 Select( 679 "TeamMembers.*", 680 "TeamScheme.DefaultTeamGuestRole TeamSchemeDefaultGuestRole", 681 "TeamScheme.DefaultTeamUserRole TeamSchemeDefaultUserRole", 682 "TeamScheme.DefaultTeamAdminRole TeamSchemeDefaultAdminRole", 683 ). 684 From("TeamMembers"). 685 LeftJoin("Teams ON TeamMembers.TeamId = Teams.Id"). 686 LeftJoin("Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id") 687 } 688 689 func (s SqlTeamStore) SaveMultipleMembers(members []*model.TeamMember, maxUsersPerTeam int) ([]*model.TeamMember, error) { 690 newTeamMembers := map[string]int{} 691 users := map[string]bool{} 692 for _, member := range members { 693 newTeamMembers[member.TeamId] = 0 694 } 695 696 for _, member := range members { 697 newTeamMembers[member.TeamId]++ 698 users[member.UserId] = true 699 700 if err := member.IsValid(); err != nil { 701 return nil, err 702 } 703 } 704 705 teams := []string{} 706 for team := range newTeamMembers { 707 teams = append(teams, team) 708 } 709 710 defaultTeamRolesByTeam := map[string]struct { 711 Id string 712 Guest sql.NullString 713 User sql.NullString 714 Admin sql.NullString 715 }{} 716 717 queryRoles := s.getQueryBuilder(). 718 Select( 719 "Teams.Id as Id", 720 "TeamScheme.DefaultTeamGuestRole as Guest", 721 "TeamScheme.DefaultTeamUserRole as User", 722 "TeamScheme.DefaultTeamAdminRole as Admin", 723 ). 724 From("Teams"). 725 LeftJoin("Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id"). 726 Where(sq.Eq{"Teams.Id": teams}) 727 728 sqlRolesQuery, argsRoles, err := queryRoles.ToSql() 729 if err != nil { 730 return nil, errors.Wrap(err, "team_roles_tosql") 731 } 732 var defaultTeamsRoles []struct { 733 Id string 734 Guest sql.NullString 735 User sql.NullString 736 Admin sql.NullString 737 } 738 _, err = s.GetMaster().Select(&defaultTeamsRoles, sqlRolesQuery, argsRoles...) 739 if err != nil { 740 return nil, errors.Wrap(err, "default_team_roles_select") 741 } 742 743 for _, defaultRoles := range defaultTeamsRoles { 744 defaultTeamRolesByTeam[defaultRoles.Id] = defaultRoles 745 } 746 747 if maxUsersPerTeam >= 0 { 748 queryCount := s.getQueryBuilder(). 749 Select( 750 "COUNT(0) as Count, TeamMembers.TeamId as TeamId", 751 ). 752 From("TeamMembers"). 753 Join("Users ON TeamMembers.UserId = Users.Id"). 754 Where(sq.Eq{"TeamMembers.TeamId": teams}). 755 Where(sq.Eq{"TeamMembers.DeleteAt": 0}). 756 Where(sq.Eq{"Users.DeleteAt": 0}). 757 GroupBy("TeamMembers.TeamId") 758 759 sqlCountQuery, argsCount, errCount := queryCount.ToSql() 760 if errCount != nil { 761 return nil, errors.Wrap(err, "member_count_tosql") 762 } 763 764 var counters []struct { 765 Count int `db:"Count"` 766 TeamId string `db:"TeamId"` 767 } 768 769 _, err = s.GetMaster().Select(&counters, sqlCountQuery, argsCount...) 770 if err != nil { 771 return nil, errors.Wrap(err, "failed to count users in the teams of the memberships") 772 } 773 774 for teamId, newMembers := range newTeamMembers { 775 existingMembers := 0 776 for _, counter := range counters { 777 if counter.TeamId == teamId { 778 existingMembers = counter.Count 779 } 780 } 781 if existingMembers+newMembers > maxUsersPerTeam { 782 return nil, store.NewErrLimitExceeded("TeamMember", existingMembers+newMembers, "team members limit exceeded") 783 } 784 } 785 } 786 787 query := s.getQueryBuilder().Insert("TeamMembers").Columns(teamMemberSliceColumns()...) 788 for _, member := range members { 789 query = query.Values(teamMemberToSlice(member)...) 790 } 791 792 sql, args, err := query.ToSql() 793 if err != nil { 794 return nil, errors.Wrap(err, "insert_members_to_sql") 795 } 796 797 if _, err = s.GetMaster().Exec(sql, args...); err != nil { 798 if IsUniqueConstraintError(err, []string{"TeamId", "teammembers_pkey", "PRIMARY"}) { 799 return nil, store.NewErrConflict("TeamMember", err, "") 800 } 801 return nil, errors.Wrap(err, "unable_to_save_team_member") 802 } 803 804 newMembers := []*model.TeamMember{} 805 for _, member := range members { 806 s.InvalidateAllTeamIdsForUser(member.UserId) 807 defaultTeamGuestRole := defaultTeamRolesByTeam[member.TeamId].Guest.String 808 defaultTeamUserRole := defaultTeamRolesByTeam[member.TeamId].User.String 809 defaultTeamAdminRole := defaultTeamRolesByTeam[member.TeamId].Admin.String 810 rolesResult := getTeamRoles(member.SchemeGuest, member.SchemeUser, member.SchemeAdmin, defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole, strings.Fields(member.ExplicitRoles)) 811 newMember := *member 812 newMember.SchemeGuest = rolesResult.schemeGuest 813 newMember.SchemeUser = rolesResult.schemeUser 814 newMember.SchemeAdmin = rolesResult.schemeAdmin 815 newMember.Roles = strings.Join(rolesResult.roles, " ") 816 newMember.ExplicitRoles = strings.Join(rolesResult.explicitRoles, " ") 817 newMembers = append(newMembers, &newMember) 818 } 819 820 return newMembers, nil 821 } 822 823 func (s SqlTeamStore) SaveMember(member *model.TeamMember, maxUsersPerTeam int) (*model.TeamMember, error) { 824 members, err := s.SaveMultipleMembers([]*model.TeamMember{member}, maxUsersPerTeam) 825 if err != nil { 826 return nil, err 827 } 828 return members[0], nil 829 } 830 831 func (s SqlTeamStore) UpdateMultipleMembers(members []*model.TeamMember) ([]*model.TeamMember, error) { 832 teams := []string{} 833 for _, member := range members { 834 member.PreUpdate() 835 836 if err := member.IsValid(); err != nil { 837 return nil, err 838 } 839 840 if _, err := s.GetMaster().Update(NewTeamMemberFromModel(member)); err != nil { 841 return nil, errors.Wrap(err, "failed to update TeamMember") 842 } 843 teams = append(teams, member.TeamId) 844 } 845 846 query := s.getQueryBuilder(). 847 Select( 848 "Teams.Id as Id", 849 "TeamScheme.DefaultTeamGuestRole as Guest", 850 "TeamScheme.DefaultTeamUserRole as User", 851 "TeamScheme.DefaultTeamAdminRole as Admin", 852 ). 853 From("Teams"). 854 LeftJoin("Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id"). 855 Where(sq.Eq{"Teams.Id": teams}) 856 857 sqlQuery, args, err := query.ToSql() 858 if err != nil { 859 return nil, errors.Wrap(err, "team_tosql") 860 } 861 var defaultTeamsRoles []struct { 862 Id string 863 Guest sql.NullString 864 User sql.NullString 865 Admin sql.NullString 866 } 867 _, err = s.GetMaster().Select(&defaultTeamsRoles, sqlQuery, args...) 868 if err != nil { 869 return nil, errors.Wrap(err, "failed to find Teams") 870 } 871 872 defaultTeamRolesByTeam := map[string]struct { 873 Id string 874 Guest sql.NullString 875 User sql.NullString 876 Admin sql.NullString 877 }{} 878 for _, defaultRoles := range defaultTeamsRoles { 879 defaultTeamRolesByTeam[defaultRoles.Id] = defaultRoles 880 } 881 882 updatedMembers := []*model.TeamMember{} 883 for _, member := range members { 884 s.InvalidateAllTeamIdsForUser(member.UserId) 885 defaultTeamGuestRole := defaultTeamRolesByTeam[member.TeamId].Guest.String 886 defaultTeamUserRole := defaultTeamRolesByTeam[member.TeamId].User.String 887 defaultTeamAdminRole := defaultTeamRolesByTeam[member.TeamId].Admin.String 888 rolesResult := getTeamRoles(member.SchemeGuest, member.SchemeUser, member.SchemeAdmin, defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole, strings.Fields(member.ExplicitRoles)) 889 updatedMember := *member 890 updatedMember.SchemeGuest = rolesResult.schemeGuest 891 updatedMember.SchemeUser = rolesResult.schemeUser 892 updatedMember.SchemeAdmin = rolesResult.schemeAdmin 893 updatedMember.Roles = strings.Join(rolesResult.roles, " ") 894 updatedMember.ExplicitRoles = strings.Join(rolesResult.explicitRoles, " ") 895 updatedMembers = append(updatedMembers, &updatedMember) 896 } 897 898 return updatedMembers, nil 899 } 900 901 func (s SqlTeamStore) UpdateMember(member *model.TeamMember) (*model.TeamMember, error) { 902 members, err := s.UpdateMultipleMembers([]*model.TeamMember{member}) 903 if err != nil { 904 return nil, err 905 } 906 return members[0], nil 907 } 908 909 // GetMember returns a single member of the team that matches the teamId and userId provided as parameters. 910 func (s SqlTeamStore) GetMember(ctx context.Context, teamId string, userId string) (*model.TeamMember, error) { 911 query := s.getTeamMembersWithSchemeSelectQuery(). 912 Where(sq.Eq{"TeamMembers.TeamId": teamId}). 913 Where(sq.Eq{"TeamMembers.UserId": userId}) 914 915 queryString, args, err := query.ToSql() 916 if err != nil { 917 return nil, errors.Wrap(err, "team_tosql") 918 } 919 920 var dbMember teamMemberWithSchemeRoles 921 err = s.DBFromContext(ctx).SelectOne(&dbMember, queryString, args...) 922 if err != nil { 923 if err == sql.ErrNoRows { 924 return nil, store.NewErrNotFound("TeamMember", fmt.Sprintf("teamId=%s, userId=%s", teamId, userId)) 925 } 926 return nil, errors.Wrapf(err, "failed to find TeamMembers with teamId=%s and userId=%s", teamId, userId) 927 } 928 929 return dbMember.ToModel(), nil 930 } 931 932 // GetMembers returns a list of members from the database that matches the teamId passed as parameter and, 933 // also expects teamMembersGetOptions to be passed as a parameter which allows to further filter what to show in the result. 934 // TeamMembersGetOptions Model has following options-> 935 // 1. Sort through USERNAME [ if provided, which otherwise defaults to ID ] 936 // 2. Sort through USERNAME [ if provided, which otherwise defaults to ID ] and exclude deleted members. 937 // 3. Return all the members but, exclude deleted ones. 938 // 4. Apply ViewUsersRestrictions to restrict what is visible to the user. 939 func (s SqlTeamStore) GetMembers(teamId string, offset int, limit int, teamMembersGetOptions *model.TeamMembersGetOptions) ([]*model.TeamMember, error) { 940 query := s.getTeamMembersWithSchemeSelectQuery(). 941 Where(sq.Eq{"TeamMembers.TeamId": teamId}). 942 Where(sq.Eq{"TeamMembers.DeleteAt": 0}). 943 Limit(uint64(limit)). 944 Offset(uint64(offset)) 945 946 if teamMembersGetOptions == nil || teamMembersGetOptions.Sort == "" { 947 query = query.OrderBy("UserId") 948 } 949 950 if teamMembersGetOptions != nil { 951 if teamMembersGetOptions.Sort == model.USERNAME || teamMembersGetOptions.ExcludeDeletedUsers { 952 query = query.LeftJoin("Users ON TeamMembers.UserId = Users.Id") 953 } 954 955 if teamMembersGetOptions.ExcludeDeletedUsers { 956 query = query.Where(sq.Eq{"Users.DeleteAt": 0}) 957 } 958 959 if teamMembersGetOptions.Sort == model.USERNAME { 960 query = query.OrderBy(model.USERNAME) 961 } 962 963 query = applyTeamMemberViewRestrictionsFilter(query, teamMembersGetOptions.ViewRestrictions) 964 } 965 966 queryString, args, err := query.ToSql() 967 if err != nil { 968 return nil, errors.Wrap(err, "team_tosql") 969 } 970 971 var dbMembers teamMemberWithSchemeRolesList 972 _, err = s.GetReplica().Select(&dbMembers, queryString, args...) 973 if err != nil { 974 return nil, errors.Wrapf(err, "failed to find TeamMembers with teamId=%s", teamId) 975 } 976 977 return dbMembers.ToModel(), nil 978 } 979 980 // GetTotalMemberCount returns the number of all members in a team for the teamId passed as a parameter. 981 // Expects a restrictions parameter of type ViewUsersRestrictions that defines a set of Teams and Channels that are visible to the caller of the query, and applies restrictions with a filtered result. 982 func (s SqlTeamStore) GetTotalMemberCount(teamId string, restrictions *model.ViewUsersRestrictions) (int64, error) { 983 query := s.getQueryBuilder(). 984 Select("count(DISTINCT TeamMembers.UserId)"). 985 From("TeamMembers, Users"). 986 Where("TeamMembers.DeleteAt = 0"). 987 Where("TeamMembers.UserId = Users.Id"). 988 Where(sq.Eq{"TeamMembers.TeamId": teamId}) 989 990 query = applyTeamMemberViewRestrictionsFilterForStats(query, restrictions) 991 queryString, args, err := query.ToSql() 992 if err != nil { 993 return int64(0), errors.Wrap(err, "team_tosql") 994 } 995 996 count, err := s.GetReplica().SelectInt(queryString, args...) 997 if err != nil { 998 return int64(0), errors.Wrap(err, "failed to count TeamMembers") 999 } 1000 return count, nil 1001 } 1002 1003 // GetActiveMemberCount returns the number of active members in a team for the teamId passed as a parameter i.e. members with 'DeleteAt = 0' 1004 // Expects a restrictions parameter of type ViewUsersRestrictions that defines a set of Teams and Channels that are visible to the caller of the query, and applies restrictions with a filtered result. 1005 func (s SqlTeamStore) GetActiveMemberCount(teamId string, restrictions *model.ViewUsersRestrictions) (int64, error) { 1006 query := s.getQueryBuilder(). 1007 Select("count(DISTINCT TeamMembers.UserId)"). 1008 From("TeamMembers, Users"). 1009 Where("TeamMembers.DeleteAt = 0"). 1010 Where("TeamMembers.UserId = Users.Id"). 1011 Where("Users.DeleteAt = 0"). 1012 Where(sq.Eq{"TeamMembers.TeamId": teamId}) 1013 1014 query = applyTeamMemberViewRestrictionsFilterForStats(query, restrictions) 1015 queryString, args, err := query.ToSql() 1016 if err != nil { 1017 return 0, errors.Wrap(err, "team_tosql") 1018 } 1019 1020 count, err := s.GetReplica().SelectInt(queryString, args...) 1021 if err != nil { 1022 return 0, errors.Wrap(err, "failed to count TeamMembers") 1023 } 1024 1025 return count, nil 1026 } 1027 1028 // GetMembersByIds returns a list of members from the database that matches the teamId and the list of userIds passed as parameters. 1029 // Expects a restrictions parameter of type ViewUsersRestrictions that defines a set of Teams and Channels that are visible to the caller of the query, and applies restrictions with a filtered result. 1030 func (s SqlTeamStore) GetMembersByIds(teamId string, userIds []string, restrictions *model.ViewUsersRestrictions) ([]*model.TeamMember, error) { 1031 if len(userIds) == 0 { 1032 return nil, errors.New("invalid list of user ids") 1033 } 1034 1035 query := s.getTeamMembersWithSchemeSelectQuery(). 1036 Where(sq.Eq{"TeamMembers.TeamId": teamId}). 1037 Where(sq.Eq{"TeamMembers.UserId": userIds}). 1038 Where(sq.Eq{"TeamMembers.DeleteAt": 0}) 1039 1040 query = applyTeamMemberViewRestrictionsFilter(query, restrictions) 1041 1042 queryString, args, err := query.ToSql() 1043 if err != nil { 1044 return nil, errors.Wrap(err, "team_tosql") 1045 } 1046 1047 var dbMembers teamMemberWithSchemeRolesList 1048 if _, err = s.GetReplica().Select(&dbMembers, queryString, args...); err != nil { 1049 return nil, errors.Wrap(err, "failed to find TeamMembers") 1050 } 1051 return dbMembers.ToModel(), nil 1052 } 1053 1054 // GetTeamsForUser returns a list of teams that the user is a member of. Expects userId to be passed as a parameter. 1055 func (s SqlTeamStore) GetTeamsForUser(ctx context.Context, userId string) ([]*model.TeamMember, error) { 1056 query := s.getTeamMembersWithSchemeSelectQuery(). 1057 Where(sq.Eq{"TeamMembers.UserId": userId}) 1058 1059 queryString, args, err := query.ToSql() 1060 if err != nil { 1061 return nil, errors.Wrap(err, "team_tosql") 1062 } 1063 1064 var dbMembers teamMemberWithSchemeRolesList 1065 _, err = s.SqlStore.DBFromContext(ctx).Select(&dbMembers, queryString, args...) 1066 if err != nil { 1067 return nil, errors.Wrapf(err, "failed to find TeamMembers with userId=%s", userId) 1068 } 1069 1070 return dbMembers.ToModel(), nil 1071 } 1072 1073 // GetTeamsForUserWithPagination returns limited TeamMembers according to the perPage parameter specified. 1074 // It also offsets the records as per the page parameter supplied. 1075 func (s SqlTeamStore) GetTeamsForUserWithPagination(userId string, page, perPage int) ([]*model.TeamMember, error) { 1076 query := s.getTeamMembersWithSchemeSelectQuery(). 1077 Where(sq.Eq{"TeamMembers.UserId": userId}). 1078 Limit(uint64(perPage)). 1079 Offset(uint64(page * perPage)) 1080 1081 queryString, args, err := query.ToSql() 1082 if err != nil { 1083 return nil, errors.Wrap(err, "team_tosql") 1084 } 1085 1086 var dbMembers teamMemberWithSchemeRolesList 1087 _, err = s.GetReplica().Select(&dbMembers, queryString, args...) 1088 if err != nil { 1089 return nil, errors.Wrapf(err, "failed to find TeamMembers with userId=%s", userId) 1090 } 1091 1092 return dbMembers.ToModel(), nil 1093 } 1094 1095 // GetChannelUnreadsForAllTeams returns unreads msg count, mention counts, and notifyProps 1096 // for all the channels in all the teams except the excluded ones. 1097 func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string) ([]*model.ChannelUnread, error) { 1098 query, args, err := s.getQueryBuilder(). 1099 Select("Channels.TeamId TeamId", "Channels.Id ChannelId", "(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount", "(Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot", "ChannelMembers.MentionCount MentionCount", "ChannelMembers.MentionCountRoot MentionCountRoot", "ChannelMembers.NotifyProps NotifyProps"). 1100 From("Channels"). 1101 Join("ChannelMembers ON Id = ChannelId"). 1102 Where(sq.Eq{"UserId": userId, "DeleteAt": 0}). 1103 Where(sq.NotEq{"TeamId": excludeTeamId}).ToSql() 1104 1105 if err != nil { 1106 return nil, errors.Wrap(err, "team_tosql") 1107 } 1108 var data []*model.ChannelUnread 1109 _, err = s.GetReplica().Select(&data, query, args...) 1110 1111 if err != nil { 1112 return nil, errors.Wrapf(err, "failed to find Channels with userId=%s and teamId!=%s", userId, excludeTeamId) 1113 } 1114 1115 return data, nil 1116 } 1117 1118 // GetChannelUnreadsForTeam returns unreads msg count, mention counts and notifyProps for all the channels in a single team. 1119 func (s SqlTeamStore) GetChannelUnreadsForTeam(teamId, userId string) ([]*model.ChannelUnread, error) { 1120 query, args, err := s.getQueryBuilder(). 1121 Select("Channels.TeamId TeamId", "Channels.Id ChannelId", "(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount", "(Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot", "ChannelMembers.MentionCount MentionCount", "ChannelMembers.MentionCountRoot MentionCountRoot", "ChannelMembers.NotifyProps NotifyProps"). 1122 From("Channels"). 1123 Join("ChannelMembers ON Id = ChannelId"). 1124 Where(sq.Eq{"UserId": userId, "TeamId": teamId, "DeleteAt": 0}).ToSql() 1125 1126 if err != nil { 1127 return nil, errors.Wrap(err, "team_tosql") 1128 } 1129 1130 var channels []*model.ChannelUnread 1131 _, err = s.GetReplica().Select(&channels, query, args...) 1132 1133 if err != nil { 1134 return nil, errors.Wrapf(err, "failed to find Channels with teamId=%s and userId=%s", teamId, userId) 1135 } 1136 return channels, nil 1137 } 1138 1139 func (s SqlTeamStore) RemoveMembers(teamId string, userIds []string) error { 1140 builder := s.getQueryBuilder(). 1141 Delete("TeamMembers"). 1142 Where(sq.Eq{"TeamId": teamId}). 1143 Where(sq.Eq{"UserId": userIds}) 1144 1145 query, args, err := builder.ToSql() 1146 if err != nil { 1147 return errors.Wrap(err, "team_tosql") 1148 } 1149 _, err = s.GetMaster().Exec(query, args...) 1150 if err != nil { 1151 return errors.Wrapf(err, "failed to delete TeamMembers with teamId=%s and userId in %v", teamId, userIds) 1152 } 1153 return nil 1154 } 1155 1156 // RemoveMember remove from the database the team members that match the userId and teamId passed as parameter. 1157 func (s SqlTeamStore) RemoveMember(teamId string, userId string) error { 1158 return s.RemoveMembers(teamId, []string{userId}) 1159 } 1160 1161 // RemoveAllMembersByTeam removes from the database the team members that belong to the teamId passed as parameter. 1162 func (s SqlTeamStore) RemoveAllMembersByTeam(teamId string) error { 1163 query, args, err := s.getQueryBuilder(). 1164 Delete("TeamMembers"). 1165 Where(sq.Eq{"TeamId": teamId}).ToSql() 1166 if err != nil { 1167 return errors.Wrap(err, "team_tosql") 1168 } 1169 1170 _, err = s.GetMaster().Exec(query, args...) 1171 if err != nil { 1172 return errors.Wrapf(err, "failed to delete TeamMembers with teamId=%s", teamId) 1173 } 1174 return nil 1175 } 1176 1177 // RemoveAllMembersByUser removes from the database the team members that match the userId passed as parameter. 1178 func (s SqlTeamStore) RemoveAllMembersByUser(userId string) error { 1179 query, args, err := s.getQueryBuilder(). 1180 Delete("TeamMembers"). 1181 Where(sq.Eq{"UserId": userId}).ToSql() 1182 if err != nil { 1183 return errors.Wrap(err, "team_tosql") 1184 } 1185 _, err = s.GetMaster().Exec(query, args...) 1186 if err != nil { 1187 return errors.Wrapf(err, "failed to delete TeamMembers with userId=%s", userId) 1188 } 1189 return nil 1190 } 1191 1192 // UpdateLastTeamIconUpdate sets the last updated time for the icon based on the parameter passed in teamId. The 1193 // LastTeamIconUpdate and UpdateAt fields are set to the parameter passed in curTime. Returns nil on success and an error 1194 // otherwise. 1195 func (s SqlTeamStore) UpdateLastTeamIconUpdate(teamId string, curTime int64) error { 1196 query, args, err := s.getQueryBuilder(). 1197 Update("Teams"). 1198 SetMap(sq.Eq{"LastTeamIconUpdate": curTime, "UpdateAt": curTime}). 1199 Where(sq.Eq{"Id": teamId}).ToSql() 1200 if err != nil { 1201 return errors.Wrap(err, "team_tosql") 1202 } 1203 1204 if _, err = s.GetMaster().Exec(query, args...); err != nil { 1205 return errors.Wrap(err, "failed to update Team") 1206 } 1207 return nil 1208 } 1209 1210 // GetTeamsByScheme returns from the database all teams that match the schemeId provided as parameter, up to 1211 // a total limit passed as paramater and paginated by offset number passed as parameter. 1212 func (s SqlTeamStore) GetTeamsByScheme(schemeId string, offset int, limit int) ([]*model.Team, error) { 1213 query, args, err := s.teamsQuery.Where(sq.Eq{"SchemeId": schemeId}). 1214 OrderBy("DisplayName"). 1215 Limit(uint64(limit)). 1216 Offset(uint64(offset)).ToSql() 1217 1218 if err != nil { 1219 return nil, errors.Wrap(err, "team_tosql") 1220 } 1221 1222 var teams []*model.Team 1223 _, err = s.GetReplica().Select(&teams, query, args...) 1224 if err != nil { 1225 return nil, errors.Wrapf(err, "failed to find Teams with schemeId=%s", schemeId) 1226 } 1227 return teams, nil 1228 } 1229 1230 // MigrateTeamMembers performs the Advanced Permissions Phase 2 migration for TeamMember objects. Migration is done 1231 // in batches as a single transaction per batch to ensure consistency but to also minimise execution time to avoid 1232 // causing unnecessary table locks. **THIS FUNCTION SHOULD NOT BE USED FOR ANY OTHER PURPOSE.** Executing this function 1233 // *after* the new Schemes functionality has been used on an installation will have unintended consequences. 1234 func (s SqlTeamStore) MigrateTeamMembers(fromTeamId string, fromUserId string) (map[string]string, error) { 1235 var transaction *gorp.Transaction 1236 var err error 1237 1238 if transaction, err = s.GetMaster().Begin(); err != nil { 1239 return nil, errors.Wrap(err, "begin_transaction") 1240 } 1241 defer finalizeTransaction(transaction) 1242 1243 var teamMembers []teamMember 1244 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 { 1245 return nil, errors.Wrap(err, "failed to find TeamMembers") 1246 } 1247 1248 if len(teamMembers) == 0 { 1249 // No more team members in query result means that the migration has finished. 1250 return nil, nil 1251 } 1252 1253 for i := range teamMembers { 1254 member := teamMembers[i] 1255 roles := strings.Fields(member.Roles) 1256 var newRoles []string 1257 if !member.SchemeAdmin.Valid { 1258 member.SchemeAdmin = sql.NullBool{Bool: false, Valid: true} 1259 } 1260 if !member.SchemeUser.Valid { 1261 member.SchemeUser = sql.NullBool{Bool: false, Valid: true} 1262 } 1263 if !member.SchemeGuest.Valid { 1264 member.SchemeGuest = sql.NullBool{Bool: false, Valid: true} 1265 } 1266 for _, role := range roles { 1267 if role == model.TEAM_ADMIN_ROLE_ID { 1268 member.SchemeAdmin = sql.NullBool{Bool: true, Valid: true} 1269 } else if role == model.TEAM_USER_ROLE_ID { 1270 member.SchemeUser = sql.NullBool{Bool: true, Valid: true} 1271 } else if role == model.TEAM_GUEST_ROLE_ID { 1272 member.SchemeGuest = sql.NullBool{Bool: true, Valid: true} 1273 } else { 1274 newRoles = append(newRoles, role) 1275 } 1276 } 1277 member.Roles = strings.Join(newRoles, " ") 1278 1279 if _, err := transaction.Update(&member); err != nil { 1280 return nil, errors.Wrap(err, "failed to update TeamMember") 1281 } 1282 1283 } 1284 1285 if err := transaction.Commit(); err != nil { 1286 return nil, errors.Wrap(err, "commit_transaction") 1287 } 1288 1289 data := make(map[string]string) 1290 data["TeamId"] = teamMembers[len(teamMembers)-1].TeamId 1291 data["UserId"] = teamMembers[len(teamMembers)-1].UserId 1292 1293 return data, nil 1294 } 1295 1296 // ResetAllTeamSchemes Set all Team's SchemeId values to an empty string. 1297 func (s SqlTeamStore) ResetAllTeamSchemes() error { 1298 if _, err := s.GetMaster().Exec("UPDATE Teams SET SchemeId=''"); err != nil { 1299 return errors.Wrap(err, "failed to update Teams") 1300 } 1301 return nil 1302 } 1303 1304 // ClearCaches method not implemented. 1305 func (s SqlTeamStore) ClearCaches() {} 1306 1307 // InvalidateAllTeamIdsForUser does not execute anything because the store does not handle the cache. 1308 //nolint:unparam 1309 func (s SqlTeamStore) InvalidateAllTeamIdsForUser(userId string) {} 1310 1311 // ClearAllCustomRoleAssignments removes all custom role assignments from TeamMembers. 1312 func (s SqlTeamStore) ClearAllCustomRoleAssignments() error { 1313 1314 builtInRoles := model.MakeDefaultRoles() 1315 lastUserId := strings.Repeat("0", 26) 1316 lastTeamId := strings.Repeat("0", 26) 1317 1318 for { 1319 var transaction *gorp.Transaction 1320 var err error 1321 1322 if transaction, err = s.GetMaster().Begin(); err != nil { 1323 return errors.Wrap(err, "begin_transaction") 1324 } 1325 defer finalizeTransaction(transaction) 1326 1327 var teamMembers []*teamMember 1328 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 { 1329 return errors.Wrap(err, "failed to find TeamMembers") 1330 } 1331 1332 if len(teamMembers) == 0 { 1333 break 1334 } 1335 1336 for _, member := range teamMembers { 1337 lastUserId = member.UserId 1338 lastTeamId = member.TeamId 1339 1340 var newRoles []string 1341 1342 for _, role := range strings.Fields(member.Roles) { 1343 for name := range builtInRoles { 1344 if name == role { 1345 newRoles = append(newRoles, role) 1346 break 1347 } 1348 } 1349 } 1350 1351 newRolesString := strings.Join(newRoles, " ") 1352 if newRolesString != member.Roles { 1353 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 { 1354 return errors.Wrap(err, "failed to update TeamMembers") 1355 } 1356 } 1357 } 1358 1359 if err := transaction.Commit(); err != nil { 1360 return errors.Wrap(err, "commit_transaction") 1361 } 1362 } 1363 return nil 1364 } 1365 1366 // AnalyticsGetTeamCountForScheme returns the number of active teams that match the schemeId passed as parameter. 1367 func (s SqlTeamStore) AnalyticsGetTeamCountForScheme(schemeId string) (int64, error) { 1368 query, args, err := s.getQueryBuilder(). 1369 Select("count(*)"). 1370 From("Teams"). 1371 Where(sq.Eq{"SchemeId": schemeId, "DeleteAt": 0}).ToSql() 1372 1373 if err != nil { 1374 return 0, errors.Wrap(err, "team_tosql") 1375 } 1376 count, err := s.GetReplica().SelectInt(query, args...) 1377 if err != nil { 1378 return 0, errors.Wrapf(err, "failed to count Teams with schemdId=%s", schemeId) 1379 } 1380 1381 return count, nil 1382 } 1383 1384 // GetAllForExportAfter returns teams for export, up to a total limit passed as paramater where Teams.Id is greater than the afterId passed as parameter. 1385 func (s SqlTeamStore) GetAllForExportAfter(limit int, afterId string) ([]*model.TeamForExport, error) { 1386 var data []*model.TeamForExport 1387 query, args, err := s.getQueryBuilder(). 1388 Select("Teams.*", "Schemes.Name as SchemeName"). 1389 From("Teams"). 1390 LeftJoin("Schemes ON Teams.SchemeId = Schemes.Id"). 1391 Where(sq.Gt{"Teams.Id": afterId}). 1392 OrderBy("Id"). 1393 Limit(uint64(limit)).ToSql() 1394 1395 if err != nil { 1396 return nil, errors.Wrap(err, "team_tosql") 1397 } 1398 if _, err = s.GetReplica().Select(&data, query, args...); err != nil { 1399 return nil, errors.Wrap(err, "failed to find Teams") 1400 } 1401 1402 return data, nil 1403 } 1404 1405 // GetUserTeamIds get the team ids to which the user belongs to. allowFromCache parameter does not have any effect in this Store 1406 //nolint:unparam 1407 func (s SqlTeamStore) GetUserTeamIds(userId string, allowFromCache bool) ([]string, error) { 1408 var teamIds []string 1409 query, args, err := s.getQueryBuilder(). 1410 Select("TeamId"). 1411 From("TeamMembers"). 1412 Join("Teams ON TeamMembers.TeamId = Teams.Id"). 1413 Where(sq.Eq{"TeamMembers.UserId": userId, "TeamMembers.DeleteAt": 0, "Teams.DeleteAt": 0}).ToSql() 1414 1415 if err != nil { 1416 return []string{}, errors.Wrap(err, "team_tosql") 1417 } 1418 _, err = s.GetReplica().Select(&teamIds, query, args...) 1419 if err != nil { 1420 return []string{}, errors.Wrapf(err, "failed to find TeamMembers with userId=%s", userId) 1421 } 1422 1423 return teamIds, nil 1424 } 1425 1426 // GetCommonTeamIDsForTwoUsers returns the intersection of all the teams to which the specified 1427 // users belong. 1428 func (s SqlTeamStore) GetCommonTeamIDsForTwoUsers(userID, otherUserID string) ([]string, error) { 1429 var teamIDs []string 1430 query, args, err := s.getQueryBuilder(). 1431 Select("TM1.TeamId"). 1432 From("TeamMembers AS TM1"). 1433 InnerJoin("TeamMembers AS TM2 ON TM1.TeamId = TM2.TeamId"). 1434 InnerJoin("Teams ON TM1.TeamId = Teams.Id"). 1435 Where(sq.And{ 1436 sq.Eq{"TM1.UserId": userID}, 1437 sq.Eq{"TM1.DeleteAt": 0}, 1438 sq.Eq{"TM2.UserId": otherUserID}, 1439 sq.Eq{"TM2.DeleteAt": 0}, 1440 sq.Eq{"Teams.DeleteAt": 0}, 1441 }). 1442 ToSql() 1443 if err != nil { 1444 return nil, errors.Wrap(err, "team_tosql") 1445 } 1446 _, err = s.GetReplica().Select(&teamIDs, query, args...) 1447 if err != nil { 1448 return nil, errors.Wrapf(err, "failed to find TeamMembers with user IDs %s and %s", userID, otherUserID) 1449 } 1450 1451 return teamIDs, nil 1452 } 1453 1454 // GetTeamMembersForExport gets the various teams for which a user, denoted by userId, is a part of. 1455 func (s SqlTeamStore) GetTeamMembersForExport(userId string) ([]*model.TeamMemberForExport, error) { 1456 var members []*model.TeamMemberForExport 1457 query, args, err := s.getQueryBuilder(). 1458 Select("TeamMembers.TeamId", "TeamMembers.UserId", "TeamMembers.Roles", "TeamMembers.DeleteAt", 1459 "(TeamMembers.SchemeGuest IS NOT NULL AND TeamMembers.SchemeGuest) as SchemeGuest", 1460 "TeamMembers.SchemeUser", "TeamMembers.SchemeAdmin", "Teams.Name as TeamName"). 1461 From("TeamMembers"). 1462 Join("Teams ON TeamMembers.TeamId = Teams.Id"). 1463 Where(sq.Eq{"TeamMembers.UserId": userId, "Teams.DeleteAt": 0}).ToSql() 1464 1465 if err != nil { 1466 return nil, errors.Wrap(err, "team_tosql") 1467 } 1468 _, err = s.GetReplica().Select(&members, query, args...) 1469 if err != nil { 1470 return nil, errors.Wrapf(err, "failed to find TeamMembers with userId=%s", userId) 1471 } 1472 return members, nil 1473 } 1474 1475 //UserBelongsToTeams returns true if the user denoted by userId is a member of the teams in the teamIds string array. 1476 func (s SqlTeamStore) UserBelongsToTeams(userId string, teamIds []string) (bool, error) { 1477 idQuery := sq.Eq{ 1478 "UserId": userId, 1479 "TeamId": teamIds, 1480 "DeleteAt": 0, 1481 } 1482 1483 query, params, err := s.getQueryBuilder().Select("Count(*)").From("TeamMembers").Where(idQuery).ToSql() 1484 if err != nil { 1485 return false, errors.Wrap(err, "team_tosql") 1486 } 1487 1488 c, err := s.GetReplica().SelectInt(query, params...) 1489 if err != nil { 1490 return false, errors.Wrap(err, "failed to count TeamMembers") 1491 } 1492 1493 return c > 0, nil 1494 } 1495 1496 // UpdateMembersRole updates all the members of teamID in the userIds string array to be admins and sets all other 1497 // users as not being admin. 1498 func (s SqlTeamStore) UpdateMembersRole(teamID string, userIDs []string) error { 1499 query, args, err := s.getQueryBuilder(). 1500 Update("TeamMembers"). 1501 Set("SchemeAdmin", sq.Case().When(sq.Eq{"UserId": userIDs}, "true").Else("false")). 1502 Where(sq.Eq{"TeamId": teamID, "DeleteAt": 0}). 1503 Where(sq.Or{sq.Eq{"SchemeGuest": false}, sq.Expr("SchemeGuest IS NULL")}).ToSql() 1504 if err != nil { 1505 return errors.Wrap(err, "team_tosql") 1506 } 1507 1508 if _, err = s.GetMaster().Exec(query, args...); err != nil { 1509 return errors.Wrap(err, "failed to update TeamMembers") 1510 } 1511 1512 return nil 1513 } 1514 1515 func applyTeamMemberViewRestrictionsFilter(query sq.SelectBuilder, restrictions *model.ViewUsersRestrictions) sq.SelectBuilder { 1516 if restrictions == nil { 1517 return query 1518 } 1519 1520 // If you have no access to teams or channels, return and empty result. 1521 if restrictions.Teams != nil && len(restrictions.Teams) == 0 && restrictions.Channels != nil && len(restrictions.Channels) == 0 { 1522 return query.Where("1 = 0") 1523 } 1524 1525 teams := make([]interface{}, len(restrictions.Teams)) 1526 for i, v := range restrictions.Teams { 1527 teams[i] = v 1528 } 1529 channels := make([]interface{}, len(restrictions.Channels)) 1530 for i, v := range restrictions.Channels { 1531 channels[i] = v 1532 } 1533 1534 resultQuery := query.Join("Users ru ON (TeamMembers.UserId = ru.Id)") 1535 if restrictions.Teams != nil && len(restrictions.Teams) > 0 { 1536 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...) 1537 } 1538 if restrictions.Channels != nil && len(restrictions.Channels) > 0 { 1539 resultQuery = resultQuery.Join(fmt.Sprintf("ChannelMembers rcm ON ( rcm.UserId = ru.Id AND rcm.ChannelId IN (%s))", sq.Placeholders(len(channels))), channels...) 1540 } 1541 1542 return resultQuery.Distinct() 1543 } 1544 1545 func applyTeamMemberViewRestrictionsFilterForStats(query sq.SelectBuilder, restrictions *model.ViewUsersRestrictions) sq.SelectBuilder { 1546 if restrictions == nil { 1547 return query 1548 } 1549 1550 // If you have no access to teams or channels, return and empty result. 1551 if restrictions.Teams != nil && len(restrictions.Teams) == 0 && restrictions.Channels != nil && len(restrictions.Channels) == 0 { 1552 return query.Where("1 = 0") 1553 } 1554 1555 teams := make([]interface{}, len(restrictions.Teams)) 1556 for i, v := range restrictions.Teams { 1557 teams[i] = v 1558 } 1559 channels := make([]interface{}, len(restrictions.Channels)) 1560 for i, v := range restrictions.Channels { 1561 channels[i] = v 1562 } 1563 1564 resultQuery := query 1565 if restrictions.Teams != nil && len(restrictions.Teams) > 0 { 1566 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...) 1567 } 1568 if restrictions.Channels != nil && len(restrictions.Channels) > 0 { 1569 resultQuery = resultQuery.Join(fmt.Sprintf("ChannelMembers rcm ON ( rcm.UserId = Users.Id AND rcm.ChannelId IN (%s))", sq.Placeholders(len(channels))), channels...) 1570 } 1571 1572 return resultQuery 1573 } 1574 1575 // GroupSyncedTeamCount returns the number of teams that are group constrained. 1576 func (s SqlTeamStore) GroupSyncedTeamCount() (int64, error) { 1577 builder := s.getQueryBuilder().Select("COUNT(*)").From("Teams").Where(sq.Eq{"GroupConstrained": true, "DeleteAt": 0}) 1578 1579 query, args, err := builder.ToSql() 1580 if err != nil { 1581 return 0, errors.Wrap(err, "team_tosql") 1582 } 1583 1584 count, err := s.GetReplica().SelectInt(query, args...) 1585 if err != nil { 1586 return 0, errors.Wrap(err, "failed to count Teams") 1587 } 1588 1589 return count, nil 1590 }