github.com/mattermost/mattermost-server/v5@v5.39.3/api4/team_local.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package api4 5 6 import ( 7 "net/http" 8 "strings" 9 10 "github.com/pkg/errors" 11 12 "github.com/mattermost/mattermost-server/v5/audit" 13 "github.com/mattermost/mattermost-server/v5/model" 14 "github.com/mattermost/mattermost-server/v5/store" 15 ) 16 17 func (api *API) InitTeamLocal() { 18 api.BaseRoutes.Teams.Handle("", api.ApiLocal(localCreateTeam)).Methods("POST") 19 api.BaseRoutes.Teams.Handle("", api.ApiLocal(getAllTeams)).Methods("GET") 20 api.BaseRoutes.Teams.Handle("/search", api.ApiLocal(searchTeams)).Methods("POST") 21 22 api.BaseRoutes.Team.Handle("", api.ApiLocal(getTeam)).Methods("GET") 23 api.BaseRoutes.Team.Handle("", api.ApiLocal(updateTeam)).Methods("PUT") 24 api.BaseRoutes.Team.Handle("", api.ApiLocal(localDeleteTeam)).Methods("DELETE") 25 api.BaseRoutes.Team.Handle("/invite/email", api.ApiLocal(localInviteUsersToTeam)).Methods("POST") 26 api.BaseRoutes.Team.Handle("/patch", api.ApiLocal(patchTeam)).Methods("PUT") 27 api.BaseRoutes.Team.Handle("/privacy", api.ApiLocal(updateTeamPrivacy)).Methods("PUT") 28 api.BaseRoutes.Team.Handle("/restore", api.ApiLocal(restoreTeam)).Methods("POST") 29 30 api.BaseRoutes.TeamByName.Handle("", api.ApiLocal(getTeamByName)).Methods("GET") 31 api.BaseRoutes.TeamMembers.Handle("", api.ApiLocal(addTeamMember)).Methods("POST") 32 api.BaseRoutes.TeamMember.Handle("", api.ApiLocal(removeTeamMember)).Methods("DELETE") 33 } 34 35 func localDeleteTeam(c *Context, w http.ResponseWriter, r *http.Request) { 36 c.RequireTeamId() 37 if c.Err != nil { 38 return 39 } 40 41 auditRec := c.MakeAuditRecord("localDeleteTeam", audit.Fail) 42 defer c.LogAuditRec(auditRec) 43 44 if team, err := c.App.GetTeam(c.Params.TeamId); err == nil { 45 auditRec.AddMeta("team", team) 46 } 47 48 var err *model.AppError 49 if c.Params.Permanent { 50 err = c.App.PermanentDeleteTeamId(c.Params.TeamId) 51 } else { 52 err = c.App.SoftDeleteTeam(c.Params.TeamId) 53 } 54 55 if err != nil { 56 c.Err = err 57 return 58 } 59 60 auditRec.Success() 61 ReturnStatusOK(w) 62 } 63 64 func localInviteUsersToTeam(c *Context, w http.ResponseWriter, r *http.Request) { 65 c.RequireTeamId() 66 if c.Err != nil { 67 return 68 } 69 70 if !*c.App.Config().ServiceSettings.EnableEmailInvitations { 71 c.Err = model.NewAppError("localInviteUsersToTeam", "api.team.invite_members.disabled.app_error", nil, "", http.StatusNotImplemented) 72 return 73 } 74 75 emailList := model.ArrayFromJson(r.Body) 76 if len(emailList) == 0 { 77 c.SetInvalidParam("user_email") 78 return 79 } 80 for i := range emailList { 81 email := strings.ToLower(emailList[i]) 82 if !model.IsValidEmail(email) { 83 c.Err = model.NewAppError("localInviteUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Address": email}, "", http.StatusBadRequest) 84 return 85 } 86 emailList[i] = email 87 } 88 89 auditRec := c.MakeAuditRecord("localInviteUsersToTeam", audit.Fail) 90 defer c.LogAuditRec(auditRec) 91 auditRec.AddMeta("team_id", c.Params.TeamId) 92 auditRec.AddMeta("count", len(emailList)) 93 auditRec.AddMeta("emails", emailList) 94 95 team, nErr := c.App.Srv().Store.Team().Get(c.Params.TeamId) 96 if nErr != nil { 97 var nfErr *store.ErrNotFound 98 switch { 99 case errors.As(nErr, &nfErr): 100 c.Err = model.NewAppError("localInviteUsersToTeam", "app.team.get.find.app_error", nil, nfErr.Error(), http.StatusNotFound) 101 default: 102 c.Err = model.NewAppError("localInviteUsersToTeam", "app.team.get.finding.app_error", nil, nErr.Error(), http.StatusInternalServerError) 103 } 104 return 105 } 106 107 allowedDomains := []string{team.AllowedDomains, *c.App.Config().TeamSettings.RestrictCreationToDomains} 108 109 if r.URL.Query().Get("graceful") != "" { 110 var invitesWithErrors []*model.EmailInviteWithError 111 var goodEmails, errList []string 112 for _, email := range emailList { 113 invite := &model.EmailInviteWithError{ 114 Email: email, 115 Error: nil, 116 } 117 if !isEmailAddressAllowed(email, allowedDomains) { 118 invite.Error = model.NewAppError("localInviteUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": email}, "", http.StatusBadRequest) 119 errList = append(errList, model.EmailInviteWithErrorToString(invite)) 120 } else { 121 goodEmails = append(goodEmails, email) 122 } 123 invitesWithErrors = append(invitesWithErrors, invite) 124 } 125 auditRec.AddMeta("errors", errList) 126 if len(goodEmails) > 0 { 127 err := c.App.Srv().EmailService.SendInviteEmails(team, "Administrator", "mmctl "+model.NewId(), goodEmails, *c.App.Config().ServiceSettings.SiteURL) 128 if err != nil { 129 c.Err = err 130 return 131 } 132 } 133 // in graceful mode we return both the successful ones and the failed ones 134 w.Write([]byte(model.EmailInviteWithErrorToJson(invitesWithErrors))) 135 } else { 136 var invalidEmailList []string 137 138 for _, email := range emailList { 139 if !isEmailAddressAllowed(email, allowedDomains) { 140 invalidEmailList = append(invalidEmailList, email) 141 } 142 } 143 if len(invalidEmailList) > 0 { 144 s := strings.Join(invalidEmailList, ", ") 145 c.Err = model.NewAppError("localInviteUsersToTeam", "api.team.invite_members.invalid_email.app_error", map[string]interface{}{"Addresses": s}, "", http.StatusBadRequest) 146 return 147 } 148 err := c.App.Srv().EmailService.SendInviteEmails(team, "Administrator", "mmctl "+model.NewId(), emailList, *c.App.Config().ServiceSettings.SiteURL) 149 if err != nil { 150 c.Err = err 151 return 152 } 153 ReturnStatusOK(w) 154 } 155 auditRec.Success() 156 } 157 158 func isEmailAddressAllowed(email string, allowedDomains []string) bool { 159 for _, restriction := range allowedDomains { 160 domains := normalizeDomains(restriction) 161 if len(domains) <= 0 { 162 continue 163 } 164 matched := false 165 for _, d := range domains { 166 if strings.HasSuffix(email, "@"+d) { 167 matched = true 168 break 169 } 170 } 171 if !matched { 172 return false 173 } 174 } 175 return true 176 } 177 178 func normalizeDomains(domains string) []string { 179 // commas and @ signs are optional 180 // can be in the form of "@corp.mattermost.com, mattermost.com mattermost.org" -> corp.mattermost.com mattermost.com mattermost.org 181 return strings.Fields(strings.TrimSpace(strings.ToLower(strings.Replace(strings.Replace(domains, "@", " ", -1), ",", " ", -1)))) 182 } 183 184 func localCreateTeam(c *Context, w http.ResponseWriter, r *http.Request) { 185 team := model.TeamFromJson(r.Body) 186 if team == nil { 187 c.SetInvalidParam("team") 188 return 189 } 190 team.Email = strings.ToLower(team.Email) 191 192 auditRec := c.MakeAuditRecord("localCreateTeam", audit.Fail) 193 defer c.LogAuditRec(auditRec) 194 auditRec.AddMeta("team", team) 195 196 rteam, err := c.App.CreateTeam(c.AppContext, team) 197 if err != nil { 198 c.Err = err 199 return 200 } 201 // Don't sanitize the team here since the user will be a team admin and their session won't reflect that yet 202 203 auditRec.Success() 204 auditRec.AddMeta("team", team) // overwrite meta 205 206 w.WriteHeader(http.StatusCreated) 207 w.Write([]byte(rteam.ToJson())) 208 }