github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/model/team.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package model
     5  
     6  import (
     7  	"encoding/json"
     8  	"fmt"
     9  	"io"
    10  	"net/http"
    11  	"regexp"
    12  	"strings"
    13  	"unicode/utf8"
    14  )
    15  
    16  const (
    17  	TEAM_OPEN                       = "O"
    18  	TEAM_INVITE                     = "I"
    19  	TEAM_ALLOWED_DOMAINS_MAX_LENGTH = 500
    20  	TEAM_COMPANY_NAME_MAX_LENGTH    = 64
    21  	TEAM_DESCRIPTION_MAX_LENGTH     = 255
    22  	TEAM_DISPLAY_NAME_MAX_RUNES     = 64
    23  	TEAM_EMAIL_MAX_LENGTH           = 128
    24  	TEAM_NAME_MAX_LENGTH            = 64
    25  	TEAM_NAME_MIN_LENGTH            = 2
    26  )
    27  
    28  type Team struct {
    29  	Id                 string  `json:"id"`
    30  	CreateAt           int64   `json:"create_at"`
    31  	UpdateAt           int64   `json:"update_at"`
    32  	DeleteAt           int64   `json:"delete_at"`
    33  	DisplayName        string  `json:"display_name"`
    34  	Name               string  `json:"name"`
    35  	Description        string  `json:"description"`
    36  	Email              string  `json:"email"`
    37  	Type               string  `json:"type"`
    38  	CompanyName        string  `json:"company_name"`
    39  	AllowedDomains     string  `json:"allowed_domains"`
    40  	InviteId           string  `json:"invite_id"`
    41  	AllowOpenInvite    bool    `json:"allow_open_invite"`
    42  	LastTeamIconUpdate int64   `json:"last_team_icon_update,omitempty"`
    43  	SchemeId           *string `json:"scheme_id"`
    44  	GroupConstrained   *bool   `json:"group_constrained"`
    45  }
    46  
    47  type TeamPatch struct {
    48  	DisplayName      *string `json:"display_name"`
    49  	Description      *string `json:"description"`
    50  	CompanyName      *string `json:"company_name"`
    51  	AllowedDomains   *string `json:"allowed_domains"`
    52  	AllowOpenInvite  *bool   `json:"allow_open_invite"`
    53  	GroupConstrained *bool   `json:"group_constrained"`
    54  }
    55  
    56  type TeamForExport struct {
    57  	Team
    58  	SchemeName *string
    59  }
    60  
    61  type Invites struct {
    62  	Invites []map[string]string `json:"invites"`
    63  }
    64  
    65  type TeamsWithCount struct {
    66  	Teams      []*Team `json:"teams"`
    67  	TotalCount int64   `json:"total_count"`
    68  }
    69  
    70  func InvitesFromJson(data io.Reader) *Invites {
    71  	var o *Invites
    72  	json.NewDecoder(data).Decode(&o)
    73  	return o
    74  }
    75  
    76  func (o *Invites) ToEmailList() []string {
    77  	emailList := make([]string, len(o.Invites))
    78  	for _, invite := range o.Invites {
    79  		emailList = append(emailList, invite["email"])
    80  	}
    81  	return emailList
    82  }
    83  
    84  func (o *Invites) ToJson() string {
    85  	b, _ := json.Marshal(o)
    86  	return string(b)
    87  }
    88  
    89  func (o *Team) ToJson() string {
    90  	b, _ := json.Marshal(o)
    91  	return string(b)
    92  }
    93  
    94  func TeamFromJson(data io.Reader) *Team {
    95  	var o *Team
    96  	json.NewDecoder(data).Decode(&o)
    97  	return o
    98  }
    99  
   100  func TeamMapToJson(u map[string]*Team) string {
   101  	b, _ := json.Marshal(u)
   102  	return string(b)
   103  }
   104  
   105  func TeamMapFromJson(data io.Reader) map[string]*Team {
   106  	var teams map[string]*Team
   107  	json.NewDecoder(data).Decode(&teams)
   108  	return teams
   109  }
   110  
   111  func TeamListToJson(t []*Team) string {
   112  	b, _ := json.Marshal(t)
   113  	return string(b)
   114  }
   115  
   116  func TeamsWithCountToJson(tlc *TeamsWithCount) []byte {
   117  	b, _ := json.Marshal(tlc)
   118  	return b
   119  }
   120  
   121  func TeamsWithCountFromJson(data io.Reader) *TeamsWithCount {
   122  	var twc *TeamsWithCount
   123  	json.NewDecoder(data).Decode(&twc)
   124  	return twc
   125  }
   126  
   127  func TeamListFromJson(data io.Reader) []*Team {
   128  	var teams []*Team
   129  	json.NewDecoder(data).Decode(&teams)
   130  	return teams
   131  }
   132  
   133  func (o *Team) Etag() string {
   134  	return Etag(o.Id, o.UpdateAt)
   135  }
   136  
   137  func (o *Team) IsValid() *AppError {
   138  
   139  	if !IsValidId(o.Id) {
   140  		return NewAppError("Team.IsValid", "model.team.is_valid.id.app_error", nil, "", http.StatusBadRequest)
   141  	}
   142  
   143  	if o.CreateAt == 0 {
   144  		return NewAppError("Team.IsValid", "model.team.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   145  	}
   146  
   147  	if o.UpdateAt == 0 {
   148  		return NewAppError("Team.IsValid", "model.team.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   149  	}
   150  
   151  	if len(o.Email) > TEAM_EMAIL_MAX_LENGTH {
   152  		return NewAppError("Team.IsValid", "model.team.is_valid.email.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   153  	}
   154  
   155  	if len(o.Email) > 0 && !IsValidEmail(o.Email) {
   156  		return NewAppError("Team.IsValid", "model.team.is_valid.email.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   157  	}
   158  
   159  	if utf8.RuneCountInString(o.DisplayName) == 0 || utf8.RuneCountInString(o.DisplayName) > TEAM_DISPLAY_NAME_MAX_RUNES {
   160  		return NewAppError("Team.IsValid", "model.team.is_valid.name.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   161  	}
   162  
   163  	if len(o.Name) > TEAM_NAME_MAX_LENGTH {
   164  		return NewAppError("Team.IsValid", "model.team.is_valid.url.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   165  	}
   166  
   167  	if len(o.Description) > TEAM_DESCRIPTION_MAX_LENGTH {
   168  		return NewAppError("Team.IsValid", "model.team.is_valid.description.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   169  	}
   170  
   171  	if len(o.InviteId) == 0 {
   172  		return NewAppError("Team.IsValid", "model.team.is_valid.invite_id.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   173  	}
   174  
   175  	if IsReservedTeamName(o.Name) {
   176  		return NewAppError("Team.IsValid", "model.team.is_valid.reserved.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   177  	}
   178  
   179  	if !IsValidTeamName(o.Name) {
   180  		return NewAppError("Team.IsValid", "model.team.is_valid.characters.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   181  	}
   182  
   183  	if !(o.Type == TEAM_OPEN || o.Type == TEAM_INVITE) {
   184  		return NewAppError("Team.IsValid", "model.team.is_valid.type.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   185  	}
   186  
   187  	if len(o.CompanyName) > TEAM_COMPANY_NAME_MAX_LENGTH {
   188  		return NewAppError("Team.IsValid", "model.team.is_valid.company.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   189  	}
   190  
   191  	if len(o.AllowedDomains) > TEAM_ALLOWED_DOMAINS_MAX_LENGTH {
   192  		return NewAppError("Team.IsValid", "model.team.is_valid.domains.app_error", nil, "id="+o.Id, http.StatusBadRequest)
   193  	}
   194  
   195  	return nil
   196  }
   197  
   198  func (o *Team) PreSave() {
   199  	if o.Id == "" {
   200  		o.Id = NewId()
   201  	}
   202  
   203  	o.CreateAt = GetMillis()
   204  	o.UpdateAt = o.CreateAt
   205  
   206  	o.Name = SanitizeUnicode(o.Name)
   207  	o.DisplayName = SanitizeUnicode(o.DisplayName)
   208  	o.Description = SanitizeUnicode(o.Description)
   209  	o.CompanyName = SanitizeUnicode(o.CompanyName)
   210  
   211  	if len(o.InviteId) == 0 {
   212  		o.InviteId = NewId()
   213  	}
   214  }
   215  
   216  func (o *Team) PreUpdate() {
   217  	o.UpdateAt = GetMillis()
   218  	o.Name = SanitizeUnicode(o.Name)
   219  	o.DisplayName = SanitizeUnicode(o.DisplayName)
   220  	o.Description = SanitizeUnicode(o.Description)
   221  	o.CompanyName = SanitizeUnicode(o.CompanyName)
   222  }
   223  
   224  func IsReservedTeamName(s string) bool {
   225  	s = strings.ToLower(s)
   226  
   227  	for _, value := range reservedName {
   228  		if strings.Index(s, value) == 0 {
   229  			return true
   230  		}
   231  	}
   232  
   233  	return false
   234  }
   235  
   236  func IsValidTeamName(s string) bool {
   237  	if !IsValidAlphaNum(s) {
   238  		return false
   239  	}
   240  
   241  	if len(s) < TEAM_NAME_MIN_LENGTH {
   242  		return false
   243  	}
   244  
   245  	return true
   246  }
   247  
   248  var validTeamNameCharacter = regexp.MustCompile(`^[a-z0-9-]$`)
   249  
   250  func CleanTeamName(s string) string {
   251  	s = strings.ToLower(strings.Replace(s, " ", "-", -1))
   252  
   253  	for _, value := range reservedName {
   254  		if strings.Index(s, value) == 0 {
   255  			s = strings.Replace(s, value, "", -1)
   256  		}
   257  	}
   258  
   259  	s = strings.TrimSpace(s)
   260  
   261  	for _, c := range s {
   262  		char := fmt.Sprintf("%c", c)
   263  		if !validTeamNameCharacter.MatchString(char) {
   264  			s = strings.Replace(s, char, "", -1)
   265  		}
   266  	}
   267  
   268  	s = strings.Trim(s, "-")
   269  
   270  	if !IsValidTeamName(s) {
   271  		s = NewId()
   272  	}
   273  
   274  	return s
   275  }
   276  
   277  func (o *Team) Sanitize() {
   278  	o.Email = ""
   279  	o.InviteId = ""
   280  }
   281  
   282  func (o *Team) Patch(patch *TeamPatch) {
   283  	if patch.DisplayName != nil {
   284  		o.DisplayName = *patch.DisplayName
   285  	}
   286  
   287  	if patch.Description != nil {
   288  		o.Description = *patch.Description
   289  	}
   290  
   291  	if patch.CompanyName != nil {
   292  		o.CompanyName = *patch.CompanyName
   293  	}
   294  
   295  	if patch.AllowedDomains != nil {
   296  		o.AllowedDomains = *patch.AllowedDomains
   297  	}
   298  
   299  	if patch.AllowOpenInvite != nil {
   300  		o.AllowOpenInvite = *patch.AllowOpenInvite
   301  	}
   302  
   303  	if patch.GroupConstrained != nil {
   304  		o.GroupConstrained = patch.GroupConstrained
   305  	}
   306  }
   307  
   308  func (o *Team) IsGroupConstrained() bool {
   309  	return o.GroupConstrained != nil && *o.GroupConstrained
   310  }
   311  
   312  func (t *TeamPatch) ToJson() string {
   313  	b, err := json.Marshal(t)
   314  	if err != nil {
   315  		return ""
   316  	}
   317  
   318  	return string(b)
   319  }
   320  
   321  func TeamPatchFromJson(data io.Reader) *TeamPatch {
   322  	decoder := json.NewDecoder(data)
   323  	var team TeamPatch
   324  	err := decoder.Decode(&team)
   325  	if err != nil {
   326  		return nil
   327  	}
   328  
   329  	return &team
   330  }