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