From 2e5617c29be69637acd384e85f795a0b343bec8d Mon Sep 17 00:00:00 2001 From: Corey Hulen Date: Thu, 21 Apr 2016 22:37:01 -0700 Subject: PLT-2057 User as a first class object (#2648) * Adding TeamMember to system * Fixing all unit tests on the backend * Fixing merge conflicts * Fixing merge conflict * Adding javascript unit tests * Adding TeamMember to system * Fixing all unit tests on the backend * Fixing merge conflicts * Fixing merge conflict * Adding javascript unit tests * Adding client side unit test * Cleaning up the clint side tests * Fixing msg * Adding more client side unit tests * Adding more using tests * Adding last bit of client side unit tests and adding make cmd * Fixing bad merge * Fixing libraries * Updating to new client side API * Fixing borken unit test * Fixing unit tests * ugg...trying to beat gofmt * ugg...trying to beat gofmt * Cleaning up remainder of the server side routes * Adding inital load api * Increased coverage of webhook unit tests (#2660) * Adding loading ... to root html * Fixing bad merge * Removing explicit content type so superagent will guess corectly (#2685) * Fixing merge and unit tests * Adding create team UI * Fixing signup flows * Adding LDAP unit tests and enterprise unit test helper (#2702) * Add the ability to reset MFA from the commandline (#2706) * Fixing compliance unit tests * Fixing client side tests * Adding open server to system console * Moving websocket connection * Fixing unit test * Fixing unit tests * Fixing unit tests * Adding nickname and more LDAP unit tests (#2717) * Adding join open teams * Cleaning up all TODOs in the code * Fixing web sockets * Removing unused webockets file * PLT-2533 Add the ability to reset a user's MFA from the system console (#2715) * Add the ability to reset a user's MFA from the system console * Add client side unit test for adminResetMfa * Reorganizing authentication to fix LDAP error message (#2723) * Fixing failing unit test * Initial upgrade db code * Adding upgrade script * Fixing upgrade script after running on core * Update OAuth and Claim routes to work with user model changes (#2739) * Fixing perminant deletion. Adding ability to delete all user and the entire database (#2740) * Fixing team invite ldap login call (#2741) * Fixing bluebar and some img stuff * Fix all the different file upload web utils (#2743) * Fixing invalid session redirect (#2744) * Redirect on bad channel name (#2746) * Fixing a bunch of issue and removing dead code * Patch to fix error message on leave channel (#2747) * Setting EnableOpenServer to false by default * Fixing config * Fixing upgrade * Fixing reported bugs * Bug fixes for PLT-2057 * PLT-2563 Redo password recovery to use a database table (#2745) * Redo password recovery to use a database table * Update reset password audits * Split out admin and user reset password APIs to be separate * Delete password recovery when user is permanently deleted * Consolidate password resetting into a single function * Removed private channels as an option for outgoing webhooks (#2752) * PLT-2577/PLT-2552 Fixes for backstage (#2753) * Added URL to incoming webhook list * Fixed client functions for adding/removing integrations * Disallowed slash commands without trigger words * Fixed clientside handling of errors on AddCommand page * Minor auth cleanup (#2758) * Changed EditPostModal to just close if you save without making any changes (#2759) * Renamed client -> Client in async_client.jsx and fixed eslint warnings (#2756) * Fixed url in channel info modal (#2755) * Fixing reported issues * Moving to version 3 of the apis * Fixing command unit tests (#2760) * Adding team admins * Fixing DM issue * Fixing eslint error * Properly set EditPostModal's originalText state in all cases (#2762) * Update client config check to assume features is defined if server is licensed (#2772) * Fixing url link * Fixing issue with websocket crashing when sending messages to different teams --- api/team.go | 461 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 253 insertions(+), 208 deletions(-) (limited to 'api/team.go') diff --git a/api/team.go b/api/team.go index 255982522..eefdc3d85 100644 --- a/api/team.go +++ b/api/team.go @@ -6,38 +6,43 @@ package api import ( "bytes" "fmt" - l4g "github.com/alecthomas/log4go" - "github.com/gorilla/mux" - "github.com/mattermost/platform/einterfaces" - "github.com/mattermost/platform/model" - "github.com/mattermost/platform/store" - "github.com/mattermost/platform/utils" "html/template" "net/http" "net/url" "strconv" "strings" "time" + + l4g "github.com/alecthomas/log4go" + "github.com/gorilla/mux" + + "github.com/mattermost/platform/model" + "github.com/mattermost/platform/utils" ) -func InitTeam(r *mux.Router) { +func InitTeam() { l4g.Debug(utils.T("api.team.init.debug")) - sr := r.PathPrefix("/teams").Subrouter() - sr.Handle("/create", ApiAppHandler(createTeam)).Methods("POST") - sr.Handle("/create_from_signup", ApiAppHandler(createTeamFromSignup)).Methods("POST") - sr.Handle("/create_with_ldap", ApiAppHandler(createTeamWithLdap)).Methods("POST") - sr.Handle("/create_with_sso/{service:[A-Za-z]+}", ApiAppHandler(createTeamFromSSO)).Methods("POST") - sr.Handle("/signup", ApiAppHandler(signupTeam)).Methods("POST") - sr.Handle("/all", ApiAppHandler(getAll)).Methods("GET") - sr.Handle("/find_team_by_name", ApiAppHandler(findTeamByName)).Methods("POST") - sr.Handle("/invite_members", ApiUserRequired(inviteMembers)).Methods("POST") - sr.Handle("/update", ApiUserRequired(updateTeam)).Methods("POST") - sr.Handle("/me", ApiUserRequired(getMyTeam)).Methods("GET") - sr.Handle("/get_invite_info", ApiAppHandler(getInviteInfo)).Methods("POST") + BaseRoutes.Teams.Handle("/create", ApiAppHandler(createTeam)).Methods("POST") + BaseRoutes.Teams.Handle("/create_from_signup", ApiAppHandler(createTeamFromSignup)).Methods("POST") + BaseRoutes.Teams.Handle("/signup", ApiAppHandler(signupTeam)).Methods("POST") + BaseRoutes.Teams.Handle("/all", ApiAppHandler(getAll)).Methods("GET") + BaseRoutes.Teams.Handle("/all_team_listings", ApiUserRequired(GetAllTeamListings)).Methods("GET") + BaseRoutes.Teams.Handle("/get_invite_info", ApiAppHandler(getInviteInfo)).Methods("POST") + BaseRoutes.Teams.Handle("/find_team_by_name", ApiAppHandler(findTeamByName)).Methods("POST") + BaseRoutes.Teams.Handle("/members/{id:[A-Za-z0-9]+}", ApiUserRequired(getMembers)).Methods("GET") + + BaseRoutes.NeedTeam.Handle("/me", ApiUserRequired(getMyTeam)).Methods("GET") + BaseRoutes.NeedTeam.Handle("/update", ApiUserRequired(updateTeam)).Methods("POST") + + BaseRoutes.NeedTeam.Handle("/invite_members", ApiUserRequired(inviteMembers)).Methods("POST") + + BaseRoutes.NeedTeam.Handle("/add_user_to_team", ApiUserRequired(addUserToTeam)).Methods("POST") + // These should be moved to the global admain console - sr.Handle("/import_team", ApiUserRequired(importTeam)).Methods("POST") - sr.Handle("/export_team", ApiUserRequired(exportTeam)).Methods("GET") + BaseRoutes.Teams.Handle("/import_team", ApiUserRequired(importTeam)).Methods("POST") + BaseRoutes.Teams.Handle("/export_team", ApiUserRequired(exportTeam)).Methods("GET") + BaseRoutes.Teams.Handle("/add_user_to_team_from_invite", ApiUserRequired(addUserToTeamFromInvite)).Methods("POST") } func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) { @@ -92,67 +97,6 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(model.MapToJson(m))) } -func createTeamFromSSO(c *Context, w http.ResponseWriter, r *http.Request) { - params := mux.Vars(r) - service := params["service"] - - sso := utils.Cfg.GetSSOService(service) - if sso != nil && !sso.Enable { - c.SetInvalidParam("createTeamFromSSO", "service") - return - } - - team := model.TeamFromJson(r.Body) - - if team == nil { - c.SetInvalidParam("createTeamFromSSO", "team") - return - } - - if !isTeamCreationAllowed(c, team.Email) { - return - } - - team.PreSave() - - team.Name = model.CleanTeamName(team.Name) - - if err := team.IsValid(*utils.Cfg.TeamSettings.RestrictTeamNames); err != nil { - c.Err = err - return - } - - team.Id = "" - - found := true - count := 0 - for found { - if found = FindTeamByName(c, team.Name, "true"); c.Err != nil { - return - } else if found { - team.Name = team.Name + strconv.Itoa(count) - count += 1 - } - } - - if result := <-Srv.Store.Team().Save(team); result.Err != nil { - c.Err = result.Err - return - } else { - rteam := result.Data.(*model.Team) - - if _, err := CreateDefaultChannels(c, rteam.Id); err != nil { - c.Err = nil - return - } - - data := map[string]string{"follow_link": c.GetSiteURL() + "/api/v1/oauth/" + service + "/signup?team=" + rteam.Name} - w.Write([]byte(model.MapToJson(data))) - - } - -} - func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) { if !utils.Cfg.EmailSettings.EnableSignUpWithEmail { c.Err = model.NewLocAppError("createTeamFromSignup", "api.team.create_team_from_signup.email_disabled.app_error", nil, "") @@ -186,13 +130,11 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) { password := teamSignup.User.Password teamSignup.User.PreSave() - teamSignup.User.TeamId = model.NewId() if err := teamSignup.User.IsValid(); err != nil { c.Err = err return } teamSignup.User.Id = "" - teamSignup.User.TeamId = "" teamSignup.User.Password = password if !model.ComparePassword(teamSignup.Hash, fmt.Sprintf("%v:%v", teamSignup.Data, utils.Cfg.EmailSettings.InviteSalt)) { @@ -206,10 +148,7 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) { return } - found := FindTeamByName(c, teamSignup.Team.Name, "true") - if c.Err != nil { - return - } + found := FindTeamByName(teamSignup.Team.Name) if found { c.Err = model.NewLocAppError("createTeamFromSignup", "api.team.create_team_from_signup.unavailable.app_error", nil, "d="+teamSignup.Team.Name) @@ -227,15 +166,16 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) { return } - teamSignup.User.TeamId = rteam.Id teamSignup.User.EmailVerified = true - ruser, err := CreateUser(rteam, &teamSignup.User) + ruser, err := CreateUser(&teamSignup.User) if err != nil { c.Err = err return } + JoinUserToTeam(rteam, ruser) + InviteMembers(c, rteam, ruser, teamSignup.Invites) teamSignup.Team = *rteam @@ -245,85 +185,38 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) { } } -func createTeamWithLdap(c *Context, w http.ResponseWriter, r *http.Request) { - ldap := einterfaces.GetLdapInterface() - if ldap == nil { - c.Err = model.NewLocAppError("createTeamWithLdap", "ent.ldap.do_login.licence_disable.app_error", nil, "") - return - } - - teamSignup := model.TeamSignupFromJson(r.Body) +func createTeam(c *Context, w http.ResponseWriter, r *http.Request) { + team := model.TeamFromJson(r.Body) - if teamSignup == nil { - c.SetInvalidParam("createTeam", "teamSignup") + if team == nil { + c.SetInvalidParam("createTeam", "team") return } - teamSignup.Team.PreSave() - - if err := teamSignup.Team.IsValid(*utils.Cfg.TeamSettings.RestrictTeamNames); err != nil { - c.Err = err - return - } + var user *model.User + if len(c.Session.UserId) > 0 { + uchan := Srv.Store.User().Get(c.Session.UserId) - if !isTeamCreationAllowed(c, teamSignup.Team.Email) { - return + if result := <-uchan; result.Err != nil { + c.Err = result.Err + return + } else { + user = result.Data.(*model.User) + team.Email = user.Email + } } - teamSignup.Team.Id = "" - - found := FindTeamByName(c, teamSignup.Team.Name, "true") + rteam := CreateTeam(c, team) if c.Err != nil { return } - if found { - c.Err = model.NewLocAppError("createTeamFromSignup", "api.team.create_team_from_signup.unavailable.app_error", nil, "d="+teamSignup.Team.Name) - return - } - - user, err := ldap.GetUser(teamSignup.User.Username) - if err != nil { - c.Err = err - return - } - - err = ldap.CheckPassword(teamSignup.User.Username, teamSignup.User.Password) - if err != nil { - c.Err = err - return - } - - if result := <-Srv.Store.Team().Save(&teamSignup.Team); result.Err != nil { - c.Err = result.Err - return - } else { - rteam := result.Data.(*model.Team) - - if _, err := CreateDefaultChannels(c, rteam.Id); err != nil { - c.Err = nil - return - } - - user.TeamId = rteam.Id - ruser, err := CreateUser(rteam, user) + if user != nil { + err := JoinUserToTeam(team, user) if err != nil { c.Err = err return } - - teamSignup.Team = *rteam - teamSignup.User = *ruser - - w.Write([]byte(teamSignup.ToJson())) - } -} - -func createTeam(c *Context, w http.ResponseWriter, r *http.Request) { - team := model.TeamFromJson(r.Body) - rteam := CreateTeam(c, team) - if c.Err != nil { - return } w.Write([]byte(rteam.ToJson())) @@ -360,6 +253,31 @@ func CreateTeam(c *Context, team *model.Team) *model.Team { } } +func JoinUserToTeam(team *model.Team, user *model.User) *model.AppError { + + tm := &model.TeamMember{TeamId: team.Id, UserId: user.Id} + + channelRole := "" + if team.Email == user.Email { + tm.Roles = model.ROLE_TEAM_ADMIN + channelRole = model.CHANNEL_ROLE_ADMIN + } + + if tmr := <-Srv.Store.Team().SaveMember(tm); tmr.Err != nil { + return tmr.Err + } + + // Soft error if there is an issue joining the default channels + if err := JoinDefaultChannels(team.Id, user, channelRole); err != nil { + l4g.Error(utils.T("api.user.create_user.joining.error"), user.Id, team.Id, err) + } + + RemoveAllSessionsForUserId(user.Id) + InvalidateCacheForUser(user.Id) + + return nil +} + func isTeamCreationAllowed(c *Context, email string) bool { email = strings.ToLower(email) @@ -389,6 +307,24 @@ func isTeamCreationAllowed(c *Context, email string) bool { return true } +func GetAllTeamListings(c *Context, w http.ResponseWriter, r *http.Request) { + if result := <-Srv.Store.Team().GetAllTeamListing(); result.Err != nil { + c.Err = result.Err + return + } else { + teams := result.Data.([]*model.Team) + m := make(map[string]*model.Team) + for _, v := range teams { + m[v.Id] = v + if !c.IsSystemAdmin() { + m[v.Id].Sanitize() + } + } + + w.Write([]byte(model.TeamMapToJson(m))) + } +} + func getAll(c *Context, w http.ResponseWriter, r *http.Request) { if result := <-Srv.Store.Team().GetAll(); result.Err != nil { c.Err = result.Err @@ -435,52 +371,54 @@ func revokeAllSessions(c *Context, w http.ResponseWriter, r *http.Request) { } } -func findTeamByName(c *Context, w http.ResponseWriter, r *http.Request) { - - m := model.MapFromJson(r.Body) - - name := strings.ToLower(strings.TrimSpace(m["name"])) - all := strings.ToLower(strings.TrimSpace(m["all"])) +func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) { + invites := model.InvitesFromJson(r.Body) + if len(invites.Invites) == 0 { + c.Err = model.NewLocAppError("Team.InviteMembers", "api.team.invite_members.no_one.app_error", nil, "") + c.Err.StatusCode = http.StatusBadRequest + return + } - found := FindTeamByName(c, name, all) + tchan := Srv.Store.Team().Get(c.TeamId) + uchan := Srv.Store.User().Get(c.Session.UserId) - if c.Err != nil { + var team *model.Team + if result := <-tchan; result.Err != nil { + c.Err = result.Err return + } else { + team = result.Data.(*model.Team) } - if found { - w.Write([]byte("true")) + var user *model.User + if result := <-uchan; result.Err != nil { + c.Err = result.Err + return } else { - w.Write([]byte("false")) + user = result.Data.(*model.User) } -} - -func FindTeamByName(c *Context, name string, all string) bool { - if name == "" || len(name) > 64 { - c.SetInvalidParam("findTeamByName", "domain") - return false + ia := make([]string, len(invites.Invites)) + for _, invite := range invites.Invites { + ia = append(ia, invite["email"]) } - if result := <-Srv.Store.Team().GetByName(name); result.Err != nil { - return false - } else { - return true - } + InviteMembers(c, team, user, ia) - return false + w.Write([]byte(invites.ToJson())) } -func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) { - invites := model.InvitesFromJson(r.Body) - if len(invites.Invites) == 0 { - c.Err = model.NewLocAppError("Team.InviteMembers", "api.team.invite_members.no_one.app_error", nil, "") - c.Err.StatusCode = http.StatusBadRequest +func addUserToTeam(c *Context, w http.ResponseWriter, r *http.Request) { + params := model.MapFromJson(r.Body) + userId := params["user_id"] + + if len(userId) != 26 { + c.SetInvalidParam("addUserToTeam", "user_id") return } - tchan := Srv.Store.Team().Get(c.Session.TeamId) - uchan := Srv.Store.User().Get(c.Session.UserId) + tchan := Srv.Store.Team().Get(c.TeamId) + uchan := Srv.Store.User().Get(userId) var team *model.Team if result := <-tchan; result.Err != nil { @@ -498,23 +436,116 @@ func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) { user = result.Data.(*model.User) } - var invNum int64 = 0 - for i, invite := range invites.Invites { - if result := <-Srv.Store.User().GetByEmail(c.Session.TeamId, invite["email"]); result.Err == nil || result.Err.Id != store.MISSING_ACCOUNT_ERROR { - invNum = int64(i) - c.Err = model.NewLocAppError("invite_members", "api.team.invite_members.already.app_error", nil, strconv.FormatInt(invNum, 10)) + if !c.IsTeamAdmin() { + c.Err = model.NewLocAppError("addUserToTeam", "api.team.update_team.permissions.app_error", nil, "userId="+c.Session.UserId) + c.Err.StatusCode = http.StatusForbidden + return + } + + err := JoinUserToTeam(team, user) + if err != nil { + c.Err = err + return + } + + w.Write([]byte(model.MapToJson(params))) +} + +func addUserToTeamFromInvite(c *Context, w http.ResponseWriter, r *http.Request) { + + params := model.MapFromJson(r.Body) + hash := params["hash"] + data := params["data"] + inviteId := params["invite_id"] + + teamId := "" + var team *model.Team + + if len(hash) > 0 { + props := model.MapFromJson(strings.NewReader(data)) + + if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) { + c.Err = model.NewLocAppError("addUserToTeamFromInvite", "api.user.create_user.signup_link_invalid.app_error", nil, "") + return + } + + t, err := strconv.ParseInt(props["time"], 10, 64) + if err != nil || model.GetMillis()-t > 1000*60*60*48 { // 48 hours + c.Err = model.NewLocAppError("addUserToTeamFromInvite", "api.user.create_user.signup_link_expired.app_error", nil, "") + return + } + + teamId = props["id"] + + // try to load the team to make sure it exists + if result := <-Srv.Store.Team().Get(teamId); result.Err != nil { + c.Err = result.Err + return + } else { + team = result.Data.(*model.Team) + } + } + + if len(inviteId) > 0 { + if result := <-Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil { + c.Err = result.Err + return + } else { + team = result.Data.(*model.Team) + teamId = team.Id + } + } + + if len(teamId) == 0 { + c.Err = model.NewLocAppError("addUserToTeamFromInvite", "api.user.create_user.signup_link_invalid.app_error", nil, "") + return + } + + uchan := Srv.Store.User().Get(c.Session.UserId) + + var user *model.User + if result := <-uchan; result.Err != nil { + c.Err = result.Err + return + } else { + user = result.Data.(*model.User) + } + + tm := c.Session.GetTeamByTeamId(teamId) + + if tm == nil { + err := JoinUserToTeam(team, user) + if err != nil { + c.Err = err return } } - ia := make([]string, len(invites.Invites)) - for _, invite := range invites.Invites { - ia = append(ia, invite["email"]) + team.Sanitize() + + w.Write([]byte(team.ToJson())) +} + +func FindTeamByName(name string) bool { + if result := <-Srv.Store.Team().GetByName(name); result.Err != nil { + return false + } else { + return true } +} - InviteMembers(c, team, user, ia) +func findTeamByName(c *Context, w http.ResponseWriter, r *http.Request) { - w.Write([]byte(invites.ToJson())) + m := model.MapFromJson(r.Body) + name := strings.ToLower(strings.TrimSpace(m["name"])) + + found := FindTeamByName(name) + + if found { + w.Write([]byte("true")) + } else { + w.Write([]byte("false")) + } } func InviteMembers(c *Context, team *model.Team, user *model.User, invites []string) { @@ -573,7 +604,7 @@ func updateTeam(c *Context, w http.ResponseWriter, r *http.Request) { return } - team.Id = c.Session.TeamId + team.Id = c.TeamId if !c.IsTeamAdmin() { c.Err = model.NewLocAppError("updateTeam", "api.team.update_team.permissions.app_error", nil, "userId="+c.Session.UserId) @@ -592,7 +623,6 @@ func updateTeam(c *Context, w http.ResponseWriter, r *http.Request) { oldTeam.DisplayName = team.DisplayName oldTeam.InviteId = team.InviteId oldTeam.AllowOpenInvite = team.AllowOpenInvite - oldTeam.AllowTeamListing = team.AllowTeamListing oldTeam.CompanyName = team.CompanyName oldTeam.AllowedDomains = team.AllowedDomains //oldTeam.Type = team.Type @@ -617,16 +647,11 @@ func PermanentDeleteTeam(c *Context, team *model.Team) *model.AppError { return result.Err } - if result := <-Srv.Store.User().GetForExport(team.Id); result.Err != nil { + if result := <-Srv.Store.Channel().PermanentDeleteByTeam(team.Id); result.Err != nil { return result.Err - } else { - users := result.Data.([]*model.User) - for _, user := range users { - PermanentDeleteUser(c, user) - } } - if result := <-Srv.Store.Channel().PermanentDeleteByTeam(team.Id); result.Err != nil { + if result := <-Srv.Store.Team().RemoveAllMembersByTeam(team.Id); result.Err != nil { return result.Err } @@ -642,11 +667,11 @@ func PermanentDeleteTeam(c *Context, team *model.Team) *model.AppError { func getMyTeam(c *Context, w http.ResponseWriter, r *http.Request) { - if len(c.Session.TeamId) == 0 { + if len(c.TeamId) == 0 { return } - if result := <-Srv.Store.Team().Get(c.Session.TeamId); result.Err != nil { + if result := <-Srv.Store.Team().Get(c.TeamId); result.Err != nil { c.Err = result.Err return } else if HandleEtag(result.Data.(*model.Team).Etag(), w, r) { @@ -659,7 +684,7 @@ func getMyTeam(c *Context, w http.ResponseWriter, r *http.Request) { } func importTeam(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.HasPermissionsToTeam(c.Session.TeamId, "import") || !c.IsTeamAdmin() { + if !c.HasPermissionsToTeam(c.TeamId, "import") || !c.IsTeamAdmin() { c.Err = model.NewLocAppError("importTeam", "api.team.import_team.admin.app_error", nil, "userId="+c.Session.UserId) c.Err.StatusCode = http.StatusForbidden return @@ -714,7 +739,7 @@ func importTeam(c *Context, w http.ResponseWriter, r *http.Request) { switch importFrom { case "slack": var err *model.AppError - if err, log = SlackImport(fileData, fileSize, c.Session.TeamId); err != nil { + if err, log = SlackImport(fileData, fileSize, c.TeamId); err != nil { c.Err = err c.Err.StatusCode = http.StatusBadRequest } @@ -726,7 +751,7 @@ func importTeam(c *Context, w http.ResponseWriter, r *http.Request) { } func exportTeam(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.HasPermissionsToTeam(c.Session.TeamId, "export") || !c.IsTeamAdmin() { + if !c.HasPermissionsToTeam(c.TeamId, "export") || !c.IsTeamAdmin() { c.Err = model.NewLocAppError("exportTeam", "api.team.export_team.admin.app_error", nil, "userId="+c.Session.UserId) c.Err.StatusCode = http.StatusForbidden return @@ -765,3 +790,23 @@ func getInviteInfo(c *Context, w http.ResponseWriter, r *http.Request) { w.Write([]byte(model.MapToJson(result))) } } + +func getMembers(c *Context, w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + id := params["id"] + + if c.Session.GetTeamByTeamId(id) == nil { + if !c.HasSystemAdminPermissions("getMembers") { + return + } + } + + if result := <-Srv.Store.Team().GetMembers(id); result.Err != nil { + c.Err = result.Err + return + } else { + members := result.Data.([]*model.TeamMember) + w.Write([]byte(model.TeamMembersToJson(members))) + return + } +} -- cgit v1.2.3-1-g7c22