github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/team.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "bytes" 8 "errors" 9 "fmt" 10 "image" 11 "image/png" 12 "io" 13 "mime/multipart" 14 "net/http" 15 "net/url" 16 "strings" 17 18 "github.com/disintegration/imaging" 19 "github.com/mattermost/mattermost-server/v5/mlog" 20 "github.com/mattermost/mattermost-server/v5/model" 21 "github.com/mattermost/mattermost-server/v5/plugin" 22 "github.com/mattermost/mattermost-server/v5/store" 23 "github.com/mattermost/mattermost-server/v5/utils" 24 ) 25 26 func (a *App) CreateTeam(team *model.Team) (*model.Team, *model.AppError) { 27 team.InviteId = "" 28 rteam, err := a.Srv().Store.Team().Save(team) 29 if err != nil { 30 return nil, err 31 } 32 33 if _, err := a.CreateDefaultChannels(rteam.Id); err != nil { 34 return nil, err 35 } 36 37 return rteam, nil 38 } 39 40 func (a *App) CreateTeamWithUser(team *model.Team, userId string) (*model.Team, *model.AppError) { 41 user, err := a.GetUser(userId) 42 if err != nil { 43 return nil, err 44 } 45 team.Email = user.Email 46 47 if !a.isTeamEmailAllowed(user, team) { 48 return nil, model.NewAppError("isTeamEmailAllowed", "api.team.is_team_creation_allowed.domain.app_error", nil, "", http.StatusBadRequest) 49 } 50 51 rteam, err := a.CreateTeam(team) 52 if err != nil { 53 return nil, err 54 } 55 56 if err = a.JoinUserToTeam(rteam, user, ""); err != nil { 57 return nil, err 58 } 59 60 return rteam, nil 61 } 62 63 func (a *App) normalizeDomains(domains string) []string { 64 // commas and @ signs are optional 65 // can be in the form of "@corp.mattermost.com, mattermost.com mattermost.org" -> corp.mattermost.com mattermost.com mattermost.org 66 return strings.Fields(strings.TrimSpace(strings.ToLower(strings.Replace(strings.Replace(domains, "@", " ", -1), ",", " ", -1)))) 67 } 68 69 func (a *App) isEmailAddressAllowed(email string, allowedDomains []string) bool { 70 for _, restriction := range allowedDomains { 71 domains := a.normalizeDomains(restriction) 72 if len(domains) <= 0 { 73 continue 74 } 75 matched := false 76 for _, d := range domains { 77 if strings.HasSuffix(email, "@"+d) { 78 matched = true 79 break 80 } 81 } 82 if !matched { 83 return false 84 } 85 } 86 87 return true 88 } 89 90 func (a *App) isTeamEmailAllowed(user *model.User, team *model.Team) bool { 91 if user.IsBot { 92 return true 93 } 94 email := strings.ToLower(user.Email) 95 allowedDomains := a.getAllowedDomains(user, team) 96 return a.isEmailAddressAllowed(email, allowedDomains) 97 } 98 99 func (a *App) getAllowedDomains(user *model.User, team *model.Team) []string { 100 if user.IsGuest() { 101 return []string{*a.Config().GuestAccountsSettings.RestrictCreationToDomains} 102 } 103 // First check per team allowedDomains, then app wide restrictions 104 return []string{team.AllowedDomains, *a.Config().TeamSettings.RestrictCreationToDomains} 105 } 106 107 func (a *App) CheckValidDomains(team *model.Team) *model.AppError { 108 validDomains := a.normalizeDomains(*a.Config().TeamSettings.RestrictCreationToDomains) 109 if len(validDomains) > 0 { 110 for _, domain := range a.normalizeDomains(team.AllowedDomains) { 111 matched := false 112 for _, d := range validDomains { 113 if domain == d { 114 matched = true 115 break 116 } 117 } 118 if !matched { 119 err := model.NewAppError("UpdateTeam", "api.team.update_restricted_domains.mismatch.app_error", map[string]interface{}{"Domain": domain}, "", http.StatusBadRequest) 120 return err 121 } 122 } 123 } 124 125 return nil 126 } 127 128 func (a *App) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) { 129 oldTeam, err := a.GetTeam(team.Id) 130 if err != nil { 131 return nil, err 132 } 133 134 if err = a.CheckValidDomains(team); err != nil { 135 return nil, err 136 } 137 138 oldTeam.DisplayName = team.DisplayName 139 oldTeam.Description = team.Description 140 oldTeam.AllowOpenInvite = team.AllowOpenInvite 141 oldTeam.CompanyName = team.CompanyName 142 oldTeam.AllowedDomains = team.AllowedDomains 143 oldTeam.LastTeamIconUpdate = team.LastTeamIconUpdate 144 oldTeam.GroupConstrained = team.GroupConstrained 145 146 oldTeam, err = a.updateTeamUnsanitized(oldTeam) 147 if err != nil { 148 return team, err 149 } 150 151 a.sendTeamEvent(oldTeam, model.WEBSOCKET_EVENT_UPDATE_TEAM) 152 153 return oldTeam, nil 154 } 155 156 func (a *App) updateTeamUnsanitized(team *model.Team) (*model.Team, *model.AppError) { 157 return a.Srv().Store.Team().Update(team) 158 } 159 160 // RenameTeam is used to rename the team Name and the DisplayName fields 161 func (a *App) RenameTeam(team *model.Team, newTeamName string, newDisplayName string) (*model.Team, *model.AppError) { 162 163 // check if name is occupied 164 _, errnf := a.GetTeamByName(newTeamName) 165 166 // "-" can be used as a newTeamName if only DisplayName change is wanted 167 if errnf == nil && newTeamName != "-" { 168 errbody := fmt.Sprintf("team with name %s already exists", newTeamName) 169 return nil, model.NewAppError("RenameTeam", "app.team.rename_team.name_occupied", nil, errbody, http.StatusBadRequest) 170 } 171 172 if newTeamName != "-" { 173 team.Name = newTeamName 174 } 175 176 if newDisplayName != "" { 177 team.DisplayName = newDisplayName 178 } 179 180 newTeam, err := a.updateTeamUnsanitized(team) 181 if err != nil { 182 return nil, err 183 } 184 185 return newTeam, nil 186 } 187 188 func (a *App) UpdateTeamScheme(team *model.Team) (*model.Team, *model.AppError) { 189 oldTeam, err := a.GetTeam(team.Id) 190 if err != nil { 191 return nil, err 192 } 193 194 oldTeam.SchemeId = team.SchemeId 195 196 if oldTeam, err = a.Srv().Store.Team().Update(oldTeam); err != nil { 197 return nil, err 198 } 199 200 a.sendTeamEvent(oldTeam, model.WEBSOCKET_EVENT_UPDATE_TEAM_SCHEME) 201 202 return oldTeam, nil 203 } 204 205 func (a *App) UpdateTeamPrivacy(teamId string, teamType string, allowOpenInvite bool) *model.AppError { 206 oldTeam, err := a.GetTeam(teamId) 207 if err != nil { 208 return err 209 } 210 211 // Force a regeneration of the invite token if changing a team to restricted. 212 if (allowOpenInvite != oldTeam.AllowOpenInvite || teamType != oldTeam.Type) && (!allowOpenInvite || teamType == model.TEAM_INVITE) { 213 oldTeam.InviteId = model.NewId() 214 } 215 216 oldTeam.Type = teamType 217 oldTeam.AllowOpenInvite = allowOpenInvite 218 219 if oldTeam, err = a.Srv().Store.Team().Update(oldTeam); err != nil { 220 return err 221 } 222 223 a.sendTeamEvent(oldTeam, model.WEBSOCKET_EVENT_UPDATE_TEAM) 224 225 return nil 226 } 227 228 func (a *App) PatchTeam(teamId string, patch *model.TeamPatch) (*model.Team, *model.AppError) { 229 team, err := a.GetTeam(teamId) 230 if err != nil { 231 return nil, err 232 } 233 234 team.Patch(patch) 235 if patch.AllowOpenInvite != nil && !*patch.AllowOpenInvite { 236 team.InviteId = model.NewId() 237 } 238 239 if err = a.CheckValidDomains(team); err != nil { 240 return nil, err 241 } 242 243 team, err = a.updateTeamUnsanitized(team) 244 if err != nil { 245 return team, err 246 } 247 248 a.sendTeamEvent(team, model.WEBSOCKET_EVENT_UPDATE_TEAM) 249 250 return team, nil 251 } 252 253 func (a *App) RegenerateTeamInviteId(teamId string) (*model.Team, *model.AppError) { 254 team, err := a.GetTeam(teamId) 255 if err != nil { 256 return nil, err 257 } 258 259 team.InviteId = model.NewId() 260 261 updatedTeam, err := a.Srv().Store.Team().Update(team) 262 if err != nil { 263 return nil, err 264 } 265 266 a.sendTeamEvent(updatedTeam, model.WEBSOCKET_EVENT_UPDATE_TEAM) 267 268 return updatedTeam, nil 269 } 270 271 func (a *App) sendTeamEvent(team *model.Team, event string) { 272 sanitizedTeam := &model.Team{} 273 *sanitizedTeam = *team 274 sanitizedTeam.Sanitize() 275 276 teamId := "" // no filtering by teamId by default 277 if event == model.WEBSOCKET_EVENT_UPDATE_TEAM { 278 // in case of update_team event - we send the message only to members of that team 279 teamId = team.Id 280 } 281 message := model.NewWebSocketEvent(event, teamId, "", "", nil) 282 message.Add("team", sanitizedTeam.ToJson()) 283 a.Publish(message) 284 } 285 286 func (a *App) GetSchemeRolesForTeam(teamId string) (string, string, string, *model.AppError) { 287 team, err := a.GetTeam(teamId) 288 if err != nil { 289 return "", "", "", err 290 } 291 292 if team.SchemeId != nil && len(*team.SchemeId) != 0 { 293 scheme, err := a.GetScheme(*team.SchemeId) 294 if err != nil { 295 return "", "", "", err 296 } 297 return scheme.DefaultTeamGuestRole, scheme.DefaultTeamUserRole, scheme.DefaultTeamAdminRole, nil 298 } 299 300 return model.TEAM_GUEST_ROLE_ID, model.TEAM_USER_ROLE_ID, model.TEAM_ADMIN_ROLE_ID, nil 301 } 302 303 func (a *App) UpdateTeamMemberRoles(teamId string, userId string, newRoles string) (*model.TeamMember, *model.AppError) { 304 member, err := a.Srv().Store.Team().GetMember(teamId, userId) 305 if err != nil { 306 return nil, err 307 } 308 309 if member == nil { 310 err = model.NewAppError("UpdateTeamMemberRoles", "api.team.update_member_roles.not_a_member", nil, "userId="+userId+" teamId="+teamId, http.StatusBadRequest) 311 return nil, err 312 } 313 314 schemeGuestRole, schemeUserRole, schemeAdminRole, err := a.GetSchemeRolesForTeam(teamId) 315 if err != nil { 316 return nil, err 317 } 318 319 prevSchemeGuestValue := member.SchemeGuest 320 321 var newExplicitRoles []string 322 member.SchemeGuest = false 323 member.SchemeUser = false 324 member.SchemeAdmin = false 325 326 for _, roleName := range strings.Fields(newRoles) { 327 var role *model.Role 328 role, err = a.GetRoleByName(roleName) 329 if err != nil { 330 err.StatusCode = http.StatusBadRequest 331 return nil, err 332 } 333 if !role.SchemeManaged { 334 // The role is not scheme-managed, so it's OK to apply it to the explicit roles field. 335 newExplicitRoles = append(newExplicitRoles, roleName) 336 } else { 337 // The role is scheme-managed, so need to check if it is part of the scheme for this channel or not. 338 switch roleName { 339 case schemeAdminRole: 340 member.SchemeAdmin = true 341 case schemeUserRole: 342 member.SchemeUser = true 343 case schemeGuestRole: 344 member.SchemeGuest = true 345 default: 346 // If not part of the scheme for this team, then it is not allowed to apply it as an explicit role. 347 return nil, model.NewAppError("UpdateTeamMemberRoles", "api.channel.update_team_member_roles.scheme_role.app_error", nil, "role_name="+roleName, http.StatusBadRequest) 348 } 349 } 350 } 351 352 if member.SchemeGuest && member.SchemeUser { 353 return nil, model.NewAppError("UpdateTeamMemberRoles", "api.team.update_team_member_roles.guest_and_user.app_error", nil, "", http.StatusBadRequest) 354 } 355 356 if prevSchemeGuestValue != member.SchemeGuest { 357 return nil, model.NewAppError("UpdateTeamMemberRoles", "api.channel.update_team_member_roles.changing_guest_role.app_error", nil, "", http.StatusBadRequest) 358 } 359 360 member.ExplicitRoles = strings.Join(newExplicitRoles, " ") 361 362 member, err = a.Srv().Store.Team().UpdateMember(member) 363 if err != nil { 364 return nil, err 365 } 366 367 a.ClearSessionCacheForUser(userId) 368 369 a.sendUpdatedMemberRoleEvent(userId, member) 370 371 return member, nil 372 } 373 374 func (a *App) UpdateTeamMemberSchemeRoles(teamId string, userId string, isSchemeGuest bool, isSchemeUser bool, isSchemeAdmin bool) (*model.TeamMember, *model.AppError) { 375 member, err := a.GetTeamMember(teamId, userId) 376 if err != nil { 377 return nil, err 378 } 379 380 member.SchemeAdmin = isSchemeAdmin 381 member.SchemeUser = isSchemeUser 382 member.SchemeGuest = isSchemeGuest 383 384 if member.SchemeUser && member.SchemeGuest { 385 return nil, model.NewAppError("UpdateTeamMemberSchemeRoles", "api.team.update_team_member_roles.guest_and_user.app_error", nil, "", http.StatusBadRequest) 386 } 387 388 // If the migration is not completed, we also need to check the default team_admin/team_user roles are not present in the roles field. 389 if err = a.IsPhase2MigrationCompleted(); err != nil { 390 member.ExplicitRoles = RemoveRoles([]string{model.TEAM_GUEST_ROLE_ID, model.TEAM_USER_ROLE_ID, model.TEAM_ADMIN_ROLE_ID}, member.ExplicitRoles) 391 } 392 393 member, err = a.Srv().Store.Team().UpdateMember(member) 394 if err != nil { 395 return nil, err 396 } 397 398 a.ClearSessionCacheForUser(userId) 399 400 a.sendUpdatedMemberRoleEvent(userId, member) 401 402 return member, nil 403 } 404 405 func (a *App) sendUpdatedMemberRoleEvent(userId string, member *model.TeamMember) { 406 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_MEMBERROLE_UPDATED, "", "", userId, nil) 407 message.Add("member", member.ToJson()) 408 a.Publish(message) 409 } 410 411 func (a *App) AddUserToTeam(teamId string, userId string, userRequestorId string) (*model.Team, *model.AppError) { 412 tchan := make(chan store.StoreResult, 1) 413 go func() { 414 team, err := a.Srv().Store.Team().Get(teamId) 415 tchan <- store.StoreResult{Data: team, Err: err} 416 close(tchan) 417 }() 418 419 uchan := make(chan store.StoreResult, 1) 420 go func() { 421 user, err := a.Srv().Store.User().Get(userId) 422 uchan <- store.StoreResult{Data: user, Err: err} 423 close(uchan) 424 }() 425 426 result := <-tchan 427 if result.Err != nil { 428 return nil, result.Err 429 } 430 team := result.Data.(*model.Team) 431 432 result = <-uchan 433 if result.Err != nil { 434 return nil, result.Err 435 } 436 user := result.Data.(*model.User) 437 438 if err := a.JoinUserToTeam(team, user, userRequestorId); err != nil { 439 return nil, err 440 } 441 442 return team, nil 443 } 444 445 func (a *App) AddUserToTeamByTeamId(teamId string, user *model.User) *model.AppError { 446 team, err := a.Srv().Store.Team().Get(teamId) 447 if err != nil { 448 return err 449 } 450 451 return a.JoinUserToTeam(team, user, "") 452 } 453 454 func (a *App) AddUserToTeamByToken(userId string, tokenId string) (*model.Team, *model.AppError) { 455 token, err := a.Srv().Store.Token().GetByToken(tokenId) 456 if err != nil { 457 return nil, model.NewAppError("AddUserToTeamByToken", "api.user.create_user.signup_link_invalid.app_error", nil, err.Error(), http.StatusBadRequest) 458 } 459 460 if token.Type != TOKEN_TYPE_TEAM_INVITATION && token.Type != TOKEN_TYPE_GUEST_INVITATION { 461 return nil, model.NewAppError("AddUserToTeamByToken", "api.user.create_user.signup_link_invalid.app_error", nil, "", http.StatusBadRequest) 462 } 463 464 if model.GetMillis()-token.CreateAt >= INVITATION_EXPIRY_TIME { 465 a.DeleteToken(token) 466 return nil, model.NewAppError("AddUserToTeamByToken", "api.user.create_user.signup_link_expired.app_error", nil, "", http.StatusBadRequest) 467 } 468 469 tokenData := model.MapFromJson(strings.NewReader(token.Extra)) 470 471 tchan := make(chan store.StoreResult, 1) 472 go func() { 473 team, err := a.Srv().Store.Team().Get(tokenData["teamId"]) 474 tchan <- store.StoreResult{Data: team, Err: err} 475 close(tchan) 476 }() 477 478 uchan := make(chan store.StoreResult, 1) 479 go func() { 480 user, err := a.Srv().Store.User().Get(userId) 481 uchan <- store.StoreResult{Data: user, Err: err} 482 close(uchan) 483 }() 484 485 result := <-tchan 486 if result.Err != nil { 487 return nil, result.Err 488 } 489 team := result.Data.(*model.Team) 490 491 if team.IsGroupConstrained() { 492 return nil, model.NewAppError("AddUserToTeamByToken", "app.team.invite_token.group_constrained.error", nil, "", http.StatusForbidden) 493 } 494 495 result = <-uchan 496 if result.Err != nil { 497 return nil, result.Err 498 } 499 user := result.Data.(*model.User) 500 501 if user.IsGuest() && token.Type == TOKEN_TYPE_TEAM_INVITATION { 502 return nil, model.NewAppError("AddUserToTeamByToken", "api.user.create_user.invalid_invitation_type.app_error", nil, "", http.StatusBadRequest) 503 } 504 if !user.IsGuest() && token.Type == TOKEN_TYPE_GUEST_INVITATION { 505 return nil, model.NewAppError("AddUserToTeamByToken", "api.user.create_user.invalid_invitation_type.app_error", nil, "", http.StatusBadRequest) 506 } 507 508 if err := a.JoinUserToTeam(team, user, ""); err != nil { 509 return nil, err 510 } 511 512 if token.Type == TOKEN_TYPE_GUEST_INVITATION { 513 channels, err := a.Srv().Store.Channel().GetChannelsByIds(strings.Split(tokenData["channels"], " "), false) 514 if err != nil { 515 return nil, err 516 } 517 518 for _, channel := range channels { 519 _, err := a.AddUserToChannel(user, channel) 520 if err != nil { 521 mlog.Error("error adding user to channel", mlog.Err(err)) 522 } 523 } 524 } 525 526 if err := a.DeleteToken(token); err != nil { 527 return nil, err 528 } 529 530 return team, nil 531 } 532 533 func (a *App) AddUserToTeamByInviteId(inviteId string, userId string) (*model.Team, *model.AppError) { 534 tchan := make(chan store.StoreResult, 1) 535 go func() { 536 team, err := a.Srv().Store.Team().GetByInviteId(inviteId) 537 tchan <- store.StoreResult{Data: team, Err: err} 538 close(tchan) 539 }() 540 541 uchan := make(chan store.StoreResult, 1) 542 go func() { 543 user, err := a.Srv().Store.User().Get(userId) 544 uchan <- store.StoreResult{Data: user, Err: err} 545 close(uchan) 546 }() 547 548 result := <-tchan 549 if result.Err != nil { 550 return nil, result.Err 551 } 552 team := result.Data.(*model.Team) 553 554 result = <-uchan 555 if result.Err != nil { 556 return nil, result.Err 557 } 558 user := result.Data.(*model.User) 559 560 if err := a.JoinUserToTeam(team, user, ""); err != nil { 561 return nil, err 562 } 563 564 return team, nil 565 } 566 567 // Returns three values: 568 // 1. a pointer to the team member, if successful 569 // 2. a boolean: true if the user has a non-deleted team member for that team already, otherwise false. 570 // 3. a pointer to an AppError if something went wrong. 571 func (a *App) joinUserToTeam(team *model.Team, user *model.User) (*model.TeamMember, bool, *model.AppError) { 572 tm := &model.TeamMember{ 573 TeamId: team.Id, 574 UserId: user.Id, 575 SchemeGuest: user.IsGuest(), 576 SchemeUser: !user.IsGuest(), 577 } 578 579 if !user.IsGuest() { 580 userShouldBeAdmin, err := a.UserIsInAdminRoleGroup(user.Id, team.Id, model.GroupSyncableTypeTeam) 581 if err != nil { 582 return nil, false, err 583 } 584 tm.SchemeAdmin = userShouldBeAdmin 585 } 586 587 if team.Email == user.Email { 588 tm.SchemeAdmin = true 589 } 590 591 rtm, err := a.Srv().Store.Team().GetMember(team.Id, user.Id) 592 if err != nil { 593 // Membership appears to be missing. Lets try to add. 594 var tmr *model.TeamMember 595 tmr, err = a.Srv().Store.Team().SaveMember(tm, *a.Config().TeamSettings.MaxUsersPerTeam) 596 if err != nil { 597 return nil, false, err 598 } 599 return tmr, false, nil 600 } 601 602 // Membership already exists. Check if deleted and update, otherwise do nothing 603 // Do nothing if already added 604 if rtm.DeleteAt == 0 { 605 return rtm, true, nil 606 } 607 608 membersCount, err := a.Srv().Store.Team().GetActiveMemberCount(tm.TeamId, nil) 609 if err != nil { 610 return nil, false, err 611 } 612 613 if membersCount >= int64(*a.Config().TeamSettings.MaxUsersPerTeam) { 614 return nil, false, model.NewAppError("joinUserToTeam", "app.team.join_user_to_team.max_accounts.app_error", nil, "teamId="+tm.TeamId, http.StatusBadRequest) 615 } 616 617 member, err := a.Srv().Store.Team().UpdateMember(tm) 618 if err != nil { 619 return nil, false, err 620 } 621 622 return member, false, nil 623 } 624 625 func (a *App) JoinUserToTeam(team *model.Team, user *model.User, userRequestorId string) *model.AppError { 626 if !a.isTeamEmailAllowed(user, team) { 627 return model.NewAppError("JoinUserToTeam", "api.team.join_user_to_team.allowed_domains.app_error", nil, "", http.StatusBadRequest) 628 } 629 tm, alreadyAdded, err := a.joinUserToTeam(team, user) 630 if err != nil { 631 return err 632 } 633 if alreadyAdded { 634 return nil 635 } 636 637 if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { 638 var actor *model.User 639 if userRequestorId != "" { 640 actor, _ = a.GetUser(userRequestorId) 641 } 642 643 a.Srv().Go(func() { 644 pluginContext := a.PluginContext() 645 pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { 646 hooks.UserHasJoinedTeam(pluginContext, tm, actor) 647 return true 648 }, plugin.UserHasJoinedTeamId) 649 }) 650 } 651 652 if _, err := a.Srv().Store.User().UpdateUpdateAt(user.Id); err != nil { 653 return err 654 } 655 656 if err := a.createInitialSidebarCategories(user.Id, team.Id); err != nil { 657 mlog.Error( 658 "Encountered an issue creating default sidebar categories.", 659 mlog.String("user_id", user.Id), 660 mlog.String("team_id", team.Id), 661 mlog.Err(err), 662 ) 663 } 664 665 shouldBeAdmin := team.Email == user.Email 666 667 if !user.IsGuest() { 668 // Soft error if there is an issue joining the default channels 669 if err := a.JoinDefaultChannels(team.Id, user, shouldBeAdmin, userRequestorId); err != nil { 670 mlog.Error( 671 "Encountered an issue joining default channels.", 672 mlog.String("user_id", user.Id), 673 mlog.String("team_id", team.Id), 674 mlog.Err(err), 675 ) 676 } 677 } 678 679 a.ClearSessionCacheForUser(user.Id) 680 a.InvalidateCacheForUser(user.Id) 681 a.invalidateCacheForUserTeams(user.Id) 682 683 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", user.Id, nil) 684 message.Add("team_id", team.Id) 685 message.Add("user_id", user.Id) 686 a.Publish(message) 687 688 return nil 689 } 690 691 func (a *App) GetTeam(teamId string) (*model.Team, *model.AppError) { 692 return a.Srv().Store.Team().Get(teamId) 693 } 694 695 func (a *App) GetTeamByName(name string) (*model.Team, *model.AppError) { 696 return a.Srv().Store.Team().GetByName(name) 697 } 698 699 func (a *App) GetTeamByInviteId(inviteId string) (*model.Team, *model.AppError) { 700 return a.Srv().Store.Team().GetByInviteId(inviteId) 701 } 702 703 func (a *App) GetAllTeams() ([]*model.Team, *model.AppError) { 704 return a.Srv().Store.Team().GetAll() 705 } 706 707 func (a *App) GetAllTeamsPage(offset int, limit int) ([]*model.Team, *model.AppError) { 708 return a.Srv().Store.Team().GetAllPage(offset, limit) 709 } 710 711 func (a *App) GetAllTeamsPageWithCount(offset int, limit int) (*model.TeamsWithCount, *model.AppError) { 712 totalCount, err := a.Srv().Store.Team().AnalyticsTeamCount(true) 713 if err != nil { 714 return nil, err 715 } 716 teams, err := a.Srv().Store.Team().GetAllPage(offset, limit) 717 if err != nil { 718 return nil, err 719 } 720 return &model.TeamsWithCount{Teams: teams, TotalCount: totalCount}, nil 721 } 722 723 func (a *App) GetAllPrivateTeams() ([]*model.Team, *model.AppError) { 724 return a.Srv().Store.Team().GetAllPrivateTeamListing() 725 } 726 727 func (a *App) GetAllPrivateTeamsPage(offset int, limit int) ([]*model.Team, *model.AppError) { 728 return a.Srv().Store.Team().GetAllPrivateTeamPageListing(offset, limit) 729 } 730 731 func (a *App) GetAllPrivateTeamsPageWithCount(offset int, limit int) (*model.TeamsWithCount, *model.AppError) { 732 totalCount, err := a.Srv().Store.Team().AnalyticsPrivateTeamCount() 733 if err != nil { 734 return nil, err 735 } 736 teams, err := a.Srv().Store.Team().GetAllPrivateTeamPageListing(offset, limit) 737 if err != nil { 738 return nil, err 739 } 740 return &model.TeamsWithCount{Teams: teams, TotalCount: totalCount}, nil 741 } 742 743 func (a *App) GetAllPublicTeams() ([]*model.Team, *model.AppError) { 744 return a.Srv().Store.Team().GetAllTeamListing() 745 } 746 747 func (a *App) GetAllPublicTeamsPage(offset int, limit int) ([]*model.Team, *model.AppError) { 748 return a.Srv().Store.Team().GetAllTeamPageListing(offset, limit) 749 } 750 751 func (a *App) GetAllPublicTeamsPageWithCount(offset int, limit int) (*model.TeamsWithCount, *model.AppError) { 752 totalCount, err := a.Srv().Store.Team().AnalyticsPublicTeamCount() 753 if err != nil { 754 return nil, err 755 } 756 teams, err := a.Srv().Store.Team().GetAllPublicTeamPageListing(offset, limit) 757 if err != nil { 758 return nil, err 759 } 760 return &model.TeamsWithCount{Teams: teams, TotalCount: totalCount}, nil 761 } 762 763 // SearchAllTeams returns a team list and the total count of the results 764 func (a *App) SearchAllTeams(searchOpts *model.TeamSearch) ([]*model.Team, int64, *model.AppError) { 765 if searchOpts.IsPaginated() { 766 return a.Srv().Store.Team().SearchAllPaged(searchOpts.Term, searchOpts) 767 } 768 results, err := a.Srv().Store.Team().SearchAll(searchOpts.Term, searchOpts) 769 return results, int64(len(results)), err 770 } 771 772 func (a *App) SearchPublicTeams(term string) ([]*model.Team, *model.AppError) { 773 return a.Srv().Store.Team().SearchOpen(term) 774 } 775 776 func (a *App) SearchPrivateTeams(term string) ([]*model.Team, *model.AppError) { 777 return a.Srv().Store.Team().SearchPrivate(term) 778 } 779 780 func (a *App) GetTeamsForUser(userId string) ([]*model.Team, *model.AppError) { 781 return a.Srv().Store.Team().GetTeamsByUserId(userId) 782 } 783 784 func (a *App) GetTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError) { 785 return a.Srv().Store.Team().GetMember(teamId, userId) 786 } 787 788 func (a *App) GetTeamMembersForUser(userId string) ([]*model.TeamMember, *model.AppError) { 789 return a.Srv().Store.Team().GetTeamsForUser(userId) 790 } 791 792 func (a *App) GetTeamMembersForUserWithPagination(userId string, page, perPage int) ([]*model.TeamMember, *model.AppError) { 793 return a.Srv().Store.Team().GetTeamsForUserWithPagination(userId, page, perPage) 794 } 795 796 func (a *App) GetTeamMembers(teamId string, offset int, limit int, teamMembersGetOptions *model.TeamMembersGetOptions) ([]*model.TeamMember, *model.AppError) { 797 return a.Srv().Store.Team().GetMembers(teamId, offset, limit, teamMembersGetOptions) 798 } 799 800 func (a *App) GetTeamMembersByIds(teamId string, userIds []string, restrictions *model.ViewUsersRestrictions) ([]*model.TeamMember, *model.AppError) { 801 return a.Srv().Store.Team().GetMembersByIds(teamId, userIds, restrictions) 802 } 803 804 func (a *App) AddTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError) { 805 if _, err := a.AddUserToTeam(teamId, userId, ""); err != nil { 806 return nil, err 807 } 808 809 teamMember, err := a.GetTeamMember(teamId, userId) 810 if err != nil { 811 return nil, err 812 } 813 814 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", userId, nil) 815 message.Add("team_id", teamId) 816 message.Add("user_id", userId) 817 a.Publish(message) 818 819 return teamMember, nil 820 } 821 822 func (a *App) AddTeamMembers(teamId string, userIds []string, userRequestorId string, graceful bool) ([]*model.TeamMemberWithError, *model.AppError) { 823 var membersWithErrors []*model.TeamMemberWithError 824 825 for _, userId := range userIds { 826 if _, err := a.AddUserToTeam(teamId, userId, userRequestorId); err != nil { 827 if graceful { 828 membersWithErrors = append(membersWithErrors, &model.TeamMemberWithError{ 829 UserId: userId, 830 Error: err, 831 }) 832 continue 833 } 834 return nil, err 835 } 836 837 teamMember, err := a.GetTeamMember(teamId, userId) 838 if err != nil { 839 return nil, err 840 } 841 membersWithErrors = append(membersWithErrors, &model.TeamMemberWithError{ 842 UserId: userId, 843 Member: teamMember, 844 }) 845 846 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", userId, nil) 847 message.Add("team_id", teamId) 848 message.Add("user_id", userId) 849 a.Publish(message) 850 } 851 852 return membersWithErrors, nil 853 } 854 855 func (a *App) AddTeamMemberByToken(userId, tokenId string) (*model.TeamMember, *model.AppError) { 856 team, err := a.AddUserToTeamByToken(userId, tokenId) 857 if err != nil { 858 return nil, err 859 } 860 861 teamMember, err := a.GetTeamMember(team.Id, userId) 862 if err != nil { 863 return nil, err 864 } 865 866 return teamMember, nil 867 } 868 869 func (a *App) AddTeamMemberByInviteId(inviteId, userId string) (*model.TeamMember, *model.AppError) { 870 team, err := a.AddUserToTeamByInviteId(inviteId, userId) 871 if err != nil { 872 return nil, err 873 } 874 875 if team.IsGroupConstrained() { 876 return nil, model.NewAppError("AddTeamMemberByInviteId", "app.team.invite_id.group_constrained.error", nil, "", http.StatusForbidden) 877 } 878 879 teamMember, err := a.GetTeamMember(team.Id, userId) 880 if err != nil { 881 return nil, err 882 } 883 return teamMember, nil 884 } 885 886 func (a *App) GetTeamUnread(teamId, userId string) (*model.TeamUnread, *model.AppError) { 887 channelUnreads, err := a.Srv().Store.Team().GetChannelUnreadsForTeam(teamId, userId) 888 if err != nil { 889 return nil, err 890 } 891 892 var teamUnread = &model.TeamUnread{ 893 MsgCount: 0, 894 MentionCount: 0, 895 TeamId: teamId, 896 } 897 898 for _, cu := range channelUnreads { 899 teamUnread.MentionCount += cu.MentionCount 900 901 if cu.NotifyProps[model.MARK_UNREAD_NOTIFY_PROP] != model.CHANNEL_MARK_UNREAD_MENTION { 902 teamUnread.MsgCount += cu.MsgCount 903 } 904 } 905 906 return teamUnread, nil 907 } 908 909 func (a *App) RemoveUserFromTeam(teamId string, userId string, requestorId string) *model.AppError { 910 tchan := make(chan store.StoreResult, 1) 911 go func() { 912 team, err := a.Srv().Store.Team().Get(teamId) 913 tchan <- store.StoreResult{Data: team, Err: err} 914 close(tchan) 915 }() 916 917 uchan := make(chan store.StoreResult, 1) 918 go func() { 919 user, err := a.Srv().Store.User().Get(userId) 920 uchan <- store.StoreResult{Data: user, Err: err} 921 close(uchan) 922 }() 923 924 result := <-tchan 925 if result.Err != nil { 926 return result.Err 927 } 928 team := result.Data.(*model.Team) 929 930 result = <-uchan 931 if result.Err != nil { 932 return result.Err 933 } 934 user := result.Data.(*model.User) 935 936 if err := a.LeaveTeam(team, user, requestorId); err != nil { 937 return err 938 } 939 940 return nil 941 } 942 943 func (a *App) RemoveTeamMemberFromTeam(teamMember *model.TeamMember, requestorId string) *model.AppError { 944 // Send the websocket message before we actually do the remove so the user being removed gets it. 945 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_LEAVE_TEAM, teamMember.TeamId, "", "", nil) 946 message.Add("user_id", teamMember.UserId) 947 message.Add("team_id", teamMember.TeamId) 948 a.Publish(message) 949 950 user, err := a.Srv().Store.User().Get(teamMember.UserId) 951 if err != nil { 952 return err 953 } 954 955 teamMember.Roles = "" 956 teamMember.DeleteAt = model.GetMillis() 957 958 if _, err := a.Srv().Store.Team().UpdateMember(teamMember); err != nil { 959 return err 960 } 961 962 if pluginsEnvironment := a.GetPluginsEnvironment(); pluginsEnvironment != nil { 963 var actor *model.User 964 if requestorId != "" { 965 actor, _ = a.GetUser(requestorId) 966 } 967 968 a.Srv().Go(func() { 969 pluginContext := a.PluginContext() 970 pluginsEnvironment.RunMultiPluginHook(func(hooks plugin.Hooks) bool { 971 hooks.UserHasLeftTeam(pluginContext, teamMember, actor) 972 return true 973 }, plugin.UserHasLeftTeamId) 974 }) 975 } 976 977 if _, err := a.Srv().Store.User().UpdateUpdateAt(user.Id); err != nil { 978 return err 979 } 980 981 if err := a.Srv().Store.Channel().ClearSidebarOnTeamLeave(user.Id, teamMember.TeamId); err != nil { 982 return err 983 } 984 985 // delete the preferences that set the last channel used in the team and other team specific preferences 986 if err := a.Srv().Store.Preference().DeleteCategory(user.Id, teamMember.TeamId); err != nil { 987 return model.NewAppError("RemoveTeamMemberFromTeam", "app.preference.delete.app_error", nil, err.Error(), http.StatusInternalServerError) 988 } 989 990 a.ClearSessionCacheForUser(user.Id) 991 a.InvalidateCacheForUser(user.Id) 992 a.invalidateCacheForUserTeams(user.Id) 993 994 return nil 995 } 996 997 func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string) *model.AppError { 998 teamMember, err := a.GetTeamMember(team.Id, user.Id) 999 if err != nil { 1000 return model.NewAppError("LeaveTeam", "api.team.remove_user_from_team.missing.app_error", nil, err.Error(), http.StatusBadRequest) 1001 } 1002 1003 var channelList *model.ChannelList 1004 1005 var nErr error 1006 if channelList, nErr = a.Srv().Store.Channel().GetChannels(team.Id, user.Id, true, 0); nErr != nil { 1007 var nfErr *store.ErrNotFound 1008 if errors.As(nErr, &nfErr) { 1009 channelList = &model.ChannelList{} 1010 } else { 1011 return model.NewAppError("LeaveTeam", "app.channel.get_channels.get.app_error", nil, nErr.Error(), http.StatusInternalServerError) 1012 } 1013 } 1014 1015 for _, channel := range *channelList { 1016 if !channel.IsGroupOrDirect() { 1017 a.invalidateCacheForChannelMembers(channel.Id) 1018 if err = a.Srv().Store.Channel().RemoveMember(channel.Id, user.Id); err != nil { 1019 return err 1020 } 1021 } 1022 } 1023 1024 channel, nErr := a.Srv().Store.Channel().GetByName(team.Id, model.DEFAULT_CHANNEL, false) 1025 if nErr != nil { 1026 var nfErr *store.ErrNotFound 1027 switch { 1028 case errors.As(nErr, &nfErr): 1029 return model.NewAppError("LeaveTeam", "app.channel.get_by_name.missing.app_error", nil, nfErr.Error(), http.StatusNotFound) 1030 default: 1031 return model.NewAppError("LeaveTeam", "app.channel.get_by_name.existing.app_error", nil, nErr.Error(), http.StatusInternalServerError) 1032 } 1033 } 1034 1035 if *a.Config().ServiceSettings.ExperimentalEnableDefaultChannelLeaveJoinMessages { 1036 if requestorId == user.Id { 1037 if err = a.postLeaveTeamMessage(user, channel); err != nil { 1038 mlog.Error("Failed to post join/leave message", mlog.Err(err)) 1039 } 1040 } else { 1041 if err = a.postRemoveFromTeamMessage(user, channel); err != nil { 1042 mlog.Error("Failed to post join/leave message", mlog.Err(err)) 1043 } 1044 } 1045 } 1046 1047 if err := a.RemoveTeamMemberFromTeam(teamMember, requestorId); err != nil { 1048 return err 1049 } 1050 1051 return nil 1052 } 1053 1054 func (a *App) postLeaveTeamMessage(user *model.User, channel *model.Channel) *model.AppError { 1055 post := &model.Post{ 1056 ChannelId: channel.Id, 1057 Message: fmt.Sprintf(utils.T("api.team.leave.left"), user.Username), 1058 Type: model.POST_LEAVE_TEAM, 1059 UserId: user.Id, 1060 Props: model.StringInterface{ 1061 "username": user.Username, 1062 }, 1063 } 1064 1065 if _, err := a.CreatePost(post, channel, false, true); err != nil { 1066 return model.NewAppError("postRemoveFromChannelMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, err.Error(), http.StatusInternalServerError) 1067 } 1068 1069 return nil 1070 } 1071 1072 func (a *App) postRemoveFromTeamMessage(user *model.User, channel *model.Channel) *model.AppError { 1073 post := &model.Post{ 1074 ChannelId: channel.Id, 1075 Message: fmt.Sprintf(utils.T("api.team.remove_user_from_team.removed"), user.Username), 1076 Type: model.POST_REMOVE_FROM_TEAM, 1077 UserId: user.Id, 1078 Props: model.StringInterface{ 1079 "username": user.Username, 1080 }, 1081 } 1082 1083 if _, err := a.CreatePost(post, channel, false, true); err != nil { 1084 return model.NewAppError("postRemoveFromTeamMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, err.Error(), http.StatusInternalServerError) 1085 } 1086 1087 return nil 1088 } 1089 1090 func (a *App) prepareInviteNewUsersToTeam(teamId, senderId string) (*model.User, *model.Team, *model.AppError) { 1091 tchan := make(chan store.StoreResult, 1) 1092 go func() { 1093 team, err := a.Srv().Store.Team().Get(teamId) 1094 tchan <- store.StoreResult{Data: team, Err: err} 1095 close(tchan) 1096 }() 1097 1098 uchan := make(chan store.StoreResult, 1) 1099 go func() { 1100 user, err := a.Srv().Store.User().Get(senderId) 1101 uchan <- store.StoreResult{Data: user, Err: err} 1102 close(uchan) 1103 }() 1104 1105 result := <-tchan 1106 if result.Err != nil { 1107 return nil, nil, result.Err 1108 } 1109 team := result.Data.(*model.Team) 1110 1111 result = <-uchan 1112 if result.Err != nil { 1113 return nil, nil, result.Err 1114 } 1115 user := result.Data.(*model.User) 1116 return user, team, nil 1117 } 1118 1119 func (a *App) InviteNewUsersToTeamGracefully(emailList []string, teamId, senderId string) ([]*model.EmailInviteWithError, *model.AppError) { 1120 if !*a.Config().ServiceSettings.EnableEmailInvitations { 1121 return nil, model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented) 1122 } 1123 1124 if len(emailList) == 0 { 1125 err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.no_one.app_error", nil, "", http.StatusBadRequest) 1126 return nil, err 1127 } 1128 1129 user, team, err := a.prepareInviteNewUsersToTeam(teamId, senderId) 1130 if err != nil { 1131 return nil, err 1132 } 1133 allowedDomains := a.getAllowedDomains(user, team) 1134 var inviteListWithErrors []*model.EmailInviteWithError 1135 var goodEmails []string 1136 for _, email := range emailList { 1137 invite := &model.EmailInviteWithError{ 1138 Email: email, 1139 Error: nil, 1140 } 1141 if !a.isEmailAddressAllowed(email, allowedDomains) { 1142 invite.Error = model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": email}, "", http.StatusBadRequest) 1143 } else { 1144 goodEmails = append(goodEmails, email) 1145 } 1146 inviteListWithErrors = append(inviteListWithErrors, invite) 1147 } 1148 1149 if len(goodEmails) > 0 { 1150 nameFormat := *a.Config().TeamSettings.TeammateNameDisplay 1151 a.Srv().EmailService.SendInviteEmails(team, user.GetDisplayName(nameFormat), user.Id, goodEmails, a.GetSiteURL()) 1152 } 1153 1154 return inviteListWithErrors, nil 1155 } 1156 1157 func (a *App) prepareInviteGuestsToChannels(teamId string, guestsInvite *model.GuestsInvite, senderId string) (*model.User, *model.Team, []*model.Channel, *model.AppError) { 1158 if err := guestsInvite.IsValid(); err != nil { 1159 return nil, nil, nil, err 1160 } 1161 1162 tchan := make(chan store.StoreResult, 1) 1163 go func() { 1164 team, err := a.Srv().Store.Team().Get(teamId) 1165 tchan <- store.StoreResult{Data: team, Err: err} 1166 close(tchan) 1167 }() 1168 cchan := make(chan store.StoreResult, 1) 1169 go func() { 1170 channels, err := a.Srv().Store.Channel().GetChannelsByIds(guestsInvite.Channels, false) 1171 cchan <- store.StoreResult{Data: channels, Err: err} 1172 close(cchan) 1173 }() 1174 uchan := make(chan store.StoreResult, 1) 1175 go func() { 1176 user, err := a.Srv().Store.User().Get(senderId) 1177 uchan <- store.StoreResult{Data: user, Err: err} 1178 close(uchan) 1179 }() 1180 1181 result := <-cchan 1182 if result.Err != nil { 1183 return nil, nil, nil, result.Err 1184 } 1185 channels := result.Data.([]*model.Channel) 1186 1187 result = <-uchan 1188 if result.Err != nil { 1189 return nil, nil, nil, result.Err 1190 } 1191 user := result.Data.(*model.User) 1192 1193 result = <-tchan 1194 if result.Err != nil { 1195 return nil, nil, nil, result.Err 1196 } 1197 team := result.Data.(*model.Team) 1198 1199 for _, channel := range channels { 1200 if channel.TeamId != teamId { 1201 return nil, nil, nil, model.NewAppError("InviteGuestsToChannels", "api.team.invite_guests.channel_in_invalid_team.app_error", nil, "", http.StatusBadRequest) 1202 } 1203 } 1204 return user, team, channels, nil 1205 } 1206 1207 func (a *App) InviteGuestsToChannelsGracefully(teamId string, guestsInvite *model.GuestsInvite, senderId string) ([]*model.EmailInviteWithError, *model.AppError) { 1208 if !*a.Config().ServiceSettings.EnableEmailInvitations { 1209 return nil, model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented) 1210 } 1211 1212 user, team, channels, err := a.prepareInviteGuestsToChannels(teamId, guestsInvite, senderId) 1213 if err != nil { 1214 return nil, err 1215 } 1216 1217 var inviteListWithErrors []*model.EmailInviteWithError 1218 var goodEmails []string 1219 for _, email := range guestsInvite.Emails { 1220 invite := &model.EmailInviteWithError{ 1221 Email: email, 1222 Error: nil, 1223 } 1224 if !CheckEmailDomain(email, *a.Config().GuestAccountsSettings.RestrictCreationToDomains) { 1225 invite.Error = model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": email}, "", http.StatusBadRequest) 1226 } else { 1227 goodEmails = append(goodEmails, email) 1228 } 1229 inviteListWithErrors = append(inviteListWithErrors, invite) 1230 } 1231 1232 if len(goodEmails) > 0 { 1233 nameFormat := *a.Config().TeamSettings.TeammateNameDisplay 1234 senderProfileImage, _, err := a.GetProfileImage(user) 1235 if err != nil { 1236 a.Log().Warn("Unable to get the sender user profile image.", mlog.String("user_id", user.Id), mlog.String("team_id", team.Id), mlog.Err(err)) 1237 } 1238 a.Srv().EmailService.sendGuestInviteEmails(team, channels, user.GetDisplayName(nameFormat), user.Id, senderProfileImage, goodEmails, a.GetSiteURL(), guestsInvite.Message) 1239 } 1240 1241 return inviteListWithErrors, nil 1242 } 1243 1244 func (a *App) InviteNewUsersToTeam(emailList []string, teamId, senderId string) *model.AppError { 1245 if !*a.Config().ServiceSettings.EnableEmailInvitations { 1246 return model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented) 1247 } 1248 1249 if len(emailList) == 0 { 1250 err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.no_one.app_error", nil, "", http.StatusBadRequest) 1251 return err 1252 } 1253 1254 user, team, err := a.prepareInviteNewUsersToTeam(teamId, senderId) 1255 if err != nil { 1256 return err 1257 } 1258 1259 allowedDomains := a.getAllowedDomains(user, team) 1260 var invalidEmailList []string 1261 1262 for _, email := range emailList { 1263 if !a.isEmailAddressAllowed(email, allowedDomains) { 1264 invalidEmailList = append(invalidEmailList, email) 1265 } 1266 } 1267 1268 if len(invalidEmailList) > 0 { 1269 s := strings.Join(invalidEmailList, ", ") 1270 err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": s}, "", http.StatusBadRequest) 1271 return err 1272 } 1273 1274 nameFormat := *a.Config().TeamSettings.TeammateNameDisplay 1275 a.Srv().EmailService.SendInviteEmails(team, user.GetDisplayName(nameFormat), user.Id, emailList, a.GetSiteURL()) 1276 1277 return nil 1278 } 1279 1280 func (a *App) InviteGuestsToChannels(teamId string, guestsInvite *model.GuestsInvite, senderId string) *model.AppError { 1281 if !*a.Config().ServiceSettings.EnableEmailInvitations { 1282 return model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented) 1283 } 1284 1285 user, team, channels, err := a.prepareInviteGuestsToChannels(teamId, guestsInvite, senderId) 1286 if err != nil { 1287 return err 1288 } 1289 1290 var invalidEmailList []string 1291 for _, email := range guestsInvite.Emails { 1292 if !CheckEmailDomain(email, *a.Config().GuestAccountsSettings.RestrictCreationToDomains) { 1293 invalidEmailList = append(invalidEmailList, email) 1294 } 1295 } 1296 1297 if len(invalidEmailList) > 0 { 1298 s := strings.Join(invalidEmailList, ", ") 1299 return model.NewAppError("InviteGuestsToChannels", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": s}, "", http.StatusBadRequest) 1300 } 1301 1302 nameFormat := *a.Config().TeamSettings.TeammateNameDisplay 1303 senderProfileImage, _, err := a.GetProfileImage(user) 1304 if err != nil { 1305 a.Log().Warn("Unable to get the sender user profile image.", mlog.String("user_id", user.Id), mlog.String("team_id", team.Id), mlog.Err(err)) 1306 } 1307 a.Srv().EmailService.sendGuestInviteEmails(team, channels, user.GetDisplayName(nameFormat), user.Id, senderProfileImage, guestsInvite.Emails, a.GetSiteURL(), guestsInvite.Message) 1308 1309 return nil 1310 } 1311 1312 func (a *App) FindTeamByName(name string) bool { 1313 if _, err := a.Srv().Store.Team().GetByName(name); err != nil { 1314 return false 1315 } 1316 return true 1317 } 1318 1319 func (a *App) GetTeamsUnreadForUser(excludeTeamId string, userId string) ([]*model.TeamUnread, *model.AppError) { 1320 data, err := a.Srv().Store.Team().GetChannelUnreadsForAllTeams(excludeTeamId, userId) 1321 if err != nil { 1322 return nil, err 1323 } 1324 members := []*model.TeamUnread{} 1325 membersMap := make(map[string]*model.TeamUnread) 1326 1327 unreads := func(cu *model.ChannelUnread, tu *model.TeamUnread) *model.TeamUnread { 1328 tu.MentionCount += cu.MentionCount 1329 1330 if cu.NotifyProps[model.MARK_UNREAD_NOTIFY_PROP] != model.CHANNEL_MARK_UNREAD_MENTION { 1331 tu.MsgCount += cu.MsgCount 1332 } 1333 1334 return tu 1335 } 1336 1337 for i := range data { 1338 id := data[i].TeamId 1339 if mu, ok := membersMap[id]; ok { 1340 membersMap[id] = unreads(data[i], mu) 1341 } else { 1342 membersMap[id] = unreads(data[i], &model.TeamUnread{ 1343 MsgCount: 0, 1344 MentionCount: 0, 1345 TeamId: id, 1346 }) 1347 } 1348 } 1349 1350 for _, val := range membersMap { 1351 members = append(members, val) 1352 } 1353 1354 return members, nil 1355 } 1356 1357 func (a *App) PermanentDeleteTeamId(teamId string) *model.AppError { 1358 team, err := a.GetTeam(teamId) 1359 if err != nil { 1360 return err 1361 } 1362 1363 return a.PermanentDeleteTeam(team) 1364 } 1365 1366 func (a *App) PermanentDeleteTeam(team *model.Team) *model.AppError { 1367 team.DeleteAt = model.GetMillis() 1368 if _, err := a.Srv().Store.Team().Update(team); err != nil { 1369 return err 1370 } 1371 1372 if channels, err := a.Srv().Store.Channel().GetTeamChannels(team.Id); err != nil { 1373 if err.Id != "app.channel.get_channels.not_found.app_error" { 1374 return err 1375 } 1376 } else { 1377 for _, c := range *channels { 1378 a.PermanentDeleteChannel(c) 1379 } 1380 } 1381 1382 if err := a.Srv().Store.Team().RemoveAllMembersByTeam(team.Id); err != nil { 1383 return err 1384 } 1385 1386 if err := a.Srv().Store.Command().PermanentDeleteByTeam(team.Id); err != nil { 1387 return model.NewAppError("PermanentDeleteTeam", "app.team.permanentdeleteteam.internal_error", nil, err.Error(), http.StatusInternalServerError) 1388 } 1389 1390 if err := a.Srv().Store.Team().PermanentDelete(team.Id); err != nil { 1391 return err 1392 } 1393 1394 a.sendTeamEvent(team, model.WEBSOCKET_EVENT_DELETE_TEAM) 1395 1396 return nil 1397 } 1398 1399 func (a *App) SoftDeleteTeam(teamId string) *model.AppError { 1400 team, err := a.GetTeam(teamId) 1401 if err != nil { 1402 return err 1403 } 1404 1405 team.DeleteAt = model.GetMillis() 1406 if team, err = a.Srv().Store.Team().Update(team); err != nil { 1407 return err 1408 } 1409 1410 a.sendTeamEvent(team, model.WEBSOCKET_EVENT_DELETE_TEAM) 1411 1412 return nil 1413 } 1414 1415 func (a *App) RestoreTeam(teamId string) *model.AppError { 1416 team, err := a.GetTeam(teamId) 1417 if err != nil { 1418 return err 1419 } 1420 1421 team.DeleteAt = 0 1422 if team, err = a.Srv().Store.Team().Update(team); err != nil { 1423 return err 1424 } 1425 1426 a.sendTeamEvent(team, model.WEBSOCKET_EVENT_RESTORE_TEAM) 1427 return nil 1428 } 1429 1430 func (a *App) GetTeamStats(teamId string, restrictions *model.ViewUsersRestrictions) (*model.TeamStats, *model.AppError) { 1431 tchan := make(chan store.StoreResult, 1) 1432 go func() { 1433 totalMemberCount, err := a.Srv().Store.Team().GetTotalMemberCount(teamId, restrictions) 1434 tchan <- store.StoreResult{Data: totalMemberCount, Err: err} 1435 close(tchan) 1436 }() 1437 achan := make(chan store.StoreResult, 1) 1438 go func() { 1439 memberCount, err := a.Srv().Store.Team().GetActiveMemberCount(teamId, restrictions) 1440 achan <- store.StoreResult{Data: memberCount, Err: err} 1441 close(achan) 1442 }() 1443 1444 stats := &model.TeamStats{} 1445 stats.TeamId = teamId 1446 1447 result := <-tchan 1448 if result.Err != nil { 1449 return nil, result.Err 1450 } 1451 stats.TotalMemberCount = result.Data.(int64) 1452 1453 result = <-achan 1454 if result.Err != nil { 1455 return nil, result.Err 1456 } 1457 stats.ActiveMemberCount = result.Data.(int64) 1458 1459 return stats, nil 1460 } 1461 1462 func (a *App) GetTeamIdFromQuery(query url.Values) (string, *model.AppError) { 1463 tokenId := query.Get("t") 1464 inviteId := query.Get("id") 1465 1466 if len(tokenId) > 0 { 1467 token, err := a.Srv().Store.Token().GetByToken(tokenId) 1468 if err != nil { 1469 return "", model.NewAppError("GetTeamIdFromQuery", "api.oauth.singup_with_oauth.invalid_link.app_error", nil, "", http.StatusBadRequest) 1470 } 1471 1472 if token.Type != TOKEN_TYPE_TEAM_INVITATION && token.Type != TOKEN_TYPE_GUEST_INVITATION { 1473 return "", model.NewAppError("GetTeamIdFromQuery", "api.oauth.singup_with_oauth.invalid_link.app_error", nil, "", http.StatusBadRequest) 1474 } 1475 1476 if model.GetMillis()-token.CreateAt >= INVITATION_EXPIRY_TIME { 1477 a.DeleteToken(token) 1478 return "", model.NewAppError("GetTeamIdFromQuery", "api.oauth.singup_with_oauth.expired_link.app_error", nil, "", http.StatusBadRequest) 1479 } 1480 1481 tokenData := model.MapFromJson(strings.NewReader(token.Extra)) 1482 1483 return tokenData["teamId"], nil 1484 } 1485 if len(inviteId) > 0 { 1486 team, err := a.Srv().Store.Team().GetByInviteId(inviteId) 1487 if err == nil { 1488 return team.Id, nil 1489 } 1490 // soft fail, so we still create user but don't auto-join team 1491 mlog.Error("error getting team by inviteId.", mlog.String("invite_id", inviteId), mlog.Err(err)) 1492 } 1493 1494 return "", nil 1495 } 1496 1497 func (a *App) SanitizeTeam(session model.Session, team *model.Team) *model.Team { 1498 if a.SessionHasPermissionToTeam(session, team.Id, model.PERMISSION_MANAGE_TEAM) { 1499 return team 1500 } 1501 1502 if a.SessionHasPermissionToTeam(session, team.Id, model.PERMISSION_INVITE_USER) { 1503 inviteId := team.InviteId 1504 team.Sanitize() 1505 team.InviteId = inviteId 1506 return team 1507 } 1508 1509 team.Sanitize() 1510 1511 return team 1512 } 1513 1514 func (a *App) SanitizeTeams(session model.Session, teams []*model.Team) []*model.Team { 1515 for _, team := range teams { 1516 a.SanitizeTeam(session, team) 1517 } 1518 1519 return teams 1520 } 1521 1522 func (a *App) GetTeamIcon(team *model.Team) ([]byte, *model.AppError) { 1523 if len(*a.Config().FileSettings.DriverName) == 0 { 1524 return nil, model.NewAppError("GetTeamIcon", "api.team.get_team_icon.filesettings_no_driver.app_error", nil, "", http.StatusNotImplemented) 1525 } 1526 1527 path := "teams/" + team.Id + "/teamIcon.png" 1528 data, err := a.ReadFile(path) 1529 if err != nil { 1530 return nil, model.NewAppError("GetTeamIcon", "api.team.get_team_icon.read_file.app_error", nil, err.Error(), http.StatusNotFound) 1531 } 1532 1533 return data, nil 1534 } 1535 1536 func (a *App) SetTeamIcon(teamId string, imageData *multipart.FileHeader) *model.AppError { 1537 file, err := imageData.Open() 1538 if err != nil { 1539 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.open.app_error", nil, err.Error(), http.StatusBadRequest) 1540 } 1541 defer file.Close() 1542 return a.SetTeamIconFromMultiPartFile(teamId, file) 1543 } 1544 1545 func (a *App) SetTeamIconFromMultiPartFile(teamId string, file multipart.File) *model.AppError { 1546 team, getTeamErr := a.GetTeam(teamId) 1547 1548 if getTeamErr != nil { 1549 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.get_team.app_error", nil, getTeamErr.Error(), http.StatusBadRequest) 1550 } 1551 1552 if len(*a.Config().FileSettings.DriverName) == 0 { 1553 return model.NewAppError("setTeamIcon", "api.team.set_team_icon.storage.app_error", nil, "", http.StatusNotImplemented) 1554 } 1555 1556 // Decode image config first to check dimensions before loading the whole thing into memory later on 1557 config, _, err := image.DecodeConfig(file) 1558 if err != nil { 1559 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.decode_config.app_error", nil, err.Error(), http.StatusBadRequest) 1560 } 1561 1562 // This casting is done to prevent overflow on 32 bit systems (not needed 1563 // in 64 bits systems because images can't have more than 32 bits height or 1564 // width) 1565 if int64(config.Width)*int64(config.Height) > model.MaxImageSize { 1566 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.too_large.app_error", nil, "", http.StatusBadRequest) 1567 } 1568 1569 file.Seek(0, 0) 1570 1571 return a.SetTeamIconFromFile(team, file) 1572 } 1573 1574 func (a *App) SetTeamIconFromFile(team *model.Team, file io.Reader) *model.AppError { 1575 // Decode image into Image object 1576 img, _, err := image.Decode(file) 1577 if err != nil { 1578 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.decode.app_error", nil, err.Error(), http.StatusBadRequest) 1579 } 1580 1581 orientation, _ := getImageOrientation(file) 1582 img = makeImageUpright(img, orientation) 1583 1584 // Scale team icon 1585 teamIconWidthAndHeight := 128 1586 img = imaging.Fill(img, teamIconWidthAndHeight, teamIconWidthAndHeight, imaging.Center, imaging.Lanczos) 1587 1588 buf := new(bytes.Buffer) 1589 err = png.Encode(buf, img) 1590 if err != nil { 1591 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.encode.app_error", nil, err.Error(), http.StatusInternalServerError) 1592 } 1593 1594 path := "teams/" + team.Id + "/teamIcon.png" 1595 1596 if _, err := a.WriteFile(buf, path); err != nil { 1597 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.write_file.app_error", nil, "", http.StatusInternalServerError) 1598 } 1599 1600 curTime := model.GetMillis() 1601 1602 if err := a.Srv().Store.Team().UpdateLastTeamIconUpdate(team.Id, curTime); err != nil { 1603 return model.NewAppError("SetTeamIcon", "api.team.team_icon.update.app_error", nil, err.Error(), http.StatusBadRequest) 1604 } 1605 1606 // manually set time to avoid possible cluster inconsistencies 1607 team.LastTeamIconUpdate = curTime 1608 1609 a.sendTeamEvent(team, model.WEBSOCKET_EVENT_UPDATE_TEAM) 1610 1611 return nil 1612 } 1613 1614 func (a *App) RemoveTeamIcon(teamId string) *model.AppError { 1615 team, err := a.GetTeam(teamId) 1616 if err != nil { 1617 return model.NewAppError("RemoveTeamIcon", "api.team.remove_team_icon.get_team.app_error", nil, err.Error(), http.StatusBadRequest) 1618 } 1619 1620 if err := a.Srv().Store.Team().UpdateLastTeamIconUpdate(teamId, 0); err != nil { 1621 return model.NewAppError("RemoveTeamIcon", "api.team.team_icon.update.app_error", nil, err.Error(), http.StatusBadRequest) 1622 } 1623 1624 team.LastTeamIconUpdate = 0 1625 1626 a.sendTeamEvent(team, model.WEBSOCKET_EVENT_UPDATE_TEAM) 1627 1628 return nil 1629 } 1630 1631 func (a *App) InvalidateAllEmailInvites() *model.AppError { 1632 if err := a.Srv().Store.Token().RemoveAllTokensByType(TOKEN_TYPE_TEAM_INVITATION); err != nil { 1633 return model.NewAppError("InvalidateAllEmailInvites", "api.team.invalidate_all_email_invites.app_error", nil, err.Error(), http.StatusBadRequest) 1634 } 1635 if err := a.Srv().Store.Token().RemoveAllTokensByType(TOKEN_TYPE_GUEST_INVITATION); err != nil { 1636 return model.NewAppError("InvalidateAllEmailInvites", "api.team.invalidate_all_email_invites.app_error", nil, err.Error(), http.StatusBadRequest) 1637 } 1638 return nil 1639 } 1640 1641 func (a *App) ClearTeamMembersCache(teamID string) { 1642 perPage := 100 1643 page := 0 1644 1645 for { 1646 teamMembers, err := a.Srv().Store.Team().GetMembers(teamID, page*perPage, perPage, nil) 1647 if err != nil { 1648 a.Log().Warn("error clearing cache for team members", mlog.String("team_id", teamID), mlog.String("err", err.Error())) 1649 break 1650 } 1651 1652 for _, teamMember := range teamMembers { 1653 a.ClearSessionCacheForUser(teamMember.UserId) 1654 1655 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_MEMBERROLE_UPDATED, "", "", teamMember.UserId, nil) 1656 message.Add("member", teamMember.ToJson()) 1657 a.Publish(message) 1658 } 1659 1660 length := len(teamMembers) 1661 if length < perPage { 1662 break 1663 } 1664 1665 page++ 1666 } 1667 }