github.com/jlevesy/mattermost-server@v5.3.2-0.20181003190404-7468f35cb0c8+incompatible/app/team.go (about) 1 // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package app 5 6 import ( 7 "bytes" 8 "fmt" 9 "image" 10 "image/png" 11 "mime/multipart" 12 "net/http" 13 "net/url" 14 "strings" 15 16 "github.com/disintegration/imaging" 17 18 "github.com/mattermost/mattermost-server/mlog" 19 "github.com/mattermost/mattermost-server/model" 20 "github.com/mattermost/mattermost-server/plugin" 21 "github.com/mattermost/mattermost-server/utils" 22 ) 23 24 func (a *App) CreateTeam(team *model.Team) (*model.Team, *model.AppError) { 25 if result := <-a.Srv.Store.Team().Save(team); result.Err != nil { 26 return nil, result.Err 27 } else { 28 rteam := result.Data.(*model.Team) 29 30 if _, err := a.CreateDefaultChannels(rteam.Id); err != nil { 31 return nil, err 32 } 33 34 return rteam, nil 35 } 36 } 37 38 func (a *App) CreateTeamWithUser(team *model.Team, userId string) (*model.Team, *model.AppError) { 39 var user *model.User 40 var err *model.AppError 41 if user, err = a.GetUser(userId); err != nil { 42 return nil, err 43 } else { 44 team.Email = user.Email 45 } 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 var rteam *model.Team 52 if rteam, err = a.CreateTeam(team); 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) isTeamEmailAddressAllowed(email string, allowedDomains string) bool { 70 email = strings.ToLower(email) 71 // First check per team allowedDomains, then app wide restrictions 72 for _, restriction := range []string{allowedDomains, a.Config().TeamSettings.RestrictCreationToDomains} { 73 domains := a.normalizeDomains(restriction) 74 if len(domains) <= 0 { 75 continue 76 } 77 matched := false 78 for _, d := range domains { 79 if strings.HasSuffix(email, "@"+d) { 80 matched = true 81 break 82 } 83 } 84 if !matched { 85 return false 86 } 87 } 88 89 return true 90 } 91 92 func (a *App) isTeamEmailAllowed(user *model.User, team *model.Team) bool { 93 email := strings.ToLower(user.Email) 94 95 if len(user.AuthService) > 0 && len(*user.AuthData) > 0 { 96 return true 97 } 98 99 return a.isTeamEmailAddressAllowed(email, team.AllowedDomains) 100 } 101 102 func (a *App) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) { 103 var oldTeam *model.Team 104 var err *model.AppError 105 if oldTeam, err = a.GetTeam(team.Id); err != nil { 106 return nil, err 107 } 108 109 validDomains := a.normalizeDomains(a.Config().TeamSettings.RestrictCreationToDomains) 110 if len(validDomains) > 0 { 111 for _, domain := range a.normalizeDomains(team.AllowedDomains) { 112 matched := false 113 for _, d := range validDomains { 114 if domain == d { 115 matched = true 116 break 117 } 118 } 119 if !matched { 120 err := model.NewAppError("UpdateTeam", "api.team.update_restricted_domains.mismatch.app_error", map[string]interface{}{"Domain": domain}, "", http.StatusBadRequest) 121 return nil, err 122 } 123 } 124 } 125 126 oldTeam.DisplayName = team.DisplayName 127 oldTeam.Description = team.Description 128 oldTeam.InviteId = team.InviteId 129 oldTeam.AllowOpenInvite = team.AllowOpenInvite 130 oldTeam.CompanyName = team.CompanyName 131 oldTeam.AllowedDomains = team.AllowedDomains 132 oldTeam.LastTeamIconUpdate = team.LastTeamIconUpdate 133 134 oldTeam, err = a.updateTeamUnsanitized(oldTeam) 135 if err != nil { 136 return team, err 137 } 138 139 a.sendTeamEvent(oldTeam, model.WEBSOCKET_EVENT_UPDATE_TEAM) 140 141 return oldTeam, nil 142 } 143 144 func (a *App) updateTeamUnsanitized(team *model.Team) (*model.Team, *model.AppError) { 145 if result := <-a.Srv.Store.Team().Update(team); result.Err != nil { 146 return nil, result.Err 147 } else { 148 return result.Data.(*model.Team), nil 149 } 150 } 151 152 func (a *App) UpdateTeamScheme(team *model.Team) (*model.Team, *model.AppError) { 153 var oldTeam *model.Team 154 var err *model.AppError 155 if oldTeam, err = a.GetTeam(team.Id); err != nil { 156 return nil, err 157 } 158 159 oldTeam.SchemeId = team.SchemeId 160 161 if result := <-a.Srv.Store.Team().Update(oldTeam); result.Err != nil { 162 return nil, result.Err 163 } 164 165 a.sendTeamEvent(oldTeam, model.WEBSOCKET_EVENT_UPDATE_TEAM) 166 167 return oldTeam, nil 168 } 169 170 func (a *App) PatchTeam(teamId string, patch *model.TeamPatch) (*model.Team, *model.AppError) { 171 team, err := a.GetTeam(teamId) 172 if err != nil { 173 return nil, err 174 } 175 176 team.Patch(patch) 177 178 updatedTeam, err := a.UpdateTeam(team) 179 if err != nil { 180 return nil, err 181 } 182 183 a.sendTeamEvent(updatedTeam, model.WEBSOCKET_EVENT_UPDATE_TEAM) 184 185 return updatedTeam, nil 186 } 187 188 func (a *App) sendTeamEvent(team *model.Team, event string) { 189 sanitizedTeam := &model.Team{} 190 *sanitizedTeam = *team 191 sanitizedTeam.Sanitize() 192 193 message := model.NewWebSocketEvent(event, "", "", "", nil) 194 message.Add("team", sanitizedTeam.ToJson()) 195 a.Publish(message) 196 } 197 198 func (a *App) GetSchemeRolesForTeam(teamId string) (string, string, *model.AppError) { 199 var team *model.Team 200 var err *model.AppError 201 202 if team, err = a.GetTeam(teamId); err != nil { 203 return "", "", err 204 } 205 206 if team.SchemeId != nil && len(*team.SchemeId) != 0 { 207 if scheme, err := a.GetScheme(*team.SchemeId); err != nil { 208 return "", "", err 209 } else { 210 return scheme.DefaultTeamUserRole, scheme.DefaultTeamAdminRole, nil 211 } 212 } 213 214 return model.TEAM_USER_ROLE_ID, model.TEAM_ADMIN_ROLE_ID, nil 215 } 216 217 func (a *App) UpdateTeamMemberRoles(teamId string, userId string, newRoles string) (*model.TeamMember, *model.AppError) { 218 var member *model.TeamMember 219 if result := <-a.Srv.Store.Team().GetMember(teamId, userId); result.Err != nil { 220 return nil, result.Err 221 } else { 222 member = result.Data.(*model.TeamMember) 223 } 224 225 if member == nil { 226 err := model.NewAppError("UpdateTeamMemberRoles", "api.team.update_member_roles.not_a_member", nil, "userId="+userId+" teamId="+teamId, http.StatusBadRequest) 227 return nil, err 228 } 229 230 schemeUserRole, schemeAdminRole, err := a.GetSchemeRolesForTeam(teamId) 231 if err != nil { 232 return nil, err 233 } 234 235 var newExplicitRoles []string 236 member.SchemeUser = false 237 member.SchemeAdmin = false 238 239 for _, roleName := range strings.Fields(newRoles) { 240 if role, err := a.GetRoleByName(roleName); err != nil { 241 err.StatusCode = http.StatusBadRequest 242 return nil, err 243 } else if !role.SchemeManaged { 244 // The role is not scheme-managed, so it's OK to apply it to the explicit roles field. 245 newExplicitRoles = append(newExplicitRoles, roleName) 246 } else { 247 // The role is scheme-managed, so need to check if it is part of the scheme for this channel or not. 248 switch roleName { 249 case schemeAdminRole: 250 member.SchemeAdmin = true 251 case schemeUserRole: 252 member.SchemeUser = true 253 default: 254 // If not part of the scheme for this channel, then it is not allowed to apply it as an explicit role. 255 return nil, model.NewAppError("UpdateTeamMemberRoles", "api.channel.update_team_member_roles.scheme_role.app_error", nil, "role_name="+roleName, http.StatusBadRequest) 256 } 257 } 258 } 259 260 member.ExplicitRoles = strings.Join(newExplicitRoles, " ") 261 262 if result := <-a.Srv.Store.Team().UpdateMember(member); result.Err != nil { 263 return nil, result.Err 264 } else { 265 member = result.Data.(*model.TeamMember) 266 } 267 268 a.ClearSessionCacheForUser(userId) 269 270 a.sendUpdatedMemberRoleEvent(userId, member) 271 272 return member, nil 273 } 274 275 func (a *App) UpdateTeamMemberSchemeRoles(teamId string, userId string, isSchemeUser bool, isSchemeAdmin bool) (*model.TeamMember, *model.AppError) { 276 member, err := a.GetTeamMember(teamId, userId) 277 if err != nil { 278 return nil, err 279 } 280 281 member.SchemeAdmin = isSchemeAdmin 282 member.SchemeUser = isSchemeUser 283 284 // 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. 285 if err = a.IsPhase2MigrationCompleted(); err != nil { 286 member.ExplicitRoles = RemoveRoles([]string{model.TEAM_USER_ROLE_ID, model.TEAM_ADMIN_ROLE_ID}, member.ExplicitRoles) 287 } 288 289 if result := <-a.Srv.Store.Team().UpdateMember(member); result.Err != nil { 290 return nil, result.Err 291 } else { 292 member = result.Data.(*model.TeamMember) 293 } 294 295 a.ClearSessionCacheForUser(userId) 296 297 a.sendUpdatedMemberRoleEvent(userId, member) 298 299 return member, nil 300 } 301 302 func (a *App) sendUpdatedMemberRoleEvent(userId string, member *model.TeamMember) { 303 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_MEMBERROLE_UPDATED, "", "", userId, nil) 304 message.Add("member", member.ToJson()) 305 a.Publish(message) 306 } 307 308 func (a *App) AddUserToTeam(teamId string, userId string, userRequestorId string) (*model.Team, *model.AppError) { 309 tchan := a.Srv.Store.Team().Get(teamId) 310 uchan := a.Srv.Store.User().Get(userId) 311 312 var team *model.Team 313 if result := <-tchan; result.Err != nil { 314 return nil, result.Err 315 } else { 316 team = result.Data.(*model.Team) 317 } 318 319 var user *model.User 320 if result := <-uchan; result.Err != nil { 321 return nil, result.Err 322 } else { 323 user = result.Data.(*model.User) 324 } 325 326 if err := a.JoinUserToTeam(team, user, userRequestorId); err != nil { 327 return nil, err 328 } 329 330 return team, nil 331 } 332 333 func (a *App) AddUserToTeamByTeamId(teamId string, user *model.User) *model.AppError { 334 if result := <-a.Srv.Store.Team().Get(teamId); result.Err != nil { 335 return result.Err 336 } else { 337 return a.JoinUserToTeam(result.Data.(*model.Team), user, "") 338 } 339 } 340 341 func (a *App) AddUserToTeamByToken(userId string, tokenId string) (*model.Team, *model.AppError) { 342 result := <-a.Srv.Store.Token().GetByToken(tokenId) 343 if result.Err != nil { 344 return nil, model.NewAppError("AddUserToTeamByToken", "api.user.create_user.signup_link_invalid.app_error", nil, result.Err.Error(), http.StatusBadRequest) 345 } 346 347 token := result.Data.(*model.Token) 348 if token.Type != TOKEN_TYPE_TEAM_INVITATION { 349 return nil, model.NewAppError("AddUserToTeamByToken", "api.user.create_user.signup_link_invalid.app_error", nil, "", http.StatusBadRequest) 350 } 351 352 if model.GetMillis()-token.CreateAt >= TEAM_INVITATION_EXPIRY_TIME { 353 a.DeleteToken(token) 354 return nil, model.NewAppError("AddUserToTeamByToken", "api.user.create_user.signup_link_expired.app_error", nil, "", http.StatusBadRequest) 355 } 356 357 tokenData := model.MapFromJson(strings.NewReader(token.Extra)) 358 359 tchan := a.Srv.Store.Team().Get(tokenData["teamId"]) 360 uchan := a.Srv.Store.User().Get(userId) 361 362 var team *model.Team 363 if result := <-tchan; result.Err != nil { 364 return nil, result.Err 365 } else { 366 team = result.Data.(*model.Team) 367 } 368 369 var user *model.User 370 if result := <-uchan; result.Err != nil { 371 return nil, result.Err 372 } else { 373 user = result.Data.(*model.User) 374 } 375 376 if err := a.JoinUserToTeam(team, user, ""); err != nil { 377 return nil, err 378 } 379 380 if err := a.DeleteToken(token); err != nil { 381 return nil, err 382 } 383 384 return team, nil 385 } 386 387 func (a *App) AddUserToTeamByInviteId(inviteId string, userId string) (*model.Team, *model.AppError) { 388 tchan := a.Srv.Store.Team().GetByInviteId(inviteId) 389 uchan := a.Srv.Store.User().Get(userId) 390 391 var team *model.Team 392 if result := <-tchan; result.Err != nil { 393 return nil, result.Err 394 } else { 395 team = result.Data.(*model.Team) 396 } 397 398 var user *model.User 399 if result := <-uchan; result.Err != nil { 400 return nil, result.Err 401 } else { 402 user = result.Data.(*model.User) 403 } 404 405 if err := a.JoinUserToTeam(team, user, ""); err != nil { 406 return nil, err 407 } 408 409 return team, nil 410 } 411 412 // Returns three values: 413 // 1. a pointer to the team member, if successful 414 // 2. a boolean: true if the user has a non-deleted team member for that team already, otherwise false. 415 // 3. a pointer to an AppError if something went wrong. 416 func (a *App) joinUserToTeam(team *model.Team, user *model.User) (*model.TeamMember, bool, *model.AppError) { 417 tm := &model.TeamMember{ 418 TeamId: team.Id, 419 UserId: user.Id, 420 SchemeUser: true, 421 } 422 423 if team.Email == user.Email { 424 tm.SchemeAdmin = true 425 } 426 427 if etmr := <-a.Srv.Store.Team().GetMember(team.Id, user.Id); etmr.Err == nil { 428 // Membership already exists. Check if deleted and and update, otherwise do nothing 429 rtm := etmr.Data.(*model.TeamMember) 430 431 // Do nothing if already added 432 if rtm.DeleteAt == 0 { 433 return rtm, true, nil 434 } 435 436 if membersCount := <-a.Srv.Store.Team().GetActiveMemberCount(tm.TeamId); membersCount.Err != nil { 437 return nil, false, membersCount.Err 438 } else if membersCount.Data.(int64) >= int64(*a.Config().TeamSettings.MaxUsersPerTeam) { 439 return nil, false, model.NewAppError("joinUserToTeam", "app.team.join_user_to_team.max_accounts.app_error", nil, "teamId="+tm.TeamId, http.StatusBadRequest) 440 } else { 441 if tmr := <-a.Srv.Store.Team().UpdateMember(tm); tmr.Err != nil { 442 return nil, false, tmr.Err 443 } else { 444 return tmr.Data.(*model.TeamMember), false, nil 445 } 446 } 447 } else { 448 // Membership appears to be missing. Lets try to add. 449 if tmr := <-a.Srv.Store.Team().SaveMember(tm, *a.Config().TeamSettings.MaxUsersPerTeam); tmr.Err != nil { 450 return nil, false, tmr.Err 451 } else { 452 return tmr.Data.(*model.TeamMember), false, nil 453 } 454 } 455 } 456 457 func (a *App) JoinUserToTeam(team *model.Team, user *model.User, userRequestorId string) *model.AppError { 458 if !a.isTeamEmailAllowed(user, team) { 459 return model.NewAppError("JoinUserToTeam", "api.team.join_user_to_team.allowed_domains.app_error", nil, "", http.StatusBadRequest) 460 } 461 tm, alreadyAdded, err := a.joinUserToTeam(team, user) 462 if err != nil { 463 return err 464 } else if alreadyAdded { 465 return nil 466 } 467 468 if a.PluginsReady() { 469 var actor *model.User 470 if userRequestorId != "" { 471 actor, _ = a.GetUser(userRequestorId) 472 } 473 474 a.Go(func() { 475 pluginContext := &plugin.Context{} 476 a.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { 477 hooks.UserHasJoinedTeam(pluginContext, tm, actor) 478 return true 479 }, plugin.UserHasJoinedTeamId) 480 }) 481 } 482 483 if uua := <-a.Srv.Store.User().UpdateUpdateAt(user.Id); uua.Err != nil { 484 return uua.Err 485 } 486 487 shouldBeAdmin := team.Email == user.Email 488 489 // Soft error if there is an issue joining the default channels 490 if err := a.JoinDefaultChannels(team.Id, user, shouldBeAdmin, userRequestorId); err != nil { 491 mlog.Error(fmt.Sprintf("Encountered an issue joining default channels err=%v", err), mlog.String("user_id", user.Id), mlog.String("team_id", team.Id)) 492 } 493 494 a.ClearSessionCacheForUser(user.Id) 495 a.InvalidateCacheForUser(user.Id) 496 497 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", user.Id, nil) 498 message.Add("team_id", team.Id) 499 message.Add("user_id", user.Id) 500 a.Publish(message) 501 502 return nil 503 } 504 505 func (a *App) GetTeam(teamId string) (*model.Team, *model.AppError) { 506 if result := <-a.Srv.Store.Team().Get(teamId); result.Err != nil { 507 return nil, result.Err 508 } else { 509 return result.Data.(*model.Team), nil 510 } 511 } 512 513 func (a *App) GetTeamByName(name string) (*model.Team, *model.AppError) { 514 if result := <-a.Srv.Store.Team().GetByName(name); result.Err != nil { 515 result.Err.StatusCode = http.StatusNotFound 516 return nil, result.Err 517 } else { 518 return result.Data.(*model.Team), nil 519 } 520 } 521 522 func (a *App) GetTeamByInviteId(inviteId string) (*model.Team, *model.AppError) { 523 if result := <-a.Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil { 524 return nil, result.Err 525 } else { 526 return result.Data.(*model.Team), nil 527 } 528 } 529 530 func (a *App) GetAllTeams() ([]*model.Team, *model.AppError) { 531 if result := <-a.Srv.Store.Team().GetAll(); result.Err != nil { 532 return nil, result.Err 533 } else { 534 return result.Data.([]*model.Team), nil 535 } 536 } 537 538 func (a *App) GetAllTeamsPage(offset int, limit int) ([]*model.Team, *model.AppError) { 539 if result := <-a.Srv.Store.Team().GetAllPage(offset, limit); result.Err != nil { 540 return nil, result.Err 541 } else { 542 return result.Data.([]*model.Team), nil 543 } 544 } 545 546 func (a *App) GetAllOpenTeams() ([]*model.Team, *model.AppError) { 547 if result := <-a.Srv.Store.Team().GetAllTeamListing(); result.Err != nil { 548 return nil, result.Err 549 } else { 550 return result.Data.([]*model.Team), nil 551 } 552 } 553 554 func (a *App) SearchAllTeams(term string) ([]*model.Team, *model.AppError) { 555 if result := <-a.Srv.Store.Team().SearchAll(term); result.Err != nil { 556 return nil, result.Err 557 } else { 558 return result.Data.([]*model.Team), nil 559 } 560 } 561 562 func (a *App) SearchOpenTeams(term string) ([]*model.Team, *model.AppError) { 563 if result := <-a.Srv.Store.Team().SearchOpen(term); result.Err != nil { 564 return nil, result.Err 565 } else { 566 return result.Data.([]*model.Team), nil 567 } 568 } 569 570 func (a *App) GetAllOpenTeamsPage(offset int, limit int) ([]*model.Team, *model.AppError) { 571 if result := <-a.Srv.Store.Team().GetAllTeamPageListing(offset, limit); result.Err != nil { 572 return nil, result.Err 573 } else { 574 return result.Data.([]*model.Team), nil 575 } 576 } 577 578 func (a *App) GetTeamsForUser(userId string) ([]*model.Team, *model.AppError) { 579 if result := <-a.Srv.Store.Team().GetTeamsByUserId(userId); result.Err != nil { 580 return nil, result.Err 581 } else { 582 return result.Data.([]*model.Team), nil 583 } 584 } 585 586 func (a *App) GetTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError) { 587 if result := <-a.Srv.Store.Team().GetMember(teamId, userId); result.Err != nil { 588 return nil, result.Err 589 } else { 590 return result.Data.(*model.TeamMember), nil 591 } 592 } 593 594 func (a *App) GetTeamMembersForUser(userId string) ([]*model.TeamMember, *model.AppError) { 595 if result := <-a.Srv.Store.Team().GetTeamsForUser(userId); result.Err != nil { 596 return nil, result.Err 597 } else { 598 return result.Data.([]*model.TeamMember), nil 599 } 600 } 601 602 func (a *App) GetTeamMembers(teamId string, offset int, limit int) ([]*model.TeamMember, *model.AppError) { 603 if result := <-a.Srv.Store.Team().GetMembers(teamId, offset, limit); result.Err != nil { 604 return nil, result.Err 605 } else { 606 return result.Data.([]*model.TeamMember), nil 607 } 608 } 609 610 func (a *App) GetTeamMembersByIds(teamId string, userIds []string) ([]*model.TeamMember, *model.AppError) { 611 if result := <-a.Srv.Store.Team().GetMembersByIds(teamId, userIds); result.Err != nil { 612 return nil, result.Err 613 } else { 614 return result.Data.([]*model.TeamMember), nil 615 } 616 } 617 618 func (a *App) AddTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError) { 619 if _, err := a.AddUserToTeam(teamId, userId, ""); err != nil { 620 return nil, err 621 } 622 623 teamMember, err := a.GetTeamMember(teamId, userId) 624 if err != nil { 625 return nil, err 626 } 627 628 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", userId, nil) 629 message.Add("team_id", teamId) 630 message.Add("user_id", userId) 631 a.Publish(message) 632 633 return teamMember, nil 634 } 635 636 func (a *App) AddTeamMembers(teamId string, userIds []string, userRequestorId string) ([]*model.TeamMember, *model.AppError) { 637 var members []*model.TeamMember 638 639 for _, userId := range userIds { 640 if _, err := a.AddUserToTeam(teamId, userId, userRequestorId); err != nil { 641 return nil, err 642 } 643 644 if teamMember, err := a.GetTeamMember(teamId, userId); err != nil { 645 return nil, err 646 } else { 647 members = append(members, teamMember) 648 } 649 650 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_ADDED_TO_TEAM, "", "", userId, nil) 651 message.Add("team_id", teamId) 652 message.Add("user_id", userId) 653 a.Publish(message) 654 } 655 656 return members, nil 657 } 658 659 func (a *App) AddTeamMemberByToken(userId, tokenId string) (*model.TeamMember, *model.AppError) { 660 var team *model.Team 661 var err *model.AppError 662 663 if team, err = a.AddUserToTeamByToken(userId, tokenId); err != nil { 664 return nil, err 665 } 666 667 if teamMember, err := a.GetTeamMember(team.Id, userId); err != nil { 668 return nil, err 669 } else { 670 return teamMember, nil 671 } 672 } 673 674 func (a *App) AddTeamMemberByInviteId(inviteId, userId string) (*model.TeamMember, *model.AppError) { 675 var team *model.Team 676 var err *model.AppError 677 678 if team, err = a.AddUserToTeamByInviteId(inviteId, userId); err != nil { 679 return nil, err 680 } 681 682 if teamMember, err := a.GetTeamMember(team.Id, userId); err != nil { 683 return nil, err 684 } else { 685 return teamMember, nil 686 } 687 } 688 689 func (a *App) GetTeamUnread(teamId, userId string) (*model.TeamUnread, *model.AppError) { 690 result := <-a.Srv.Store.Team().GetChannelUnreadsForTeam(teamId, userId) 691 if result.Err != nil { 692 return nil, result.Err 693 } 694 695 channelUnreads := result.Data.([]*model.ChannelUnread) 696 var teamUnread = &model.TeamUnread{ 697 MsgCount: 0, 698 MentionCount: 0, 699 TeamId: teamId, 700 } 701 702 for _, cu := range channelUnreads { 703 teamUnread.MentionCount += cu.MentionCount 704 705 if cu.NotifyProps["mark_unread"] != model.CHANNEL_MARK_UNREAD_MENTION { 706 teamUnread.MsgCount += cu.MsgCount 707 } 708 } 709 710 return teamUnread, nil 711 } 712 713 func (a *App) RemoveUserFromTeam(teamId string, userId string, requestorId string) *model.AppError { 714 tchan := a.Srv.Store.Team().Get(teamId) 715 uchan := a.Srv.Store.User().Get(userId) 716 717 var team *model.Team 718 if result := <-tchan; result.Err != nil { 719 return result.Err 720 } else { 721 team = result.Data.(*model.Team) 722 } 723 724 var user *model.User 725 if result := <-uchan; result.Err != nil { 726 return result.Err 727 } else { 728 user = result.Data.(*model.User) 729 } 730 731 if err := a.LeaveTeam(team, user, requestorId); err != nil { 732 return err 733 } 734 735 return nil 736 } 737 738 func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string) *model.AppError { 739 teamMember, err := a.GetTeamMember(team.Id, user.Id) 740 if err != nil { 741 return model.NewAppError("LeaveTeam", "api.team.remove_user_from_team.missing.app_error", nil, err.Error(), http.StatusBadRequest) 742 } 743 744 var channelList *model.ChannelList 745 746 if result := <-a.Srv.Store.Channel().GetChannels(team.Id, user.Id, true); result.Err != nil { 747 if result.Err.Id == "store.sql_channel.get_channels.not_found.app_error" { 748 channelList = &model.ChannelList{} 749 } else { 750 return result.Err 751 } 752 753 } else { 754 channelList = result.Data.(*model.ChannelList) 755 } 756 757 for _, channel := range *channelList { 758 if !channel.IsGroupOrDirect() { 759 a.InvalidateCacheForChannelMembers(channel.Id) 760 if result := <-a.Srv.Store.Channel().RemoveMember(channel.Id, user.Id); result.Err != nil { 761 return result.Err 762 } 763 } 764 } 765 766 var channel *model.Channel 767 if result := <-a.Srv.Store.Channel().GetByName(team.Id, model.DEFAULT_CHANNEL, false); result.Err != nil { 768 return result.Err 769 } else { 770 channel = result.Data.(*model.Channel) 771 } 772 773 if *a.Config().ServiceSettings.ExperimentalEnableDefaultChannelLeaveJoinMessages { 774 if requestorId == user.Id { 775 if err := a.postLeaveTeamMessage(user, channel); err != nil { 776 mlog.Error(fmt.Sprint("Failed to post join/leave message", err)) 777 } 778 } else { 779 if err := a.postRemoveFromTeamMessage(user, channel); err != nil { 780 mlog.Error(fmt.Sprint("Failed to post join/leave message", err)) 781 } 782 } 783 } 784 785 // Send the websocket message before we actually do the remove so the user being removed gets it. 786 message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_LEAVE_TEAM, team.Id, "", "", nil) 787 message.Add("user_id", user.Id) 788 message.Add("team_id", team.Id) 789 a.Publish(message) 790 791 teamMember.Roles = "" 792 teamMember.DeleteAt = model.GetMillis() 793 794 if result := <-a.Srv.Store.Team().UpdateMember(teamMember); result.Err != nil { 795 return result.Err 796 } 797 798 if a.PluginsReady() { 799 var actor *model.User 800 if requestorId != "" { 801 actor, _ = a.GetUser(requestorId) 802 } 803 804 a.Go(func() { 805 pluginContext := &plugin.Context{} 806 a.Plugins.RunMultiPluginHook(func(hooks plugin.Hooks) bool { 807 hooks.UserHasLeftTeam(pluginContext, teamMember, actor) 808 return true 809 }, plugin.UserHasLeftTeamId) 810 }) 811 } 812 813 if uua := <-a.Srv.Store.User().UpdateUpdateAt(user.Id); uua.Err != nil { 814 return uua.Err 815 } 816 817 // delete the preferences that set the last channel used in the team and other team specific preferences 818 if result := <-a.Srv.Store.Preference().DeleteCategory(user.Id, team.Id); result.Err != nil { 819 return result.Err 820 } 821 822 a.ClearSessionCacheForUser(user.Id) 823 a.InvalidateCacheForUser(user.Id) 824 825 return nil 826 } 827 828 func (a *App) postLeaveTeamMessage(user *model.User, channel *model.Channel) *model.AppError { 829 post := &model.Post{ 830 ChannelId: channel.Id, 831 Message: fmt.Sprintf(utils.T("api.team.leave.left"), user.Username), 832 Type: model.POST_LEAVE_TEAM, 833 UserId: user.Id, 834 Props: model.StringInterface{ 835 "username": user.Username, 836 }, 837 } 838 839 if _, err := a.CreatePost(post, channel, false); err != nil { 840 return model.NewAppError("postRemoveFromChannelMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, err.Error(), http.StatusInternalServerError) 841 } 842 843 return nil 844 } 845 846 func (a *App) postRemoveFromTeamMessage(user *model.User, channel *model.Channel) *model.AppError { 847 post := &model.Post{ 848 ChannelId: channel.Id, 849 Message: fmt.Sprintf(utils.T("api.team.remove_user_from_team.removed"), user.Username), 850 Type: model.POST_REMOVE_FROM_TEAM, 851 UserId: user.Id, 852 Props: model.StringInterface{ 853 "username": user.Username, 854 }, 855 } 856 857 if _, err := a.CreatePost(post, channel, false); err != nil { 858 return model.NewAppError("postRemoveFromTeamMessage", "api.channel.post_user_add_remove_message_and_forget.error", nil, err.Error(), http.StatusInternalServerError) 859 } 860 861 return nil 862 } 863 864 func (a *App) InviteNewUsersToTeam(emailList []string, teamId, senderId string) *model.AppError { 865 if !*a.Config().ServiceSettings.EnableEmailInvitations { 866 return model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented) 867 } 868 869 if len(emailList) == 0 { 870 err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.no_one.app_error", nil, "", http.StatusBadRequest) 871 return err 872 } 873 874 tchan := a.Srv.Store.Team().Get(teamId) 875 uchan := a.Srv.Store.User().Get(senderId) 876 877 var team *model.Team 878 if result := <-tchan; result.Err != nil { 879 return result.Err 880 } else { 881 team = result.Data.(*model.Team) 882 } 883 884 var user *model.User 885 if result := <-uchan; result.Err != nil { 886 return result.Err 887 } else { 888 user = result.Data.(*model.User) 889 } 890 891 var invalidEmailList []string 892 893 for _, email := range emailList { 894 if !a.isTeamEmailAddressAllowed(email, team.AllowedDomains) { 895 invalidEmailList = append(invalidEmailList, email) 896 } 897 } 898 899 if len(invalidEmailList) > 0 { 900 s := strings.Join(invalidEmailList, ", ") 901 err := model.NewAppError("InviteNewUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": s}, "", http.StatusBadRequest) 902 return err 903 } 904 905 nameFormat := *a.Config().TeamSettings.TeammateNameDisplay 906 a.SendInviteEmails(team, user.GetDisplayName(nameFormat), user.Id, emailList, a.GetSiteURL()) 907 908 return nil 909 } 910 911 func (a *App) FindTeamByName(name string) bool { 912 if result := <-a.Srv.Store.Team().GetByName(name); result.Err != nil { 913 return false 914 } else { 915 return true 916 } 917 } 918 919 func (a *App) GetTeamsUnreadForUser(excludeTeamId string, userId string) ([]*model.TeamUnread, *model.AppError) { 920 if result := <-a.Srv.Store.Team().GetChannelUnreadsForAllTeams(excludeTeamId, userId); result.Err != nil { 921 return nil, result.Err 922 } else { 923 data := result.Data.([]*model.ChannelUnread) 924 members := []*model.TeamUnread{} 925 membersMap := make(map[string]*model.TeamUnread) 926 927 unreads := func(cu *model.ChannelUnread, tu *model.TeamUnread) *model.TeamUnread { 928 tu.MentionCount += cu.MentionCount 929 930 if cu.NotifyProps["mark_unread"] != model.CHANNEL_MARK_UNREAD_MENTION { 931 tu.MsgCount += cu.MsgCount 932 } 933 934 return tu 935 } 936 937 for i := range data { 938 id := data[i].TeamId 939 if mu, ok := membersMap[id]; ok { 940 membersMap[id] = unreads(data[i], mu) 941 } else { 942 membersMap[id] = unreads(data[i], &model.TeamUnread{ 943 MsgCount: 0, 944 MentionCount: 0, 945 TeamId: id, 946 }) 947 } 948 } 949 950 for _, val := range membersMap { 951 members = append(members, val) 952 } 953 954 return members, nil 955 } 956 } 957 958 func (a *App) PermanentDeleteTeamId(teamId string) *model.AppError { 959 team, err := a.GetTeam(teamId) 960 if err != nil { 961 return err 962 } 963 964 return a.PermanentDeleteTeam(team) 965 } 966 967 func (a *App) PermanentDeleteTeam(team *model.Team) *model.AppError { 968 team.DeleteAt = model.GetMillis() 969 if result := <-a.Srv.Store.Team().Update(team); result.Err != nil { 970 return result.Err 971 } 972 973 if result := <-a.Srv.Store.Channel().GetTeamChannels(team.Id); result.Err != nil { 974 if result.Err.Id != "store.sql_channel.get_channels.not_found.app_error" { 975 return result.Err 976 } 977 } else { 978 channels := result.Data.(*model.ChannelList) 979 for _, c := range *channels { 980 a.PermanentDeleteChannel(c) 981 } 982 } 983 984 if result := <-a.Srv.Store.Team().RemoveAllMembersByTeam(team.Id); result.Err != nil { 985 return result.Err 986 } 987 988 if result := <-a.Srv.Store.Command().PermanentDeleteByTeam(team.Id); result.Err != nil { 989 return result.Err 990 } 991 992 if result := <-a.Srv.Store.Team().PermanentDelete(team.Id); result.Err != nil { 993 return result.Err 994 } 995 996 a.sendTeamEvent(team, model.WEBSOCKET_EVENT_DELETE_TEAM) 997 998 return nil 999 } 1000 1001 func (a *App) SoftDeleteTeam(teamId string) *model.AppError { 1002 team, err := a.GetTeam(teamId) 1003 if err != nil { 1004 return err 1005 } 1006 1007 team.DeleteAt = model.GetMillis() 1008 if result := <-a.Srv.Store.Team().Update(team); result.Err != nil { 1009 return result.Err 1010 } 1011 1012 a.sendTeamEvent(team, model.WEBSOCKET_EVENT_DELETE_TEAM) 1013 1014 return nil 1015 } 1016 1017 func (a *App) GetTeamStats(teamId string) (*model.TeamStats, *model.AppError) { 1018 tchan := a.Srv.Store.Team().GetTotalMemberCount(teamId) 1019 achan := a.Srv.Store.Team().GetActiveMemberCount(teamId) 1020 1021 stats := &model.TeamStats{} 1022 stats.TeamId = teamId 1023 1024 if result := <-tchan; result.Err != nil { 1025 return nil, result.Err 1026 } else { 1027 stats.TotalMemberCount = result.Data.(int64) 1028 } 1029 1030 if result := <-achan; result.Err != nil { 1031 return nil, result.Err 1032 } else { 1033 stats.ActiveMemberCount = result.Data.(int64) 1034 } 1035 1036 return stats, nil 1037 } 1038 1039 func (a *App) GetTeamIdFromQuery(query url.Values) (string, *model.AppError) { 1040 tokenId := query.Get("t") 1041 inviteId := query.Get("id") 1042 1043 if len(tokenId) > 0 { 1044 result := <-a.Srv.Store.Token().GetByToken(tokenId) 1045 if result.Err != nil { 1046 return "", model.NewAppError("GetTeamIdFromQuery", "api.oauth.singup_with_oauth.invalid_link.app_error", nil, "", http.StatusBadRequest) 1047 } 1048 1049 token := result.Data.(*model.Token) 1050 if token.Type != TOKEN_TYPE_TEAM_INVITATION { 1051 return "", model.NewAppError("GetTeamIdFromQuery", "api.oauth.singup_with_oauth.invalid_link.app_error", nil, "", http.StatusBadRequest) 1052 } 1053 1054 if model.GetMillis()-token.CreateAt >= TEAM_INVITATION_EXPIRY_TIME { 1055 a.DeleteToken(token) 1056 return "", model.NewAppError("GetTeamIdFromQuery", "api.oauth.singup_with_oauth.expired_link.app_error", nil, "", http.StatusBadRequest) 1057 } 1058 1059 tokenData := model.MapFromJson(strings.NewReader(token.Extra)) 1060 1061 return tokenData["teamId"], nil 1062 } else if len(inviteId) > 0 { 1063 if result := <-a.Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil { 1064 // soft fail, so we still create user but don't auto-join team 1065 mlog.Error(fmt.Sprintf("%v", result.Err)) 1066 } else { 1067 return result.Data.(*model.Team).Id, nil 1068 } 1069 } 1070 1071 return "", nil 1072 } 1073 1074 func (a *App) SanitizeTeam(session model.Session, team *model.Team) *model.Team { 1075 if !a.SessionHasPermissionToTeam(session, team.Id, model.PERMISSION_MANAGE_TEAM) { 1076 team.Sanitize() 1077 } 1078 1079 return team 1080 } 1081 1082 func (a *App) SanitizeTeams(session model.Session, teams []*model.Team) []*model.Team { 1083 for _, team := range teams { 1084 a.SanitizeTeam(session, team) 1085 } 1086 1087 return teams 1088 } 1089 1090 func (a *App) GetTeamIcon(team *model.Team) ([]byte, *model.AppError) { 1091 if len(*a.Config().FileSettings.DriverName) == 0 { 1092 return nil, model.NewAppError("GetTeamIcon", "api.team.get_team_icon.filesettings_no_driver.app_error", nil, "", http.StatusNotImplemented) 1093 } else { 1094 path := "teams/" + team.Id + "/teamIcon.png" 1095 if data, err := a.ReadFile(path); err != nil { 1096 return nil, model.NewAppError("GetTeamIcon", "api.team.get_team_icon.read_file.app_error", nil, err.Error(), http.StatusNotFound) 1097 } else { 1098 return data, nil 1099 } 1100 } 1101 } 1102 1103 func (a *App) SetTeamIcon(teamId string, imageData *multipart.FileHeader) *model.AppError { 1104 file, err := imageData.Open() 1105 if err != nil { 1106 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.open.app_error", nil, err.Error(), http.StatusBadRequest) 1107 } 1108 defer file.Close() 1109 return a.SetTeamIconFromFile(teamId, file) 1110 } 1111 1112 func (a *App) SetTeamIconFromFile(teamId string, file multipart.File) *model.AppError { 1113 1114 team, getTeamErr := a.GetTeam(teamId) 1115 1116 if getTeamErr != nil { 1117 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.get_team.app_error", nil, getTeamErr.Error(), http.StatusBadRequest) 1118 } 1119 1120 if len(*a.Config().FileSettings.DriverName) == 0 { 1121 return model.NewAppError("setTeamIcon", "api.team.set_team_icon.storage.app_error", nil, "", http.StatusNotImplemented) 1122 } 1123 1124 // Decode image config first to check dimensions before loading the whole thing into memory later on 1125 config, _, err := image.DecodeConfig(file) 1126 if err != nil { 1127 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.decode_config.app_error", nil, err.Error(), http.StatusBadRequest) 1128 } else if config.Width*config.Height > model.MaxImageSize { 1129 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.too_large.app_error", nil, err.Error(), http.StatusBadRequest) 1130 } 1131 1132 file.Seek(0, 0) 1133 1134 // Decode image into Image object 1135 img, _, err := image.Decode(file) 1136 if err != nil { 1137 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.decode.app_error", nil, err.Error(), http.StatusBadRequest) 1138 } 1139 1140 file.Seek(0, 0) 1141 1142 orientation, _ := getImageOrientation(file) 1143 img = makeImageUpright(img, orientation) 1144 1145 // Scale team icon 1146 teamIconWidthAndHeight := 128 1147 img = imaging.Fill(img, teamIconWidthAndHeight, teamIconWidthAndHeight, imaging.Center, imaging.Lanczos) 1148 1149 buf := new(bytes.Buffer) 1150 err = png.Encode(buf, img) 1151 if err != nil { 1152 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.encode.app_error", nil, err.Error(), http.StatusInternalServerError) 1153 } 1154 1155 path := "teams/" + teamId + "/teamIcon.png" 1156 1157 if _, err := a.WriteFile(buf, path); err != nil { 1158 return model.NewAppError("SetTeamIcon", "api.team.set_team_icon.write_file.app_error", nil, "", http.StatusInternalServerError) 1159 } 1160 1161 curTime := model.GetMillis() 1162 1163 if result := <-a.Srv.Store.Team().UpdateLastTeamIconUpdate(teamId, curTime); result.Err != nil { 1164 return model.NewAppError("SetTeamIcon", "api.team.team_icon.update.app_error", nil, result.Err.Error(), http.StatusBadRequest) 1165 } 1166 1167 // manually set time to avoid possible cluster inconsistencies 1168 team.LastTeamIconUpdate = curTime 1169 1170 a.sendTeamEvent(team, model.WEBSOCKET_EVENT_UPDATE_TEAM) 1171 1172 return nil 1173 } 1174 1175 func (a *App) RemoveTeamIcon(teamId string) *model.AppError { 1176 team, err := a.GetTeam(teamId) 1177 if err != nil { 1178 return model.NewAppError("RemoveTeamIcon", "api.team.remove_team_icon.get_team.app_error", nil, err.Error(), http.StatusBadRequest) 1179 } 1180 1181 if result := <-a.Srv.Store.Team().UpdateLastTeamIconUpdate(teamId, 0); result.Err != nil { 1182 return model.NewAppError("RemoveTeamIcon", "api.team.team_icon.update.app_error", nil, result.Err.Error(), http.StatusBadRequest) 1183 } 1184 1185 team.LastTeamIconUpdate = 0 1186 1187 a.sendTeamEvent(team, model.WEBSOCKET_EVENT_UPDATE_TEAM) 1188 1189 return nil 1190 }