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