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  }