diff options
author | Wim <wim@42.be> | 2023-08-05 20:43:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-05 20:43:19 +0200 |
commit | 56e7bd01ca09ad52b0c4f48f146a20a4f1b78696 (patch) | |
tree | b1355645342667209263cbd355dc0b4254f1e8fe /vendor/github.com/mattermost/mattermost-server/v5/model | |
parent | 9459495484d6e06a3d46de64fccd8d06f7ccc72c (diff) | |
download | matterbridge-msglm-master.tar.gz matterbridge-msglm-master.tar.bz2 matterbridge-msglm-master.zip |
Diffstat (limited to 'vendor/github.com/mattermost/mattermost-server/v5/model')
128 files changed, 0 insertions, 31702 deletions
diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/access.go b/vendor/github.com/mattermost/mattermost-server/v5/model/access.go deleted file mode 100644 index 6b60ea9e..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/access.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" -) - -const ( - ACCESS_TOKEN_GRANT_TYPE = "authorization_code" - ACCESS_TOKEN_TYPE = "bearer" - REFRESH_TOKEN_GRANT_TYPE = "refresh_token" -) - -type AccessData struct { - ClientId string `json:"client_id"` - UserId string `json:"user_id"` - Token string `json:"token"` - RefreshToken string `json:"refresh_token"` - RedirectUri string `json:"redirect_uri"` - ExpiresAt int64 `json:"expires_at"` - Scope string `json:"scope"` -} - -type AccessResponse struct { - AccessToken string `json:"access_token"` - TokenType string `json:"token_type"` - ExpiresIn int32 `json:"expires_in"` - Scope string `json:"scope"` - RefreshToken string `json:"refresh_token"` - IdToken string `json:"id_token"` -} - -// IsValid validates the AccessData and returns an error if it isn't configured -// correctly. -func (ad *AccessData) IsValid() *AppError { - - if ad.ClientId == "" || len(ad.ClientId) > 26 { - return NewAppError("AccessData.IsValid", "model.access.is_valid.client_id.app_error", nil, "", http.StatusBadRequest) - } - - if ad.UserId == "" || len(ad.UserId) > 26 { - return NewAppError("AccessData.IsValid", "model.access.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) - } - - if len(ad.Token) != 26 { - return NewAppError("AccessData.IsValid", "model.access.is_valid.access_token.app_error", nil, "", http.StatusBadRequest) - } - - if len(ad.RefreshToken) > 26 { - return NewAppError("AccessData.IsValid", "model.access.is_valid.refresh_token.app_error", nil, "", http.StatusBadRequest) - } - - if ad.RedirectUri == "" || len(ad.RedirectUri) > 256 || !IsValidHttpUrl(ad.RedirectUri) { - return NewAppError("AccessData.IsValid", "model.access.is_valid.redirect_uri.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (ad *AccessData) IsExpired() bool { - - if ad.ExpiresAt <= 0 { - return false - } - - if GetMillis() > ad.ExpiresAt { - return true - } - - return false -} - -func (ad *AccessData) ToJson() string { - b, _ := json.Marshal(ad) - return string(b) -} - -func AccessDataFromJson(data io.Reader) *AccessData { - var ad *AccessData - json.NewDecoder(data).Decode(&ad) - return ad -} - -func (ar *AccessResponse) ToJson() string { - b, _ := json.Marshal(ar) - return string(b) -} - -func AccessResponseFromJson(data io.Reader) *AccessResponse { - var ar *AccessResponse - json.NewDecoder(data).Decode(&ar) - return ar -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/analytics_row.go b/vendor/github.com/mattermost/mattermost-server/v5/model/analytics_row.go deleted file mode 100644 index d1216664..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/analytics_row.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type AnalyticsRow struct { - Name string `json:"name"` - Value float64 `json:"value"` -} - -type AnalyticsRows []*AnalyticsRow - -func (ar *AnalyticsRow) ToJson() string { - b, _ := json.Marshal(ar) - return string(b) -} - -func AnalyticsRowFromJson(data io.Reader) *AnalyticsRow { - var ar *AnalyticsRow - json.NewDecoder(data).Decode(&ar) - return ar -} - -func (ar AnalyticsRows) ToJson() string { - b, err := json.Marshal(ar) - if err != nil { - return "[]" - } - return string(b) -} - -func AnalyticsRowsFromJson(data io.Reader) AnalyticsRows { - var ar AnalyticsRows - json.NewDecoder(data).Decode(&ar) - return ar -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/at_mentions.go b/vendor/github.com/mattermost/mattermost-server/v5/model/at_mentions.go deleted file mode 100644 index b5bfc0c7..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/at_mentions.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "regexp" - "strings" -) - -var atMentionRegexp = regexp.MustCompile(`\B@[[:alnum:]][[:alnum:]\.\-_:]*`) - -const usernameSpecialChars = ".-_" - -// PossibleAtMentions returns all substrings in message that look like valid @ -// mentions. -func PossibleAtMentions(message string) []string { - var names []string - - if !strings.Contains(message, "@") { - return names - } - - alreadyMentioned := make(map[string]bool) - for _, match := range atMentionRegexp.FindAllString(message, -1) { - name := NormalizeUsername(match[1:]) - if !alreadyMentioned[name] && IsValidUsernameAllowRemote(name) { - names = append(names, name) - alreadyMentioned[name] = true - } - } - - return names -} - -// TrimUsernameSpecialChar tries to remove the last character from word if it -// is a special character for usernames (dot, dash or underscore). If not, it -// returns the same string. -func TrimUsernameSpecialChar(word string) (string, bool) { - len := len(word) - - if len > 0 && strings.LastIndexAny(word, usernameSpecialChars) == (len-1) { - return word[:len-1], true - } - - return word, false -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/audit.go b/vendor/github.com/mattermost/mattermost-server/v5/model/audit.go deleted file mode 100644 index dd1e0602..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/audit.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type Audit struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at"` - UserId string `json:"user_id"` - Action string `json:"action"` - ExtraInfo string `json:"extra_info"` - IpAddress string `json:"ip_address"` - SessionId string `json:"session_id"` -} - -func (o *Audit) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func AuditFromJson(data io.Reader) *Audit { - var o *Audit - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/auditconv.go b/vendor/github.com/mattermost/mattermost-server/v5/model/auditconv.go deleted file mode 100644 index b3cf6062..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/auditconv.go +++ /dev/null @@ -1,713 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "github.com/francoispqt/gojay" -) - -// AuditModelTypeConv converts key model types to something better suited for audit output. -func AuditModelTypeConv(val interface{}) (newVal interface{}, converted bool) { - if val == nil { - return nil, false - } - switch v := val.(type) { - case *Channel: - return newAuditChannel(v), true - case *Team: - return newAuditTeam(v), true - case *User: - return newAuditUser(v), true - case *Command: - return newAuditCommand(v), true - case *CommandArgs: - return newAuditCommandArgs(v), true - case *Bot: - return newAuditBot(v), true - case *ChannelModerationPatch: - return newAuditChannelModerationPatch(v), true - case *Emoji: - return newAuditEmoji(v), true - case *FileInfo: - return newAuditFileInfo(v), true - case *Group: - return newAuditGroup(v), true - case *Job: - return newAuditJob(v), true - case *OAuthApp: - return newAuditOAuthApp(v), true - case *Post: - return newAuditPost(v), true - case *Role: - return newAuditRole(v), true - case *Scheme: - return newAuditScheme(v), true - case *SchemeRoles: - return newAuditSchemeRoles(v), true - case *Session: - return newAuditSession(v), true - case *IncomingWebhook: - return newAuditIncomingWebhook(v), true - case *OutgoingWebhook: - return newAuditOutgoingWebhook(v), true - case *RemoteCluster: - return newRemoteCluster(v), true - } - return val, false -} - -type auditChannel struct { - ID string - Name string - Type string -} - -// newAuditChannel creates a simplified representation of Channel for output to audit log. -func newAuditChannel(c *Channel) auditChannel { - var channel auditChannel - if c != nil { - channel.ID = c.Id - channel.Name = c.Name - channel.Type = c.Type - } - return channel -} - -func (c auditChannel) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", c.ID) - enc.StringKey("name", c.Name) - enc.StringKey("type", c.Type) -} - -func (c auditChannel) IsNil() bool { - return false -} - -type auditTeam struct { - ID string - Name string - Type string -} - -// newAuditTeam creates a simplified representation of Team for output to audit log. -func newAuditTeam(t *Team) auditTeam { - var team auditTeam - if t != nil { - team.ID = t.Id - team.Name = t.Name - team.Type = t.Type - } - return team -} - -func (t auditTeam) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", t.ID) - enc.StringKey("name", t.Name) - enc.StringKey("type", t.Type) -} - -func (t auditTeam) IsNil() bool { - return false -} - -type auditUser struct { - ID string - Name string - Roles string -} - -// newAuditUser creates a simplified representation of User for output to audit log. -func newAuditUser(u *User) auditUser { - var user auditUser - if u != nil { - user.ID = u.Id - user.Name = u.Username - user.Roles = u.Roles - } - return user -} - -func (u auditUser) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", u.ID) - enc.StringKey("name", u.Name) - enc.StringKey("roles", u.Roles) -} - -func (u auditUser) IsNil() bool { - return false -} - -type auditCommand struct { - ID string - CreatorID string - TeamID string - Trigger string - Method string - Username string - IconURL string - AutoComplete bool - AutoCompleteDesc string - AutoCompleteHint string - DisplayName string - Description string - URL string -} - -// newAuditCommand creates a simplified representation of Command for output to audit log. -func newAuditCommand(c *Command) auditCommand { - var cmd auditCommand - if c != nil { - cmd.ID = c.Id - cmd.CreatorID = c.CreatorId - cmd.TeamID = c.TeamId - cmd.Trigger = c.Trigger - cmd.Method = c.Method - cmd.Username = c.Username - cmd.IconURL = c.IconURL - cmd.AutoComplete = c.AutoComplete - cmd.AutoCompleteDesc = c.AutoCompleteDesc - cmd.AutoCompleteHint = c.AutoCompleteHint - cmd.DisplayName = c.DisplayName - cmd.Description = c.Description - cmd.URL = c.URL - } - return cmd -} - -func (cmd auditCommand) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", cmd.ID) - enc.StringKey("creator_id", cmd.CreatorID) - enc.StringKey("team_id", cmd.TeamID) - enc.StringKey("trigger", cmd.Trigger) - enc.StringKey("method", cmd.Method) - enc.StringKey("username", cmd.Username) - enc.StringKey("icon_url", cmd.IconURL) - enc.BoolKey("auto_complete", cmd.AutoComplete) - enc.StringKey("auto_complete_desc", cmd.AutoCompleteDesc) - enc.StringKey("auto_complete_hint", cmd.AutoCompleteHint) - enc.StringKey("display", cmd.DisplayName) - enc.StringKey("desc", cmd.Description) - enc.StringKey("url", cmd.URL) -} - -func (cmd auditCommand) IsNil() bool { - return false -} - -type auditCommandArgs struct { - ChannelID string - TeamID string - TriggerID string - Command string -} - -// newAuditCommandArgs creates a simplified representation of CommandArgs for output to audit log. -func newAuditCommandArgs(ca *CommandArgs) auditCommandArgs { - var cmdargs auditCommandArgs - if ca != nil { - cmdargs.ChannelID = ca.ChannelId - cmdargs.TeamID = ca.TeamId - cmdargs.TriggerID = ca.TriggerId - cmdargs.Command = ca.Command - } - return cmdargs -} - -func (ca auditCommandArgs) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("channel_id", ca.ChannelID) - enc.StringKey("team_id", ca.TriggerID) - enc.StringKey("trigger_id", ca.TeamID) - enc.StringKey("command", ca.Command) -} - -func (ca auditCommandArgs) IsNil() bool { - return false -} - -type auditBot struct { - UserID string - Username string - Displayname string -} - -// newAuditBot creates a simplified representation of Bot for output to audit log. -func newAuditBot(b *Bot) auditBot { - var bot auditBot - if b != nil { - bot.UserID = b.UserId - bot.Username = b.Username - bot.Displayname = b.DisplayName - } - return bot -} - -func (b auditBot) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("user_id", b.UserID) - enc.StringKey("username", b.Username) - enc.StringKey("display", b.Displayname) -} - -func (b auditBot) IsNil() bool { - return false -} - -type auditChannelModerationPatch struct { - Name string - RoleGuests bool - RoleMembers bool -} - -// newAuditChannelModerationPatch creates a simplified representation of ChannelModerationPatch for output to audit log. -func newAuditChannelModerationPatch(p *ChannelModerationPatch) auditChannelModerationPatch { - var patch auditChannelModerationPatch - if p != nil { - if p.Name != nil { - patch.Name = *p.Name - } - if p.Roles.Guests != nil { - patch.RoleGuests = *p.Roles.Guests - } - if p.Roles.Members != nil { - patch.RoleMembers = *p.Roles.Members - } - } - return patch -} - -func (p auditChannelModerationPatch) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("name", p.Name) - enc.BoolKey("role_guests", p.RoleGuests) - enc.BoolKey("role_members", p.RoleMembers) -} - -func (p auditChannelModerationPatch) IsNil() bool { - return false -} - -type auditEmoji struct { - ID string - Name string -} - -// newAuditEmoji creates a simplified representation of Emoji for output to audit log. -func newAuditEmoji(e *Emoji) auditEmoji { - var emoji auditEmoji - if e != nil { - emoji.ID = e.Id - emoji.Name = e.Name - } - return emoji -} - -func (e auditEmoji) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", e.ID) - enc.StringKey("name", e.Name) -} - -func (e auditEmoji) IsNil() bool { - return false -} - -type auditFileInfo struct { - ID string - PostID string - Path string - Name string - Extension string - Size int64 -} - -// newAuditFileInfo creates a simplified representation of FileInfo for output to audit log. -func newAuditFileInfo(f *FileInfo) auditFileInfo { - var fi auditFileInfo - if f != nil { - fi.ID = f.Id - fi.PostID = f.PostId - fi.Path = f.Path - fi.Name = f.Name - fi.Extension = f.Extension - fi.Size = f.Size - } - return fi -} - -func (fi auditFileInfo) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", fi.ID) - enc.StringKey("post_id", fi.PostID) - enc.StringKey("path", fi.Path) - enc.StringKey("name", fi.Name) - enc.StringKey("ext", fi.Extension) - enc.Int64Key("size", fi.Size) -} - -func (fi auditFileInfo) IsNil() bool { - return false -} - -type auditGroup struct { - ID string - Name string - DisplayName string - Description string -} - -// newAuditGroup creates a simplified representation of Group for output to audit log. -func newAuditGroup(g *Group) auditGroup { - var group auditGroup - if g != nil { - group.ID = g.Id - if g.Name == nil { - group.Name = "" - } else { - group.Name = *g.Name - } - group.DisplayName = g.DisplayName - group.Description = g.Description - } - return group -} - -func (g auditGroup) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", g.ID) - enc.StringKey("name", g.Name) - enc.StringKey("display", g.DisplayName) - enc.StringKey("desc", g.Description) -} - -func (g auditGroup) IsNil() bool { - return false -} - -type auditJob struct { - ID string - Type string - Priority int64 - StartAt int64 -} - -// newAuditJob creates a simplified representation of Job for output to audit log. -func newAuditJob(j *Job) auditJob { - var job auditJob - if j != nil { - job.ID = j.Id - job.Type = j.Type - job.Priority = j.Priority - job.StartAt = j.StartAt - } - return job -} - -func (j auditJob) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", j.ID) - enc.StringKey("type", j.Type) - enc.Int64Key("priority", j.Priority) - enc.Int64Key("start_at", j.StartAt) -} - -func (j auditJob) IsNil() bool { - return false -} - -type auditOAuthApp struct { - ID string - CreatorID string - Name string - Description string - IsTrusted bool -} - -// newAuditOAuthApp creates a simplified representation of OAuthApp for output to audit log. -func newAuditOAuthApp(o *OAuthApp) auditOAuthApp { - var oauth auditOAuthApp - if o != nil { - oauth.ID = o.Id - oauth.CreatorID = o.CreatorId - oauth.Name = o.Name - oauth.Description = o.Description - oauth.IsTrusted = o.IsTrusted - } - return oauth -} - -func (o auditOAuthApp) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", o.ID) - enc.StringKey("creator_id", o.CreatorID) - enc.StringKey("name", o.Name) - enc.StringKey("desc", o.Description) - enc.BoolKey("trusted", o.IsTrusted) -} - -func (o auditOAuthApp) IsNil() bool { - return false -} - -type auditPost struct { - ID string - ChannelID string - Type string - IsPinned bool -} - -// newAuditPost creates a simplified representation of Post for output to audit log. -func newAuditPost(p *Post) auditPost { - var post auditPost - if p != nil { - post.ID = p.Id - post.ChannelID = p.ChannelId - post.Type = p.Type - post.IsPinned = p.IsPinned - } - return post -} - -func (p auditPost) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", p.ID) - enc.StringKey("channel_id", p.ChannelID) - enc.StringKey("type", p.Type) - enc.BoolKey("pinned", p.IsPinned) -} - -func (p auditPost) IsNil() bool { - return false -} - -type auditRole struct { - ID string - Name string - DisplayName string - Permissions []string - SchemeManaged bool - BuiltIn bool -} - -// newAuditRole creates a simplified representation of Role for output to audit log. -func newAuditRole(r *Role) auditRole { - var role auditRole - if r != nil { - role.ID = r.Id - role.Name = r.Name - role.DisplayName = r.DisplayName - role.Permissions = append(role.Permissions, r.Permissions...) - role.SchemeManaged = r.SchemeManaged - role.BuiltIn = r.BuiltIn - } - return role -} - -func (r auditRole) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", r.ID) - enc.StringKey("name", r.Name) - enc.StringKey("display", r.DisplayName) - enc.SliceStringKey("perms", r.Permissions) - enc.BoolKey("schemeManaged", r.SchemeManaged) - enc.BoolKey("builtin", r.BuiltIn) -} - -func (r auditRole) IsNil() bool { - return false -} - -type auditScheme struct { - ID string - Name string - DisplayName string - Scope string -} - -// newAuditScheme creates a simplified representation of Scheme for output to audit log. -func newAuditScheme(s *Scheme) auditScheme { - var scheme auditScheme - if s != nil { - scheme.ID = s.Id - scheme.Name = s.Name - scheme.DisplayName = s.DisplayName - scheme.Scope = s.Scope - } - return scheme -} - -func (s auditScheme) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", s.ID) - enc.StringKey("name", s.Name) - enc.StringKey("display", s.DisplayName) - enc.StringKey("scope", s.Scope) -} - -func (s auditScheme) IsNil() bool { - return false -} - -type auditSchemeRoles struct { - SchemeAdmin bool - SchemeUser bool - SchemeGuest bool -} - -// newAuditSchemeRoles creates a simplified representation of SchemeRoles for output to audit log. -func newAuditSchemeRoles(s *SchemeRoles) auditSchemeRoles { - var roles auditSchemeRoles - if s != nil { - roles.SchemeAdmin = s.SchemeAdmin - roles.SchemeUser = s.SchemeUser - roles.SchemeGuest = s.SchemeGuest - } - return roles -} - -func (s auditSchemeRoles) MarshalJSONObject(enc *gojay.Encoder) { - enc.BoolKey("admin", s.SchemeAdmin) - enc.BoolKey("user", s.SchemeUser) - enc.BoolKey("guest", s.SchemeGuest) -} - -func (s auditSchemeRoles) IsNil() bool { - return false -} - -type auditSession struct { - ID string - UserId string - DeviceId string -} - -// newAuditSession creates a simplified representation of Session for output to audit log. -func newAuditSession(s *Session) auditSession { - var session auditSession - if s != nil { - session.ID = s.Id - session.UserId = s.UserId - session.DeviceId = s.DeviceId - } - return session -} - -func (s auditSession) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", s.ID) - enc.StringKey("user_id", s.UserId) - enc.StringKey("device_id", s.DeviceId) -} - -func (s auditSession) IsNil() bool { - return false -} - -type auditIncomingWebhook struct { - ID string - ChannelID string - TeamId string - DisplayName string - Description string -} - -// newAuditIncomingWebhook creates a simplified representation of IncomingWebhook for output to audit log. -func newAuditIncomingWebhook(h *IncomingWebhook) auditIncomingWebhook { - var hook auditIncomingWebhook - if h != nil { - hook.ID = h.Id - hook.ChannelID = h.ChannelId - hook.TeamId = h.TeamId - hook.DisplayName = h.DisplayName - hook.Description = h.Description - } - return hook -} - -func (h auditIncomingWebhook) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", h.ID) - enc.StringKey("channel_id", h.ChannelID) - enc.StringKey("team_id", h.TeamId) - enc.StringKey("display", h.DisplayName) - enc.StringKey("desc", h.Description) -} - -func (h auditIncomingWebhook) IsNil() bool { - return false -} - -type auditOutgoingWebhook struct { - ID string - ChannelID string - TeamID string - TriggerWords StringArray - TriggerWhen int - DisplayName string - Description string - ContentType string - Username string -} - -// newAuditOutgoingWebhook creates a simplified representation of OutgoingWebhook for output to audit log. -func newAuditOutgoingWebhook(h *OutgoingWebhook) auditOutgoingWebhook { - var hook auditOutgoingWebhook - if h != nil { - hook.ID = h.Id - hook.ChannelID = h.ChannelId - hook.TeamID = h.TeamId - hook.TriggerWords = h.TriggerWords - hook.TriggerWhen = h.TriggerWhen - hook.DisplayName = h.DisplayName - hook.Description = h.Description - hook.ContentType = h.ContentType - hook.Username = h.Username - } - return hook -} - -func (h auditOutgoingWebhook) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("id", h.ID) - enc.StringKey("channel_id", h.ChannelID) - enc.StringKey("team_id", h.TeamID) - enc.SliceStringKey("trigger_words", h.TriggerWords) - enc.IntKey("trigger_when", h.TriggerWhen) - enc.StringKey("display", h.DisplayName) - enc.StringKey("desc", h.Description) - enc.StringKey("content_type", h.ContentType) - enc.StringKey("username", h.Username) -} - -func (h auditOutgoingWebhook) IsNil() bool { - return false -} - -type auditRemoteCluster struct { - RemoteId string - RemoteTeamId string - Name string - DisplayName string - SiteURL string - CreateAt int64 - LastPingAt int64 - CreatorId string -} - -// newRemoteCluster creates a simplified representation of RemoteCluster for output to audit log. -func newRemoteCluster(r *RemoteCluster) auditRemoteCluster { - var rc auditRemoteCluster - if r != nil { - rc.RemoteId = r.RemoteId - rc.RemoteTeamId = r.RemoteTeamId - rc.Name = r.Name - rc.DisplayName = r.DisplayName - rc.SiteURL = r.SiteURL - rc.CreateAt = r.CreateAt - rc.LastPingAt = r.LastPingAt - rc.CreatorId = r.CreatorId - } - return rc -} - -func (r auditRemoteCluster) MarshalJSONObject(enc *gojay.Encoder) { - enc.StringKey("remote_id", r.RemoteId) - enc.StringKey("remote_team_id", r.RemoteTeamId) - enc.StringKey("name", r.Name) - enc.StringKey("display_name", r.DisplayName) - enc.StringKey("site_url", r.SiteURL) - enc.Int64Key("create_at", r.CreateAt) - enc.Int64Key("last_ping_at", r.LastPingAt) - enc.StringKey("creator_id", r.CreatorId) -} - -func (r auditRemoteCluster) IsNil() bool { - return false -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/audits.go b/vendor/github.com/mattermost/mattermost-server/v5/model/audits.go deleted file mode 100644 index 54e361f9..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/audits.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type Audits []Audit - -func (o Audits) Etag() string { - if len(o) > 0 { - // the first in the list is always the most current - return Etag(o[0].CreateAt) - } - return "" -} - -func (o Audits) ToJson() string { - b, err := json.Marshal(o) - if err != nil { - return "[]" - } - return string(b) -} - -func AuditsFromJson(data io.Reader) Audits { - var o Audits - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/authorize.go b/vendor/github.com/mattermost/mattermost-server/v5/model/authorize.go deleted file mode 100644 index f2a8e8dc..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/authorize.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" -) - -const ( - AUTHCODE_EXPIRE_TIME = 60 * 10 // 10 minutes - AUTHCODE_RESPONSE_TYPE = "code" - IMPLICIT_RESPONSE_TYPE = "token" - DEFAULT_SCOPE = "user" -) - -type AuthData struct { - ClientId string `json:"client_id"` - UserId string `json:"user_id"` - Code string `json:"code"` - ExpiresIn int32 `json:"expires_in"` - CreateAt int64 `json:"create_at"` - RedirectUri string `json:"redirect_uri"` - State string `json:"state"` - Scope string `json:"scope"` -} - -type AuthorizeRequest struct { - ResponseType string `json:"response_type"` - ClientId string `json:"client_id"` - RedirectUri string `json:"redirect_uri"` - Scope string `json:"scope"` - State string `json:"state"` -} - -// IsValid validates the AuthData and returns an error if it isn't configured -// correctly. -func (ad *AuthData) IsValid() *AppError { - - if !IsValidId(ad.ClientId) { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.client_id.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidId(ad.UserId) { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) - } - - if ad.Code == "" || len(ad.Code) > 128 { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.auth_code.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest) - } - - if ad.ExpiresIn == 0 { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.expires.app_error", nil, "", http.StatusBadRequest) - } - - if ad.CreateAt <= 0 { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.create_at.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest) - } - - if len(ad.RedirectUri) > 256 || !IsValidHttpUrl(ad.RedirectUri) { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.redirect_uri.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest) - } - - if len(ad.State) > 1024 { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.state.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest) - } - - if len(ad.Scope) > 128 { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.scope.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest) - } - - return nil -} - -// IsValid validates the AuthorizeRequest and returns an error if it isn't configured -// correctly. -func (ar *AuthorizeRequest) IsValid() *AppError { - - if !IsValidId(ar.ClientId) { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.client_id.app_error", nil, "", http.StatusBadRequest) - } - - if ar.ResponseType == "" { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.response_type.app_error", nil, "", http.StatusBadRequest) - } - - if ar.RedirectUri == "" || len(ar.RedirectUri) > 256 || !IsValidHttpUrl(ar.RedirectUri) { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.redirect_uri.app_error", nil, "client_id="+ar.ClientId, http.StatusBadRequest) - } - - if len(ar.State) > 1024 { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.state.app_error", nil, "client_id="+ar.ClientId, http.StatusBadRequest) - } - - if len(ar.Scope) > 128 { - return NewAppError("AuthData.IsValid", "model.authorize.is_valid.scope.app_error", nil, "client_id="+ar.ClientId, http.StatusBadRequest) - } - - return nil -} - -func (ad *AuthData) PreSave() { - if ad.ExpiresIn == 0 { - ad.ExpiresIn = AUTHCODE_EXPIRE_TIME - } - - if ad.CreateAt == 0 { - ad.CreateAt = GetMillis() - } - - if ad.Scope == "" { - ad.Scope = DEFAULT_SCOPE - } -} - -func (ad *AuthData) ToJson() string { - b, _ := json.Marshal(ad) - return string(b) -} - -func AuthDataFromJson(data io.Reader) *AuthData { - var ad *AuthData - json.NewDecoder(data).Decode(&ad) - return ad -} - -func (ar *AuthorizeRequest) ToJson() string { - b, _ := json.Marshal(ar) - return string(b) -} - -func AuthorizeRequestFromJson(data io.Reader) *AuthorizeRequest { - var ar *AuthorizeRequest - json.NewDecoder(data).Decode(&ar) - return ar -} - -func (ad *AuthData) IsExpired() bool { - return GetMillis() > ad.CreateAt+int64(ad.ExpiresIn*1000) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/bot.go b/vendor/github.com/mattermost/mattermost-server/v5/model/bot.go deleted file mode 100644 index e58fc0be..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/bot.go +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "strings" - "unicode/utf8" -) - -const ( - BOT_DISPLAY_NAME_MAX_RUNES = USER_FIRST_NAME_MAX_RUNES - BOT_DESCRIPTION_MAX_RUNES = 1024 - BOT_CREATOR_ID_MAX_RUNES = KEY_VALUE_PLUGIN_ID_MAX_RUNES // UserId or PluginId - BOT_WARN_METRIC_BOT_USERNAME = "mattermost-advisor" - BOT_SYSTEM_BOT_USERNAME = "system-bot" -) - -// Bot is a special type of User meant for programmatic interactions. -// Note that the primary key of a bot is the UserId, and matches the primary key of the -// corresponding user. -type Bot struct { - UserId string `json:"user_id"` - Username string `json:"username"` - DisplayName string `json:"display_name,omitempty"` - Description string `json:"description,omitempty"` - OwnerId string `json:"owner_id"` - LastIconUpdate int64 `json:"last_icon_update,omitempty"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` -} - -// BotPatch is a description of what fields to update on an existing bot. -type BotPatch struct { - Username *string `json:"username"` - DisplayName *string `json:"display_name"` - Description *string `json:"description"` -} - -// BotGetOptions acts as a filter on bulk bot fetching queries. -type BotGetOptions struct { - OwnerId string - IncludeDeleted bool - OnlyOrphaned bool - Page int - PerPage int -} - -// BotList is a list of bots. -type BotList []*Bot - -// Trace describes the minimum information required to identify a bot for the purpose of logging. -func (b *Bot) Trace() map[string]interface{} { - return map[string]interface{}{"user_id": b.UserId} -} - -// Clone returns a shallow copy of the bot. -func (b *Bot) Clone() *Bot { - copy := *b - return © -} - -// IsValid validates the bot and returns an error if it isn't configured correctly. -func (b *Bot) IsValid() *AppError { - if !IsValidId(b.UserId) { - return NewAppError("Bot.IsValid", "model.bot.is_valid.user_id.app_error", b.Trace(), "", http.StatusBadRequest) - } - - if !IsValidUsername(b.Username) { - return NewAppError("Bot.IsValid", "model.bot.is_valid.username.app_error", b.Trace(), "", http.StatusBadRequest) - } - - if utf8.RuneCountInString(b.DisplayName) > BOT_DISPLAY_NAME_MAX_RUNES { - return NewAppError("Bot.IsValid", "model.bot.is_valid.user_id.app_error", b.Trace(), "", http.StatusBadRequest) - } - - if utf8.RuneCountInString(b.Description) > BOT_DESCRIPTION_MAX_RUNES { - return NewAppError("Bot.IsValid", "model.bot.is_valid.description.app_error", b.Trace(), "", http.StatusBadRequest) - } - - if b.OwnerId == "" || utf8.RuneCountInString(b.OwnerId) > BOT_CREATOR_ID_MAX_RUNES { - return NewAppError("Bot.IsValid", "model.bot.is_valid.creator_id.app_error", b.Trace(), "", http.StatusBadRequest) - } - - if b.CreateAt == 0 { - return NewAppError("Bot.IsValid", "model.bot.is_valid.create_at.app_error", b.Trace(), "", http.StatusBadRequest) - } - - if b.UpdateAt == 0 { - return NewAppError("Bot.IsValid", "model.bot.is_valid.update_at.app_error", b.Trace(), "", http.StatusBadRequest) - } - - return nil -} - -// PreSave should be run before saving a new bot to the database. -func (b *Bot) PreSave() { - b.CreateAt = GetMillis() - b.UpdateAt = b.CreateAt - b.DeleteAt = 0 -} - -// PreUpdate should be run before saving an updated bot to the database. -func (b *Bot) PreUpdate() { - b.UpdateAt = GetMillis() -} - -// Etag generates an etag for caching. -func (b *Bot) Etag() string { - return Etag(b.UserId, b.UpdateAt) -} - -// ToJson serializes the bot to json. -func (b *Bot) ToJson() []byte { - data, _ := json.Marshal(b) - return data -} - -// BotFromJson deserializes a bot from json. -func BotFromJson(data io.Reader) *Bot { - var bot *Bot - json.NewDecoder(data).Decode(&bot) - return bot -} - -// Patch modifies an existing bot with optional fields from the given patch. -// TODO 6.0: consider returning a boolean to indicate whether or not the patch -// applied any changes. -func (b *Bot) Patch(patch *BotPatch) { - if patch.Username != nil { - b.Username = *patch.Username - } - - if patch.DisplayName != nil { - b.DisplayName = *patch.DisplayName - } - - if patch.Description != nil { - b.Description = *patch.Description - } -} - -// WouldPatch returns whether or not the given patch would be applied or not. -func (b *Bot) WouldPatch(patch *BotPatch) bool { - if patch == nil { - return false - } - if patch.Username != nil && *patch.Username != b.Username { - return true - } - if patch.DisplayName != nil && *patch.DisplayName != b.DisplayName { - return true - } - if patch.Description != nil && *patch.Description != b.Description { - return true - } - return false -} - -// ToJson serializes the bot patch to json. -func (b *BotPatch) ToJson() []byte { - data, err := json.Marshal(b) - if err != nil { - return nil - } - - return data -} - -// BotPatchFromJson deserializes a bot patch from json. -func BotPatchFromJson(data io.Reader) *BotPatch { - decoder := json.NewDecoder(data) - var botPatch BotPatch - err := decoder.Decode(&botPatch) - if err != nil { - return nil - } - - return &botPatch -} - -// UserFromBot returns a user model describing the bot fields stored in the User store. -func UserFromBot(b *Bot) *User { - return &User{ - Id: b.UserId, - Username: b.Username, - Email: NormalizeEmail(fmt.Sprintf("%s@localhost", b.Username)), - FirstName: b.DisplayName, - Roles: SYSTEM_USER_ROLE_ID, - } -} - -// BotFromUser returns a bot model given a user model -func BotFromUser(u *User) *Bot { - return &Bot{ - OwnerId: u.Id, - UserId: u.Id, - Username: u.Username, - DisplayName: u.GetDisplayName(SHOW_USERNAME), - } -} - -// BotListFromJson deserializes a list of bots from json. -func BotListFromJson(data io.Reader) BotList { - var bots BotList - json.NewDecoder(data).Decode(&bots) - return bots -} - -// ToJson serializes a list of bots to json. -func (l *BotList) ToJson() []byte { - b, _ := json.Marshal(l) - return b -} - -// Etag computes the etag for a list of bots. -func (l *BotList) Etag() string { - id := "0" - var t int64 = 0 - var delta int64 = 0 - - for _, v := range *l { - if v.UpdateAt > t { - t = v.UpdateAt - id = v.UserId - } - - } - - return Etag(id, t, delta, len(*l)) -} - -// MakeBotNotFoundError creates the error returned when a bot does not exist, or when the user isn't allowed to query the bot. -// The errors must the same in both cases to avoid leaking that a user is a bot. -func MakeBotNotFoundError(userId string) *AppError { - return NewAppError("SqlBotStore.Get", "store.sql_bot.get.missing.app_error", map[string]interface{}{"user_id": userId}, "", http.StatusNotFound) -} - -func IsBotDMChannel(channel *Channel, botUserID string) bool { - if channel.Type != CHANNEL_DIRECT { - return false - } - - if !strings.HasPrefix(channel.Name, botUserID+"__") && !strings.HasSuffix(channel.Name, "__"+botUserID) { - return false - } - - return true -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/builtin.go b/vendor/github.com/mattermost/mattermost-server/v5/model/builtin.go deleted file mode 100644 index 38e01f8b..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/builtin.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -func NewBool(b bool) *bool { return &b } -func NewInt(n int) *int { return &n } -func NewInt64(n int64) *int64 { return &n } -func NewString(s string) *string { return &s } diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/bundle_info.go b/vendor/github.com/mattermost/mattermost-server/v5/model/bundle_info.go deleted file mode 100644 index e4cfe125..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/bundle_info.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "github.com/mattermost/mattermost-server/v5/shared/mlog" -) - -type BundleInfo struct { - Path string - - Manifest *Manifest - ManifestPath string - ManifestError error -} - -func (b *BundleInfo) WrapLogger(logger *mlog.Logger) *mlog.Logger { - if b.Manifest != nil { - return logger.With(mlog.String("plugin_id", b.Manifest.Id)) - } - return logger.With(mlog.String("plugin_path", b.Path)) -} - -// Returns bundle info for the given path. The return value is never nil. -func BundleInfoForPath(path string) *BundleInfo { - m, mpath, err := FindManifest(path) - return &BundleInfo{ - Path: path, - Manifest: m, - ManifestPath: mpath, - ManifestError: err, - } -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel.go deleted file mode 100644 index 8dc3fa8d..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel.go +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "crypto/sha1" - "encoding/hex" - "encoding/json" - "io" - "net/http" - "sort" - "strings" - "unicode/utf8" -) - -const ( - CHANNEL_OPEN = "O" - CHANNEL_PRIVATE = "P" - CHANNEL_DIRECT = "D" - CHANNEL_GROUP = "G" - CHANNEL_GROUP_MAX_USERS = 8 - CHANNEL_GROUP_MIN_USERS = 3 - DEFAULT_CHANNEL = "town-square" - CHANNEL_DISPLAY_NAME_MAX_RUNES = 64 - CHANNEL_NAME_MIN_LENGTH = 2 - CHANNEL_NAME_MAX_LENGTH = 64 - CHANNEL_HEADER_MAX_RUNES = 1024 - CHANNEL_PURPOSE_MAX_RUNES = 250 - CHANNEL_CACHE_SIZE = 25000 - - CHANNEL_SORT_BY_USERNAME = "username" - CHANNEL_SORT_BY_STATUS = "status" -) - -type Channel struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - TeamId string `json:"team_id"` - Type string `json:"type"` - DisplayName string `json:"display_name"` - Name string `json:"name"` - Header string `json:"header"` - Purpose string `json:"purpose"` - LastPostAt int64 `json:"last_post_at"` - TotalMsgCount int64 `json:"total_msg_count"` - ExtraUpdateAt int64 `json:"extra_update_at"` - CreatorId string `json:"creator_id"` - SchemeId *string `json:"scheme_id"` - Props map[string]interface{} `json:"props" db:"-"` - GroupConstrained *bool `json:"group_constrained"` - Shared *bool `json:"shared"` - TotalMsgCountRoot int64 `json:"total_msg_count_root"` - PolicyID *string `json:"policy_id" db:"-"` -} - -type ChannelWithTeamData struct { - Channel - TeamDisplayName string `json:"team_display_name"` - TeamName string `json:"team_name"` - TeamUpdateAt int64 `json:"team_update_at"` -} - -type ChannelsWithCount struct { - Channels *ChannelListWithTeamData `json:"channels"` - TotalCount int64 `json:"total_count"` -} - -type ChannelPatch struct { - DisplayName *string `json:"display_name"` - Name *string `json:"name"` - Header *string `json:"header"` - Purpose *string `json:"purpose"` - GroupConstrained *bool `json:"group_constrained"` -} - -type ChannelForExport struct { - Channel - TeamName string - SchemeName *string -} - -type DirectChannelForExport struct { - Channel - Members *[]string -} - -type ChannelModeration struct { - Name string `json:"name"` - Roles *ChannelModeratedRoles `json:"roles"` -} - -type ChannelModeratedRoles struct { - Guests *ChannelModeratedRole `json:"guests"` - Members *ChannelModeratedRole `json:"members"` -} - -type ChannelModeratedRole struct { - Value bool `json:"value"` - Enabled bool `json:"enabled"` -} - -type ChannelModerationPatch struct { - Name *string `json:"name"` - Roles *ChannelModeratedRolesPatch `json:"roles"` -} - -type ChannelModeratedRolesPatch struct { - Guests *bool `json:"guests"` - Members *bool `json:"members"` -} - -// ChannelSearchOpts contains options for searching channels. -// -// NotAssociatedToGroup will exclude channels that have associated, active GroupChannels records. -// ExcludeDefaultChannels will exclude the configured default channels (ex 'town-square' and 'off-topic'). -// IncludeDeleted will include channel records where DeleteAt != 0. -// ExcludeChannelNames will exclude channels from the results by name. -// Paginate whether to paginate the results. -// Page page requested, if results are paginated. -// PerPage number of results per page, if paginated. -// -type ChannelSearchOpts struct { - NotAssociatedToGroup string - ExcludeDefaultChannels bool - IncludeDeleted bool - Deleted bool - ExcludeChannelNames []string - TeamIds []string - GroupConstrained bool - ExcludeGroupConstrained bool - PolicyID string - ExcludePolicyConstrained bool - IncludePolicyID bool - Public bool - Private bool - Page *int - PerPage *int -} - -type ChannelMemberCountByGroup struct { - GroupId string `db:"-" json:"group_id"` - ChannelMemberCount int64 `db:"-" json:"channel_member_count"` - ChannelMemberTimezonesCount int64 `db:"-" json:"channel_member_timezones_count"` -} - -type ChannelOption func(channel *Channel) - -func WithID(ID string) ChannelOption { - return func(channel *Channel) { - channel.Id = ID - } -} - -func (o *Channel) DeepCopy() *Channel { - copy := *o - if copy.SchemeId != nil { - copy.SchemeId = NewString(*o.SchemeId) - } - return © -} - -func (o *Channel) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func (o *ChannelPatch) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func (o *ChannelsWithCount) ToJson() []byte { - b, _ := json.Marshal(o) - return b -} - -func ChannelsWithCountFromJson(data io.Reader) *ChannelsWithCount { - var o *ChannelsWithCount - json.NewDecoder(data).Decode(&o) - return o -} - -func ChannelFromJson(data io.Reader) *Channel { - var o *Channel - json.NewDecoder(data).Decode(&o) - return o -} - -func ChannelPatchFromJson(data io.Reader) *ChannelPatch { - var o *ChannelPatch - json.NewDecoder(data).Decode(&o) - return o -} - -func ChannelModerationsFromJson(data io.Reader) []*ChannelModeration { - var o []*ChannelModeration - json.NewDecoder(data).Decode(&o) - return o -} - -func ChannelModerationsPatchFromJson(data io.Reader) []*ChannelModerationPatch { - var o []*ChannelModerationPatch - json.NewDecoder(data).Decode(&o) - return o -} - -func ChannelMemberCountsByGroupFromJson(data io.Reader) []*ChannelMemberCountByGroup { - var o []*ChannelMemberCountByGroup - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *Channel) Etag() string { - return Etag(o.Id, o.UpdateAt) -} - -func (o *Channel) IsValid() *AppError { - if !IsValidId(o.Id) { - return NewAppError("Channel.IsValid", "model.channel.is_valid.id.app_error", nil, "", http.StatusBadRequest) - } - - if o.CreateAt == 0 { - return NewAppError("Channel.IsValid", "model.channel.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if o.UpdateAt == 0 { - return NewAppError("Channel.IsValid", "model.channel.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if utf8.RuneCountInString(o.DisplayName) > CHANNEL_DISPLAY_NAME_MAX_RUNES { - return NewAppError("Channel.IsValid", "model.channel.is_valid.display_name.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if !IsValidChannelIdentifier(o.Name) { - return NewAppError("Channel.IsValid", "model.channel.is_valid.2_or_more.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if !(o.Type == CHANNEL_OPEN || o.Type == CHANNEL_PRIVATE || o.Type == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP) { - return NewAppError("Channel.IsValid", "model.channel.is_valid.type.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if utf8.RuneCountInString(o.Header) > CHANNEL_HEADER_MAX_RUNES { - return NewAppError("Channel.IsValid", "model.channel.is_valid.header.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if utf8.RuneCountInString(o.Purpose) > CHANNEL_PURPOSE_MAX_RUNES { - return NewAppError("Channel.IsValid", "model.channel.is_valid.purpose.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if len(o.CreatorId) > 26 { - return NewAppError("Channel.IsValid", "model.channel.is_valid.creator_id.app_error", nil, "", http.StatusBadRequest) - } - - userIds := strings.Split(o.Name, "__") - if o.Type != CHANNEL_DIRECT && len(userIds) == 2 && IsValidId(userIds[0]) && IsValidId(userIds[1]) { - return NewAppError("Channel.IsValid", "model.channel.is_valid.name.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (o *Channel) PreSave() { - if o.Id == "" { - o.Id = NewId() - } - - o.Name = SanitizeUnicode(o.Name) - o.DisplayName = SanitizeUnicode(o.DisplayName) - - o.CreateAt = GetMillis() - o.UpdateAt = o.CreateAt - o.ExtraUpdateAt = 0 -} - -func (o *Channel) PreUpdate() { - o.UpdateAt = GetMillis() - o.Name = SanitizeUnicode(o.Name) - o.DisplayName = SanitizeUnicode(o.DisplayName) -} - -func (o *Channel) IsGroupOrDirect() bool { - return o.Type == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP -} - -func (o *Channel) IsOpen() bool { - return o.Type == CHANNEL_OPEN -} - -func (o *Channel) Patch(patch *ChannelPatch) { - if patch.DisplayName != nil { - o.DisplayName = *patch.DisplayName - } - - if patch.Name != nil { - o.Name = *patch.Name - } - - if patch.Header != nil { - o.Header = *patch.Header - } - - if patch.Purpose != nil { - o.Purpose = *patch.Purpose - } - - if patch.GroupConstrained != nil { - o.GroupConstrained = patch.GroupConstrained - } -} - -func (o *Channel) MakeNonNil() { - if o.Props == nil { - o.Props = make(map[string]interface{}) - } -} - -func (o *Channel) AddProp(key string, value interface{}) { - o.MakeNonNil() - - o.Props[key] = value -} - -func (o *Channel) IsGroupConstrained() bool { - return o.GroupConstrained != nil && *o.GroupConstrained -} - -func (o *Channel) IsShared() bool { - return o.Shared != nil && *o.Shared -} - -func (o *Channel) GetOtherUserIdForDM(userId string) string { - if o.Type != CHANNEL_DIRECT { - return "" - } - - userIds := strings.Split(o.Name, "__") - - var otherUserId string - - if userIds[0] != userIds[1] { - if userIds[0] == userId { - otherUserId = userIds[1] - } else { - otherUserId = userIds[0] - } - } - - return otherUserId -} - -func GetDMNameFromIds(userId1, userId2 string) string { - if userId1 > userId2 { - return userId2 + "__" + userId1 - } - return userId1 + "__" + userId2 -} - -func GetGroupDisplayNameFromUsers(users []*User, truncate bool) string { - usernames := make([]string, len(users)) - for index, user := range users { - usernames[index] = user.Username - } - - sort.Strings(usernames) - - name := strings.Join(usernames, ", ") - - if truncate && len(name) > CHANNEL_NAME_MAX_LENGTH { - name = name[:CHANNEL_NAME_MAX_LENGTH] - } - - return name -} - -func GetGroupNameFromUserIds(userIds []string) string { - sort.Strings(userIds) - - h := sha1.New() - for _, id := range userIds { - io.WriteString(h, id) - } - - return hex.EncodeToString(h.Sum(nil)) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_count.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_count.go deleted file mode 100644 index 6230ab3d..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_count.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "crypto/md5" - "encoding/json" - "fmt" - "io" - "sort" - "strconv" -) - -type ChannelCounts struct { - Counts map[string]int64 `json:"counts"` - CountsRoot map[string]int64 `json:"counts_root"` - UpdateTimes map[string]int64 `json:"update_times"` -} - -func (o *ChannelCounts) Etag() string { - // we don't include CountsRoot in ETag calculation, since it's a deriviative - ids := []string{} - for id := range o.Counts { - ids = append(ids, id) - } - sort.Strings(ids) - - str := "" - for _, id := range ids { - str += id + strconv.FormatInt(o.Counts[id], 10) - } - - md5Counts := fmt.Sprintf("%x", md5.Sum([]byte(str))) - - var update int64 = 0 - for _, u := range o.UpdateTimes { - if u > update { - update = u - } - } - - return Etag(md5Counts, update) -} - -func (o *ChannelCounts) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func ChannelCountsFromJson(data io.Reader) *ChannelCounts { - var o *ChannelCounts - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_data.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_data.go deleted file mode 100644 index 0a1e0d57..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_data.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type ChannelData struct { - Channel *Channel `json:"channel"` - Member *ChannelMember `json:"member"` -} - -func (o *ChannelData) Etag() string { - var mt int64 = 0 - if o.Member != nil { - mt = o.Member.LastUpdateAt - } - - return Etag(o.Channel.Id, o.Channel.UpdateAt, o.Channel.LastPostAt, mt) -} - -func (o *ChannelData) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func ChannelDataFromJson(data io.Reader) *ChannelData { - var o *ChannelData - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_list.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_list.go deleted file mode 100644 index 4ba9e5c3..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_list.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type ChannelList []*Channel - -func (o *ChannelList) ToJson() string { - b, err := json.Marshal(o) - if err != nil { - return "[]" - } - return string(b) -} - -func (o *ChannelList) Etag() string { - - id := "0" - var t int64 = 0 - var delta int64 = 0 - - for _, v := range *o { - if v.LastPostAt > t { - t = v.LastPostAt - id = v.Id - } - - if v.UpdateAt > t { - t = v.UpdateAt - id = v.Id - } - - } - - return Etag(id, t, delta, len(*o)) -} - -func ChannelListFromJson(data io.Reader) *ChannelList { - var o *ChannelList - json.NewDecoder(data).Decode(&o) - return o -} - -func ChannelSliceFromJson(data io.Reader) []*Channel { - var o []*Channel - json.NewDecoder(data).Decode(&o) - return o -} - -type ChannelListWithTeamData []*ChannelWithTeamData - -func (o *ChannelListWithTeamData) ToJson() string { - b, err := json.Marshal(o) - if err != nil { - return "[]" - } - return string(b) -} - -func (o *ChannelListWithTeamData) Etag() string { - - id := "0" - var t int64 = 0 - var delta int64 = 0 - - for _, v := range *o { - if v.LastPostAt > t { - t = v.LastPostAt - id = v.Id - } - - if v.UpdateAt > t { - t = v.UpdateAt - id = v.Id - } - - if v.TeamUpdateAt > t { - t = v.TeamUpdateAt - id = v.Id - } - } - - return Etag(id, t, delta, len(*o)) -} - -func ChannelListWithTeamDataFromJson(data io.Reader) *ChannelListWithTeamData { - var o *ChannelListWithTeamData - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member.go deleted file mode 100644 index bc02881e..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member.go +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" - "strings" -) - -const ( - CHANNEL_NOTIFY_DEFAULT = "default" - CHANNEL_NOTIFY_ALL = "all" - CHANNEL_NOTIFY_MENTION = "mention" - CHANNEL_NOTIFY_NONE = "none" - CHANNEL_MARK_UNREAD_ALL = "all" - CHANNEL_MARK_UNREAD_MENTION = "mention" - IGNORE_CHANNEL_MENTIONS_DEFAULT = "default" - IGNORE_CHANNEL_MENTIONS_OFF = "off" - IGNORE_CHANNEL_MENTIONS_ON = "on" - IGNORE_CHANNEL_MENTIONS_NOTIFY_PROP = "ignore_channel_mentions" -) - -type ChannelUnread struct { - TeamId string `json:"team_id"` - ChannelId string `json:"channel_id"` - MsgCount int64 `json:"msg_count"` - MentionCount int64 `json:"mention_count"` - MentionCountRoot int64 `json:"mention_count_root"` - MsgCountRoot int64 `json:"msg_count_root"` - NotifyProps StringMap `json:"-"` -} - -type ChannelUnreadAt struct { - TeamId string `json:"team_id"` - UserId string `json:"user_id"` - ChannelId string `json:"channel_id"` - MsgCount int64 `json:"msg_count"` - MentionCount int64 `json:"mention_count"` - MentionCountRoot int64 `json:"mention_count_root"` - MsgCountRoot int64 `json:"msg_count_root"` - LastViewedAt int64 `json:"last_viewed_at"` - NotifyProps StringMap `json:"-"` -} - -type ChannelMember struct { - ChannelId string `json:"channel_id"` - UserId string `json:"user_id"` - Roles string `json:"roles"` - LastViewedAt int64 `json:"last_viewed_at"` - MsgCount int64 `json:"msg_count"` - MentionCount int64 `json:"mention_count"` - MentionCountRoot int64 `json:"mention_count_root"` - MsgCountRoot int64 `json:"msg_count_root"` - NotifyProps StringMap `json:"notify_props"` - LastUpdateAt int64 `json:"last_update_at"` - SchemeGuest bool `json:"scheme_guest"` - SchemeUser bool `json:"scheme_user"` - SchemeAdmin bool `json:"scheme_admin"` - ExplicitRoles string `json:"explicit_roles"` -} - -type ChannelMembers []ChannelMember - -type ChannelMemberForExport struct { - ChannelMember - ChannelName string - Username string -} - -func (o *ChannelMembers) ToJson() string { - b, err := json.Marshal(o) - if err != nil { - return "[]" - } - return string(b) -} - -func (o *ChannelUnread) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func (o *ChannelUnreadAt) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func ChannelMembersFromJson(data io.Reader) *ChannelMembers { - var o *ChannelMembers - json.NewDecoder(data).Decode(&o) - return o -} - -func ChannelUnreadFromJson(data io.Reader) *ChannelUnread { - var o *ChannelUnread - json.NewDecoder(data).Decode(&o) - return o -} - -func ChannelUnreadAtFromJson(data io.Reader) *ChannelUnreadAt { - var o *ChannelUnreadAt - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *ChannelMember) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func ChannelMemberFromJson(data io.Reader) *ChannelMember { - var o *ChannelMember - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *ChannelMember) IsValid() *AppError { - - if !IsValidId(o.ChannelId) { - return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidId(o.UserId) { - return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) - } - - notifyLevel := o.NotifyProps[DESKTOP_NOTIFY_PROP] - if len(notifyLevel) > 20 || !IsChannelNotifyLevelValid(notifyLevel) { - return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.notify_level.app_error", nil, "notify_level="+notifyLevel, http.StatusBadRequest) - } - - markUnreadLevel := o.NotifyProps[MARK_UNREAD_NOTIFY_PROP] - if len(markUnreadLevel) > 20 || !IsChannelMarkUnreadLevelValid(markUnreadLevel) { - return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.unread_level.app_error", nil, "mark_unread_level="+markUnreadLevel, http.StatusBadRequest) - } - - if pushLevel, ok := o.NotifyProps[PUSH_NOTIFY_PROP]; ok { - if len(pushLevel) > 20 || !IsChannelNotifyLevelValid(pushLevel) { - return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.push_level.app_error", nil, "push_notification_level="+pushLevel, http.StatusBadRequest) - } - } - - if sendEmail, ok := o.NotifyProps[EMAIL_NOTIFY_PROP]; ok { - if len(sendEmail) > 20 || !IsSendEmailValid(sendEmail) { - return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.email_value.app_error", nil, "push_notification_level="+sendEmail, http.StatusBadRequest) - } - } - - if ignoreChannelMentions, ok := o.NotifyProps[IGNORE_CHANNEL_MENTIONS_NOTIFY_PROP]; ok { - if len(ignoreChannelMentions) > 40 || !IsIgnoreChannelMentionsValid(ignoreChannelMentions) { - return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.ignore_channel_mentions_value.app_error", nil, "ignore_channel_mentions="+ignoreChannelMentions, http.StatusBadRequest) - } - } - - return nil -} - -func (o *ChannelMember) PreSave() { - o.LastUpdateAt = GetMillis() -} - -func (o *ChannelMember) PreUpdate() { - o.LastUpdateAt = GetMillis() -} - -func (o *ChannelMember) GetRoles() []string { - return strings.Fields(o.Roles) -} - -func (o *ChannelMember) SetChannelMuted(muted bool) { - if o.IsChannelMuted() { - o.NotifyProps[MARK_UNREAD_NOTIFY_PROP] = CHANNEL_MARK_UNREAD_ALL - } else { - o.NotifyProps[MARK_UNREAD_NOTIFY_PROP] = CHANNEL_MARK_UNREAD_MENTION - } -} - -func (o *ChannelMember) IsChannelMuted() bool { - return o.NotifyProps[MARK_UNREAD_NOTIFY_PROP] == CHANNEL_MARK_UNREAD_MENTION -} - -func IsChannelNotifyLevelValid(notifyLevel string) bool { - return notifyLevel == CHANNEL_NOTIFY_DEFAULT || - notifyLevel == CHANNEL_NOTIFY_ALL || - notifyLevel == CHANNEL_NOTIFY_MENTION || - notifyLevel == CHANNEL_NOTIFY_NONE -} - -func IsChannelMarkUnreadLevelValid(markUnreadLevel string) bool { - return markUnreadLevel == CHANNEL_MARK_UNREAD_ALL || markUnreadLevel == CHANNEL_MARK_UNREAD_MENTION -} - -func IsSendEmailValid(sendEmail string) bool { - return sendEmail == CHANNEL_NOTIFY_DEFAULT || sendEmail == "true" || sendEmail == "false" -} - -func IsIgnoreChannelMentionsValid(ignoreChannelMentions string) bool { - return ignoreChannelMentions == IGNORE_CHANNEL_MENTIONS_ON || ignoreChannelMentions == IGNORE_CHANNEL_MENTIONS_OFF || ignoreChannelMentions == IGNORE_CHANNEL_MENTIONS_DEFAULT -} - -func GetDefaultChannelNotifyProps() StringMap { - return StringMap{ - DESKTOP_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT, - MARK_UNREAD_NOTIFY_PROP: CHANNEL_MARK_UNREAD_ALL, - PUSH_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT, - EMAIL_NOTIFY_PROP: CHANNEL_NOTIFY_DEFAULT, - IGNORE_CHANNEL_MENTIONS_NOTIFY_PROP: IGNORE_CHANNEL_MENTIONS_DEFAULT, - } -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history.go deleted file mode 100644 index b77e0ff9..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -type ChannelMemberHistory struct { - ChannelId string - UserId string - JoinTime int64 - LeaveTime *int64 -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history_result.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history_result.go deleted file mode 100644 index 8f43ca4e..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_member_history_result.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -type ChannelMemberHistoryResult struct { - ChannelId string - UserId string - JoinTime int64 - LeaveTime *int64 - - // these two fields are never set in the database - when we SELECT, we join on Users to get them - UserEmail string `db:"Email"` - Username string - IsBot bool - UserDeleteAt int64 -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_mentions.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_mentions.go deleted file mode 100644 index eb14e8ed..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_mentions.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "regexp" - "strings" -) - -var channelMentionRegexp = regexp.MustCompile(`\B~[a-zA-Z0-9\-_]+`) - -func ChannelMentions(message string) []string { - var names []string - - if strings.Contains(message, "~") { - alreadyMentioned := make(map[string]bool) - for _, match := range channelMentionRegexp.FindAllString(message, -1) { - name := match[1:] - if !alreadyMentioned[name] { - names = append(names, name) - alreadyMentioned[name] = true - } - } - } - - return names -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_search.go deleted file mode 100644 index 51e11736..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_search.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -const CHANNEL_SEARCH_DEFAULT_LIMIT = 50 - -type ChannelSearch struct { - Term string `json:"term"` - ExcludeDefaultChannels bool `json:"exclude_default_channels"` - NotAssociatedToGroup string `json:"not_associated_to_group"` - TeamIds []string `json:"team_ids"` - GroupConstrained bool `json:"group_constrained"` - ExcludeGroupConstrained bool `json:"exclude_group_constrained"` - ExcludePolicyConstrained bool `json:"exclude_policy_constrained"` - Public bool `json:"public"` - Private bool `json:"private"` - IncludeDeleted bool `json:"include_deleted"` - Deleted bool `json:"deleted"` - Page *int `json:"page,omitempty"` - PerPage *int `json:"per_page,omitempty"` -} - -// ToJson convert a Channel to a json string -func (c *ChannelSearch) ToJson() string { - b, _ := json.Marshal(c) - return string(b) -} - -// ChannelSearchFromJson will decode the input and return a Channel -func ChannelSearchFromJson(data io.Reader) *ChannelSearch { - var cs *ChannelSearch - json.NewDecoder(data).Decode(&cs) - return cs -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_sidebar.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_sidebar.go deleted file mode 100644 index 35301d1e..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_sidebar.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "regexp" -) - -type SidebarCategoryType string -type SidebarCategorySorting string - -const ( - // Each sidebar category has a 'type'. System categories are Channels, Favorites and DMs - // All user-created categories will have type Custom - SidebarCategoryChannels SidebarCategoryType = "channels" - SidebarCategoryDirectMessages SidebarCategoryType = "direct_messages" - SidebarCategoryFavorites SidebarCategoryType = "favorites" - SidebarCategoryCustom SidebarCategoryType = "custom" - // Increment to use when adding/reordering things in the sidebar - MinimalSidebarSortDistance = 10 - // Default Sort Orders for categories - DefaultSidebarSortOrderFavorites = 0 - DefaultSidebarSortOrderChannels = DefaultSidebarSortOrderFavorites + MinimalSidebarSortDistance - DefaultSidebarSortOrderDMs = DefaultSidebarSortOrderChannels + MinimalSidebarSortDistance - // Sorting modes - // default for all categories except DMs (behaves like manual) - SidebarCategorySortDefault SidebarCategorySorting = "" - // sort manually - SidebarCategorySortManual SidebarCategorySorting = "manual" - // sort by recency (default for DMs) - SidebarCategorySortRecent SidebarCategorySorting = "recent" - // sort by display name alphabetically - SidebarCategorySortAlphabetical SidebarCategorySorting = "alpha" -) - -// SidebarCategory represents the corresponding DB table -// SortOrder is never returned to the user and only used for queries -type SidebarCategory struct { - Id string `json:"id"` - UserId string `json:"user_id"` - TeamId string `json:"team_id"` - SortOrder int64 `json:"-"` - Sorting SidebarCategorySorting `json:"sorting"` - Type SidebarCategoryType `json:"type"` - DisplayName string `json:"display_name"` - Muted bool `json:"muted"` - Collapsed bool `json:"collapsed"` -} - -// SidebarCategoryWithChannels combines data from SidebarCategory table with the Channel IDs that belong to that category -type SidebarCategoryWithChannels struct { - SidebarCategory - Channels []string `json:"channel_ids"` -} - -type SidebarCategoryOrder []string - -// OrderedSidebarCategories combines categories, their channel IDs and an array of Category IDs, sorted -type OrderedSidebarCategories struct { - Categories SidebarCategoriesWithChannels `json:"categories"` - Order SidebarCategoryOrder `json:"order"` -} - -type SidebarChannel struct { - ChannelId string `json:"channel_id"` - UserId string `json:"user_id"` - CategoryId string `json:"category_id"` - SortOrder int64 `json:"-"` -} - -type SidebarChannels []*SidebarChannel -type SidebarCategoriesWithChannels []*SidebarCategoryWithChannels - -func SidebarCategoryFromJson(data io.Reader) (*SidebarCategoryWithChannels, error) { - var o *SidebarCategoryWithChannels - err := json.NewDecoder(data).Decode(&o) - return o, err -} - -func SidebarCategoriesFromJson(data io.Reader) ([]*SidebarCategoryWithChannels, error) { - var o []*SidebarCategoryWithChannels - err := json.NewDecoder(data).Decode(&o) - return o, err -} - -func OrderedSidebarCategoriesFromJson(data io.Reader) (*OrderedSidebarCategories, error) { - var o *OrderedSidebarCategories - err := json.NewDecoder(data).Decode(&o) - return o, err -} - -func (o SidebarCategoryWithChannels) ToJson() []byte { - b, _ := json.Marshal(o) - return b -} - -func SidebarCategoriesWithChannelsToJson(o []*SidebarCategoryWithChannels) []byte { - b, err := json.Marshal(o) - if err != nil { - return []byte("[]") - } - return b -} - -func (o OrderedSidebarCategories) ToJson() []byte { - b, err := json.Marshal(o) - if err != nil { - return []byte("[]") - } - return b -} - -var categoryIdPattern = regexp.MustCompile("(favorites|channels|direct_messages)_[a-z0-9]{26}_[a-z0-9]{26}") - -func IsValidCategoryId(s string) bool { - // Category IDs can either be regular IDs - if IsValidId(s) { - return true - } - - // Or default categories can follow the pattern {type}_{userID}_{teamID} - return categoryIdPattern.MatchString(s) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_stats.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_stats.go deleted file mode 100644 index 76f682aa..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_stats.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type ChannelStats struct { - ChannelId string `json:"channel_id"` - MemberCount int64 `json:"member_count"` - GuestCount int64 `json:"guest_count"` - PinnedPostCount int64 `json:"pinnedpost_count"` -} - -func (o *ChannelStats) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func ChannelStatsFromJson(data io.Reader) *ChannelStats { - var o *ChannelStats - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_view.go b/vendor/github.com/mattermost/mattermost-server/v5/model/channel_view.go deleted file mode 100644 index 2ba74434..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/channel_view.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type ChannelView struct { - ChannelId string `json:"channel_id"` - PrevChannelId string `json:"prev_channel_id"` - CollapsedThreadsSupported bool `json:"collapsed_threads_supported"` -} - -func (o *ChannelView) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func ChannelViewFromJson(data io.Reader) *ChannelView { - var o *ChannelView - json.NewDecoder(data).Decode(&o) - return o -} - -type ChannelViewResponse struct { - Status string `json:"status"` - LastViewedAtTimes map[string]int64 `json:"last_viewed_at_times"` -} - -func (o *ChannelViewResponse) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func ChannelViewResponseFromJson(data io.Reader) *ChannelViewResponse { - var o *ChannelViewResponse - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/client4.go b/vendor/github.com/mattermost/mattermost-server/v5/model/client4.go deleted file mode 100644 index 0b9e713a..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/client4.go +++ /dev/null @@ -1,6343 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "mime/multipart" - "net" - "net/http" - "net/url" - "strconv" - "strings" - "time" -) - -const ( - HEADER_REQUEST_ID = "X-Request-ID" - HEADER_VERSION_ID = "X-Version-ID" - HEADER_CLUSTER_ID = "X-Cluster-ID" - HEADER_ETAG_SERVER = "ETag" - HEADER_ETAG_CLIENT = "If-None-Match" - HEADER_FORWARDED = "X-Forwarded-For" - HEADER_REAL_IP = "X-Real-IP" - HEADER_FORWARDED_PROTO = "X-Forwarded-Proto" - HEADER_TOKEN = "token" - HEADER_CSRF_TOKEN = "X-CSRF-Token" - HEADER_BEARER = "BEARER" - HEADER_AUTH = "Authorization" - HEADER_CLOUD_TOKEN = "X-Cloud-Token" - HEADER_REMOTECLUSTER_TOKEN = "X-RemoteCluster-Token" - HEADER_REMOTECLUSTER_ID = "X-RemoteCluster-Id" - HEADER_REQUESTED_WITH = "X-Requested-With" - HEADER_REQUESTED_WITH_XML = "XMLHttpRequest" - HEADER_RANGE = "Range" - STATUS = "status" - STATUS_OK = "OK" - STATUS_FAIL = "FAIL" - STATUS_UNHEALTHY = "UNHEALTHY" - STATUS_REMOVE = "REMOVE" - - CLIENT_DIR = "client" - - API_URL_SUFFIX_V1 = "/api/v1" - API_URL_SUFFIX_V4 = "/api/v4" - API_URL_SUFFIX = API_URL_SUFFIX_V4 -) - -type Response struct { - StatusCode int - Error *AppError - RequestId string - Etag string - ServerVersion string - Header http.Header -} - -type Client4 struct { - Url string // The location of the server, for example "http://localhost:8065" - ApiUrl string // The api location of the server, for example "http://localhost:8065/api/v4" - HttpClient *http.Client // The http client - AuthToken string - AuthType string - HttpHeader map[string]string // Headers to be copied over for each request - - // TrueString is the string value sent to the server for true boolean query parameters. - trueString string - - // FalseString is the string value sent to the server for false boolean query parameters. - falseString string -} - -// SetBoolString is a helper method for overriding how true and false query string parameters are -// sent to the server. -// -// This method is only exposed for testing. It is never necessary to configure these values -// in production. -func (c *Client4) SetBoolString(value bool, valueStr string) { - if value { - c.trueString = valueStr - } else { - c.falseString = valueStr - } -} - -// boolString builds the query string parameter for boolean values. -func (c *Client4) boolString(value bool) string { - if value && c.trueString != "" { - return c.trueString - } else if !value && c.falseString != "" { - return c.falseString - } - - if value { - return "true" - } - return "false" -} - -func closeBody(r *http.Response) { - if r.Body != nil { - _, _ = io.Copy(ioutil.Discard, r.Body) - _ = r.Body.Close() - } -} - -// Must is a convenience function used for testing. -func (c *Client4) Must(result interface{}, resp *Response) interface{} { - if resp.Error != nil { - time.Sleep(time.Second) - panic(resp.Error) - } - - return result -} - -func NewAPIv4Client(url string) *Client4 { - url = strings.TrimRight(url, "/") - return &Client4{url, url + API_URL_SUFFIX, &http.Client{}, "", "", map[string]string{}, "", ""} -} - -func NewAPIv4SocketClient(socketPath string) *Client4 { - tr := &http.Transport{ - Dial: func(network, addr string) (net.Conn, error) { - return net.Dial("unix", socketPath) - }, - } - - client := NewAPIv4Client("http://_") - client.HttpClient = &http.Client{Transport: tr} - - return client -} - -func BuildErrorResponse(r *http.Response, err *AppError) *Response { - var statusCode int - var header http.Header - if r != nil { - statusCode = r.StatusCode - header = r.Header - } else { - statusCode = 0 - header = make(http.Header) - } - - return &Response{ - StatusCode: statusCode, - Error: err, - Header: header, - } -} - -func BuildResponse(r *http.Response) *Response { - return &Response{ - StatusCode: r.StatusCode, - RequestId: r.Header.Get(HEADER_REQUEST_ID), - Etag: r.Header.Get(HEADER_ETAG_SERVER), - ServerVersion: r.Header.Get(HEADER_VERSION_ID), - Header: r.Header, - } -} - -func (c *Client4) SetToken(token string) { - c.AuthToken = token - c.AuthType = HEADER_BEARER -} - -// MockSession is deprecated in favour of SetToken -func (c *Client4) MockSession(token string) { - c.SetToken(token) -} - -func (c *Client4) SetOAuthToken(token string) { - c.AuthToken = token - c.AuthType = HEADER_TOKEN -} - -func (c *Client4) ClearOAuthToken() { - c.AuthToken = "" - c.AuthType = HEADER_BEARER -} - -func (c *Client4) GetUsersRoute() string { - return "/users" -} - -func (c *Client4) GetUserRoute(userId string) string { - return fmt.Sprintf(c.GetUsersRoute()+"/%v", userId) -} - -func (c *Client4) GetUserThreadsRoute(userID, teamID string) string { - return c.GetUserRoute(userID) + c.GetTeamRoute(teamID) + "/threads" -} - -func (c *Client4) GetUserThreadRoute(userId, teamId, threadId string) string { - return c.GetUserThreadsRoute(userId, teamId) + "/" + threadId -} - -func (c *Client4) GetUserCategoryRoute(userID, teamID string) string { - return c.GetUserRoute(userID) + c.GetTeamRoute(teamID) + "/channels/categories" -} - -func (c *Client4) GetUserAccessTokensRoute() string { - return fmt.Sprintf(c.GetUsersRoute() + "/tokens") -} - -func (c *Client4) GetUserAccessTokenRoute(tokenId string) string { - return fmt.Sprintf(c.GetUsersRoute()+"/tokens/%v", tokenId) -} - -func (c *Client4) GetUserByUsernameRoute(userName string) string { - return fmt.Sprintf(c.GetUsersRoute()+"/username/%v", userName) -} - -func (c *Client4) GetUserByEmailRoute(email string) string { - return fmt.Sprintf(c.GetUsersRoute()+"/email/%v", email) -} - -func (c *Client4) GetBotsRoute() string { - return "/bots" -} - -func (c *Client4) GetBotRoute(botUserId string) string { - return fmt.Sprintf("%s/%s", c.GetBotsRoute(), botUserId) -} - -func (c *Client4) GetTeamsRoute() string { - return "/teams" -} - -func (c *Client4) GetTeamRoute(teamId string) string { - return fmt.Sprintf(c.GetTeamsRoute()+"/%v", teamId) -} - -func (c *Client4) GetTeamAutoCompleteCommandsRoute(teamId string) string { - return fmt.Sprintf(c.GetTeamsRoute()+"/%v/commands/autocomplete", teamId) -} - -func (c *Client4) GetTeamByNameRoute(teamName string) string { - return fmt.Sprintf(c.GetTeamsRoute()+"/name/%v", teamName) -} - -func (c *Client4) GetTeamMemberRoute(teamId, userId string) string { - return fmt.Sprintf(c.GetTeamRoute(teamId)+"/members/%v", userId) -} - -func (c *Client4) GetTeamMembersRoute(teamId string) string { - return fmt.Sprintf(c.GetTeamRoute(teamId) + "/members") -} - -func (c *Client4) GetTeamStatsRoute(teamId string) string { - return fmt.Sprintf(c.GetTeamRoute(teamId) + "/stats") -} - -func (c *Client4) GetTeamImportRoute(teamId string) string { - return fmt.Sprintf(c.GetTeamRoute(teamId) + "/import") -} - -func (c *Client4) GetChannelsRoute() string { - return "/channels" -} - -func (c *Client4) GetChannelsForTeamRoute(teamId string) string { - return fmt.Sprintf(c.GetTeamRoute(teamId) + "/channels") -} - -func (c *Client4) GetChannelRoute(channelId string) string { - return fmt.Sprintf(c.GetChannelsRoute()+"/%v", channelId) -} - -func (c *Client4) GetChannelByNameRoute(channelName, teamId string) string { - return fmt.Sprintf(c.GetTeamRoute(teamId)+"/channels/name/%v", channelName) -} - -func (c *Client4) GetChannelsForTeamForUserRoute(teamId, userId string, includeDeleted bool) string { - route := fmt.Sprintf(c.GetUserRoute(userId) + c.GetTeamRoute(teamId) + "/channels") - if includeDeleted { - query := fmt.Sprintf("?include_deleted=%v", includeDeleted) - return route + query - } - return route -} - -func (c *Client4) GetChannelByNameForTeamNameRoute(channelName, teamName string) string { - return fmt.Sprintf(c.GetTeamByNameRoute(teamName)+"/channels/name/%v", channelName) -} - -func (c *Client4) GetChannelMembersRoute(channelId string) string { - return fmt.Sprintf(c.GetChannelRoute(channelId) + "/members") -} - -func (c *Client4) GetChannelMemberRoute(channelId, userId string) string { - return fmt.Sprintf(c.GetChannelMembersRoute(channelId)+"/%v", userId) -} - -func (c *Client4) GetPostsRoute() string { - return "/posts" -} - -func (c *Client4) GetPostsEphemeralRoute() string { - return "/posts/ephemeral" -} - -func (c *Client4) GetConfigRoute() string { - return "/config" -} - -func (c *Client4) GetLicenseRoute() string { - return "/license" -} - -func (c *Client4) GetPostRoute(postId string) string { - return fmt.Sprintf(c.GetPostsRoute()+"/%v", postId) -} - -func (c *Client4) GetFilesRoute() string { - return "/files" -} - -func (c *Client4) GetFileRoute(fileId string) string { - return fmt.Sprintf(c.GetFilesRoute()+"/%v", fileId) -} - -func (c *Client4) GetUploadsRoute() string { - return "/uploads" -} - -func (c *Client4) GetUploadRoute(uploadId string) string { - return fmt.Sprintf("%s/%s", c.GetUploadsRoute(), uploadId) -} - -func (c *Client4) GetPluginsRoute() string { - return "/plugins" -} - -func (c *Client4) GetPluginRoute(pluginId string) string { - return fmt.Sprintf(c.GetPluginsRoute()+"/%v", pluginId) -} - -func (c *Client4) GetSystemRoute() string { - return "/system" -} - -func (c *Client4) GetCloudRoute() string { - return "/cloud" -} - -func (c *Client4) GetTestEmailRoute() string { - return "/email/test" -} - -func (c *Client4) GetTestSiteURLRoute() string { - return "/site_url/test" -} - -func (c *Client4) GetTestS3Route() string { - return "/file/s3_test" -} - -func (c *Client4) GetDatabaseRoute() string { - return "/database" -} - -func (c *Client4) GetCacheRoute() string { - return "/caches" -} - -func (c *Client4) GetClusterRoute() string { - return "/cluster" -} - -func (c *Client4) GetIncomingWebhooksRoute() string { - return "/hooks/incoming" -} - -func (c *Client4) GetIncomingWebhookRoute(hookID string) string { - return fmt.Sprintf(c.GetIncomingWebhooksRoute()+"/%v", hookID) -} - -func (c *Client4) GetComplianceReportsRoute() string { - return "/compliance/reports" -} - -func (c *Client4) GetComplianceReportRoute(reportId string) string { - return fmt.Sprintf("%s/%s", c.GetComplianceReportsRoute(), reportId) -} - -func (c *Client4) GetComplianceReportDownloadRoute(reportId string) string { - return fmt.Sprintf("%s/%s/download", c.GetComplianceReportsRoute(), reportId) -} - -func (c *Client4) GetOutgoingWebhooksRoute() string { - return "/hooks/outgoing" -} - -func (c *Client4) GetOutgoingWebhookRoute(hookID string) string { - return fmt.Sprintf(c.GetOutgoingWebhooksRoute()+"/%v", hookID) -} - -func (c *Client4) GetPreferencesRoute(userId string) string { - return fmt.Sprintf(c.GetUserRoute(userId) + "/preferences") -} - -func (c *Client4) GetUserStatusRoute(userId string) string { - return fmt.Sprintf(c.GetUserRoute(userId) + "/status") -} - -func (c *Client4) GetUserStatusesRoute() string { - return fmt.Sprintf(c.GetUsersRoute() + "/status") -} - -func (c *Client4) GetSamlRoute() string { - return "/saml" -} - -func (c *Client4) GetLdapRoute() string { - return "/ldap" -} - -func (c *Client4) GetBrandRoute() string { - return "/brand" -} - -func (c *Client4) GetDataRetentionRoute() string { - return "/data_retention" -} - -func (c *Client4) GetDataRetentionPolicyRoute(policyID string) string { - return fmt.Sprintf(c.GetDataRetentionRoute()+"/policies/%v", policyID) -} - -func (c *Client4) GetElasticsearchRoute() string { - return "/elasticsearch" -} - -func (c *Client4) GetBleveRoute() string { - return "/bleve" -} - -func (c *Client4) GetCommandsRoute() string { - return "/commands" -} - -func (c *Client4) GetCommandRoute(commandId string) string { - return fmt.Sprintf(c.GetCommandsRoute()+"/%v", commandId) -} - -func (c *Client4) GetCommandMoveRoute(commandId string) string { - return fmt.Sprintf(c.GetCommandsRoute()+"/%v/move", commandId) -} - -func (c *Client4) GetEmojisRoute() string { - return "/emoji" -} - -func (c *Client4) GetEmojiRoute(emojiId string) string { - return fmt.Sprintf(c.GetEmojisRoute()+"/%v", emojiId) -} - -func (c *Client4) GetEmojiByNameRoute(name string) string { - return fmt.Sprintf(c.GetEmojisRoute()+"/name/%v", name) -} - -func (c *Client4) GetReactionsRoute() string { - return "/reactions" -} - -func (c *Client4) GetOAuthAppsRoute() string { - return "/oauth/apps" -} - -func (c *Client4) GetOAuthAppRoute(appId string) string { - return fmt.Sprintf("/oauth/apps/%v", appId) -} - -func (c *Client4) GetOpenGraphRoute() string { - return "/opengraph" -} - -func (c *Client4) GetJobsRoute() string { - return "/jobs" -} - -func (c *Client4) GetRolesRoute() string { - return "/roles" -} - -func (c *Client4) GetSchemesRoute() string { - return "/schemes" -} - -func (c *Client4) GetSchemeRoute(id string) string { - return c.GetSchemesRoute() + fmt.Sprintf("/%v", id) -} - -func (c *Client4) GetAnalyticsRoute() string { - return "/analytics" -} - -func (c *Client4) GetTimezonesRoute() string { - return fmt.Sprintf(c.GetSystemRoute() + "/timezones") -} - -func (c *Client4) GetChannelSchemeRoute(channelId string) string { - return fmt.Sprintf(c.GetChannelsRoute()+"/%v/scheme", channelId) -} - -func (c *Client4) GetTeamSchemeRoute(teamId string) string { - return fmt.Sprintf(c.GetTeamsRoute()+"/%v/scheme", teamId) -} - -func (c *Client4) GetTotalUsersStatsRoute() string { - return fmt.Sprintf(c.GetUsersRoute() + "/stats") -} - -func (c *Client4) GetRedirectLocationRoute() string { - return "/redirect_location" -} - -func (c *Client4) GetServerBusyRoute() string { - return "/server_busy" -} - -func (c *Client4) GetUserTermsOfServiceRoute(userId string) string { - return c.GetUserRoute(userId) + "/terms_of_service" -} - -func (c *Client4) GetTermsOfServiceRoute() string { - return "/terms_of_service" -} - -func (c *Client4) GetGroupsRoute() string { - return "/groups" -} - -func (c *Client4) GetPublishUserTypingRoute(userId string) string { - return c.GetUserRoute(userId) + "/typing" -} - -func (c *Client4) GetGroupRoute(groupID string) string { - return fmt.Sprintf("%s/%s", c.GetGroupsRoute(), groupID) -} - -func (c *Client4) GetGroupSyncableRoute(groupID, syncableID string, syncableType GroupSyncableType) string { - return fmt.Sprintf("%s/%ss/%s", c.GetGroupRoute(groupID), strings.ToLower(syncableType.String()), syncableID) -} - -func (c *Client4) GetGroupSyncablesRoute(groupID string, syncableType GroupSyncableType) string { - return fmt.Sprintf("%s/%ss", c.GetGroupRoute(groupID), strings.ToLower(syncableType.String())) -} - -func (c *Client4) GetImportsRoute() string { - return "/imports" -} - -func (c *Client4) GetExportsRoute() string { - return "/exports" -} - -func (c *Client4) GetExportRoute(name string) string { - return fmt.Sprintf(c.GetExportsRoute()+"/%v", name) -} - -func (c *Client4) GetRemoteClusterRoute() string { - return "/remotecluster" -} - -func (c *Client4) GetSharedChannelsRoute() string { - return "/sharedchannels" -} - -func (c *Client4) GetPermissionsRoute() string { - return "/permissions" -} - -func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) { - return c.DoApiRequest(http.MethodGet, c.ApiUrl+url, "", etag) -} - -func (c *Client4) DoApiPost(url string, data string) (*http.Response, *AppError) { - return c.DoApiRequest(http.MethodPost, c.ApiUrl+url, data, "") -} - -func (c *Client4) doApiDeleteBytes(url string, data []byte) (*http.Response, *AppError) { - return c.doApiRequestBytes(http.MethodDelete, c.ApiUrl+url, data, "") -} - -func (c *Client4) doApiPatchBytes(url string, data []byte) (*http.Response, *AppError) { - return c.doApiRequestBytes(http.MethodPatch, c.ApiUrl+url, data, "") -} - -func (c *Client4) doApiPostBytes(url string, data []byte) (*http.Response, *AppError) { - return c.doApiRequestBytes(http.MethodPost, c.ApiUrl+url, data, "") -} - -func (c *Client4) DoApiPut(url string, data string) (*http.Response, *AppError) { - return c.DoApiRequest(http.MethodPut, c.ApiUrl+url, data, "") -} - -func (c *Client4) doApiPutBytes(url string, data []byte) (*http.Response, *AppError) { - return c.doApiRequestBytes(http.MethodPut, c.ApiUrl+url, data, "") -} - -func (c *Client4) DoApiDelete(url string) (*http.Response, *AppError) { - return c.DoApiRequest(http.MethodDelete, c.ApiUrl+url, "", "") -} - -func (c *Client4) DoApiRequest(method, url, data, etag string) (*http.Response, *AppError) { - return c.doApiRequestReader(method, url, strings.NewReader(data), map[string]string{HEADER_ETAG_CLIENT: etag}) -} - -func (c *Client4) DoApiRequestWithHeaders(method, url, data string, headers map[string]string) (*http.Response, *AppError) { - return c.doApiRequestReader(method, url, strings.NewReader(data), headers) -} - -func (c *Client4) doApiRequestBytes(method, url string, data []byte, etag string) (*http.Response, *AppError) { - return c.doApiRequestReader(method, url, bytes.NewReader(data), map[string]string{HEADER_ETAG_CLIENT: etag}) -} - -func (c *Client4) doApiRequestReader(method, url string, data io.Reader, headers map[string]string) (*http.Response, *AppError) { - rq, err := http.NewRequest(method, url, data) - if err != nil { - return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest) - } - - for k, v := range headers { - rq.Header.Set(k, v) - } - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) - } - - if c.HttpHeader != nil && len(c.HttpHeader) > 0 { - for k, v := range c.HttpHeader { - rq.Header.Set(k, v) - } - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0) - } - - if rp.StatusCode == 304 { - return rp, nil - } - - if rp.StatusCode >= 300 { - defer closeBody(rp) - return rp, AppErrorFromJson(rp.Body) - } - - return rp, nil -} - -func (c *Client4) DoUploadFile(url string, data []byte, contentType string) (*FileUploadResponse, *Response) { - return c.doUploadFile(url, bytes.NewReader(data), contentType, 0) -} - -func (c *Client4) doUploadFile(url string, body io.Reader, contentType string, contentLength int64) (*FileUploadResponse, *Response) { - rq, err := http.NewRequest("POST", c.ApiUrl+url, body) - if err != nil { - return nil, &Response{Error: NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - if contentLength != 0 { - rq.ContentLength = contentLength - } - rq.Header.Set("Content-Type", contentType) - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)) - } - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } - - return FileUploadResponseFromJson(rp.Body), BuildResponse(rp) -} - -func (c *Client4) DoEmojiUploadFile(url string, data []byte, contentType string) (*Emoji, *Response) { - rq, err := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data)) - if err != nil { - return nil, &Response{Error: NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - rq.Header.Set("Content-Type", contentType) - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)) - } - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } - - return EmojiFromJson(rp.Body), BuildResponse(rp) -} - -func (c *Client4) DoUploadImportTeam(url string, data []byte, contentType string) (map[string]string, *Response) { - rq, err := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data)) - if err != nil { - return nil, &Response{Error: NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - rq.Header.Set("Content-Type", contentType) - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)) - } - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } - - return MapFromJson(rp.Body), BuildResponse(rp) -} - -// CheckStatusOK is a convenience function for checking the standard OK response -// from the web service. -func CheckStatusOK(r *http.Response) bool { - m := MapFromJson(r.Body) - defer closeBody(r) - - if m != nil && m[STATUS] == STATUS_OK { - return true - } - - return false -} - -// Authentication Section - -// LoginById authenticates a user by user id and password. -func (c *Client4) LoginById(id string, password string) (*User, *Response) { - m := make(map[string]string) - m["id"] = id - m["password"] = password - return c.login(m) -} - -// Login authenticates a user by login id, which can be username, email or some sort -// of SSO identifier based on server configuration, and a password. -func (c *Client4) Login(loginId string, password string) (*User, *Response) { - m := make(map[string]string) - m["login_id"] = loginId - m["password"] = password - return c.login(m) -} - -// LoginByLdap authenticates a user by LDAP id and password. -func (c *Client4) LoginByLdap(loginId string, password string) (*User, *Response) { - m := make(map[string]string) - m["login_id"] = loginId - m["password"] = password - m["ldap_only"] = c.boolString(true) - return c.login(m) -} - -// LoginWithDevice authenticates a user by login id (username, email or some sort -// of SSO identifier based on configuration), password and attaches a device id to -// the session. -func (c *Client4) LoginWithDevice(loginId string, password string, deviceId string) (*User, *Response) { - m := make(map[string]string) - m["login_id"] = loginId - m["password"] = password - m["device_id"] = deviceId - return c.login(m) -} - -// LoginWithMFA logs a user in with a MFA token -func (c *Client4) LoginWithMFA(loginId, password, mfaToken string) (*User, *Response) { - m := make(map[string]string) - m["login_id"] = loginId - m["password"] = password - m["token"] = mfaToken - return c.login(m) -} - -func (c *Client4) login(m map[string]string) (*User, *Response) { - r, err := c.DoApiPost("/users/login", MapToJson(m)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - c.AuthToken = r.Header.Get(HEADER_TOKEN) - c.AuthType = HEADER_BEARER - return UserFromJson(r.Body), BuildResponse(r) -} - -// Logout terminates the current user's session. -func (c *Client4) Logout() (bool, *Response) { - r, err := c.DoApiPost("/users/logout", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - c.AuthToken = "" - c.AuthType = HEADER_BEARER - return CheckStatusOK(r), BuildResponse(r) -} - -// SwitchAccountType changes a user's login type from one type to another. -func (c *Client4) SwitchAccountType(switchRequest *SwitchRequest) (string, *Response) { - r, err := c.DoApiPost(c.GetUsersRoute()+"/login/switch", switchRequest.ToJson()) - if err != nil { - return "", BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body)["follow_link"], BuildResponse(r) -} - -// User Section - -// CreateUser creates a user in the system based on the provided user struct. -func (c *Client4) CreateUser(user *User) (*User, *Response) { - r, err := c.DoApiPost(c.GetUsersRoute(), user.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) -} - -// CreateUserWithToken creates a user in the system based on the provided tokenId. -func (c *Client4) CreateUserWithToken(user *User, tokenId string) (*User, *Response) { - if tokenId == "" { - err := NewAppError("MissingHashOrData", "api.user.create_user.missing_token.app_error", nil, "", http.StatusBadRequest) - return nil, &Response{StatusCode: err.StatusCode, Error: err} - } - - query := fmt.Sprintf("?t=%v", tokenId) - r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - - return UserFromJson(r.Body), BuildResponse(r) -} - -// CreateUserWithInviteId creates a user in the system based on the provided invited id. -func (c *Client4) CreateUserWithInviteId(user *User, inviteId string) (*User, *Response) { - if inviteId == "" { - err := NewAppError("MissingInviteId", "api.user.create_user.missing_invite_id.app_error", nil, "", http.StatusBadRequest) - return nil, &Response{StatusCode: err.StatusCode, Error: err} - } - - query := fmt.Sprintf("?iid=%v", url.QueryEscape(inviteId)) - r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - - return UserFromJson(r.Body), BuildResponse(r) -} - -// GetMe returns the logged in user. -func (c *Client4) GetMe(etag string) (*User, *Response) { - r, err := c.DoApiGet(c.GetUserRoute(ME), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) -} - -// GetUser returns a user based on the provided user id string. -func (c *Client4) GetUser(userId, etag string) (*User, *Response) { - r, err := c.DoApiGet(c.GetUserRoute(userId), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) -} - -// GetUserByUsername returns a user based on the provided user name string. -func (c *Client4) GetUserByUsername(userName, etag string) (*User, *Response) { - r, err := c.DoApiGet(c.GetUserByUsernameRoute(userName), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) -} - -// GetUserByEmail returns a user based on the provided user email string. -func (c *Client4) GetUserByEmail(email, etag string) (*User, *Response) { - r, err := c.DoApiGet(c.GetUserByEmailRoute(email), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) -} - -// AutocompleteUsersInTeam returns the users on a team based on search term. -func (c *Client4) AutocompleteUsersInTeam(teamId string, username string, limit int, etag string) (*UserAutocomplete, *Response) { - query := fmt.Sprintf("?in_team=%v&name=%v&limit=%d", teamId, username, limit) - r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserAutocompleteFromJson(r.Body), BuildResponse(r) -} - -// AutocompleteUsersInChannel returns the users in a channel based on search term. -func (c *Client4) AutocompleteUsersInChannel(teamId string, channelId string, username string, limit int, etag string) (*UserAutocomplete, *Response) { - query := fmt.Sprintf("?in_team=%v&in_channel=%v&name=%v&limit=%d", teamId, channelId, username, limit) - r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserAutocompleteFromJson(r.Body), BuildResponse(r) -} - -// AutocompleteUsers returns the users in the system based on search term. -func (c *Client4) AutocompleteUsers(username string, limit int, etag string) (*UserAutocomplete, *Response) { - query := fmt.Sprintf("?name=%v&limit=%d", username, limit) - r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserAutocompleteFromJson(r.Body), BuildResponse(r) -} - -// GetDefaultProfileImage gets the default user's profile image. Must be logged in. -func (c *Client4) GetDefaultProfileImage(userId string) ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetUserRoute(userId)+"/image/default", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetDefaultProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } - - return data, BuildResponse(r) -} - -// GetProfileImage gets user's profile image. Must be logged in. -func (c *Client4) GetProfileImage(userId, etag string) ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetUserRoute(userId)+"/image", etag) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } - return data, BuildResponse(r) -} - -// GetUsers returns a page of users on the system. Page counting starts at 0. -func (c *Client4) GetUsers(page int, perPage int, etag string) ([]*User, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetUsersInTeam returns a page of users on a team. Page counting starts at 0. -func (c *Client4) GetUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { - query := fmt.Sprintf("?in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetNewUsersInTeam returns a page of users on a team. Page counting starts at 0. -func (c *Client4) GetNewUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { - query := fmt.Sprintf("?sort=create_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetRecentlyActiveUsersInTeam returns a page of users on a team. Page counting starts at 0. -func (c *Client4) GetRecentlyActiveUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { - query := fmt.Sprintf("?sort=last_activity_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetActiveUsersInTeam returns a page of users on a team. Page counting starts at 0. -func (c *Client4) GetActiveUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { - query := fmt.Sprintf("?active=true&in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetUsersNotInTeam returns a page of users who are not in a team. Page counting starts at 0. -func (c *Client4) GetUsersNotInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) { - query := fmt.Sprintf("?not_in_team=%v&page=%v&per_page=%v", teamId, page, perPage) - r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetUsersInChannel returns a page of users in a channel. Page counting starts at 0. -func (c *Client4) GetUsersInChannel(channelId string, page int, perPage int, etag string) ([]*User, *Response) { - query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v", channelId, page, perPage) - r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetUsersInChannelByStatus returns a page of users in a channel. Page counting starts at 0. Sorted by Status -func (c *Client4) GetUsersInChannelByStatus(channelId string, page int, perPage int, etag string) ([]*User, *Response) { - query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v&sort=status", channelId, page, perPage) - r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetUsersNotInChannel returns a page of users not in a channel. Page counting starts at 0. -func (c *Client4) GetUsersNotInChannel(teamId, channelId string, page int, perPage int, etag string) ([]*User, *Response) { - query := fmt.Sprintf("?in_team=%v¬_in_channel=%v&page=%v&per_page=%v", teamId, channelId, page, perPage) - r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetUsersWithoutTeam returns a page of users on the system that aren't on any teams. Page counting starts at 0. -func (c *Client4) GetUsersWithoutTeam(page int, perPage int, etag string) ([]*User, *Response) { - query := fmt.Sprintf("?without_team=1&page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetUsersInGroup returns a page of users in a group. Page counting starts at 0. -func (c *Client4) GetUsersInGroup(groupID string, page int, perPage int, etag string) ([]*User, *Response) { - query := fmt.Sprintf("?in_group=%v&page=%v&per_page=%v", groupID, page, perPage) - r, err := c.DoApiGet(c.GetUsersRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetUsersByIds returns a list of users based on the provided user ids. -func (c *Client4) GetUsersByIds(userIds []string) ([]*User, *Response) { - r, err := c.DoApiPost(c.GetUsersRoute()+"/ids", ArrayToJson(userIds)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetUsersByIds returns a list of users based on the provided user ids. -func (c *Client4) GetUsersByIdsWithOptions(userIds []string, options *UserGetByIdsOptions) ([]*User, *Response) { - v := url.Values{} - if options.Since != 0 { - v.Set("since", fmt.Sprintf("%d", options.Since)) - } - - url := c.GetUsersRoute() + "/ids" - if len(v) > 0 { - url += "?" + v.Encode() - } - - r, err := c.DoApiPost(url, ArrayToJson(userIds)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetUsersByUsernames returns a list of users based on the provided usernames. -func (c *Client4) GetUsersByUsernames(usernames []string) ([]*User, *Response) { - r, err := c.DoApiPost(c.GetUsersRoute()+"/usernames", ArrayToJson(usernames)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// GetUsersByGroupChannelIds returns a map with channel ids as keys -// and a list of users as values based on the provided user ids. -func (c *Client4) GetUsersByGroupChannelIds(groupChannelIds []string) (map[string][]*User, *Response) { - r, err := c.DoApiPost(c.GetUsersRoute()+"/group_channels", ArrayToJson(groupChannelIds)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - - usersByChannelId := map[string][]*User{} - json.NewDecoder(r.Body).Decode(&usersByChannelId) - return usersByChannelId, BuildResponse(r) -} - -// SearchUsers returns a list of users based on some search criteria. -func (c *Client4) SearchUsers(search *UserSearch) ([]*User, *Response) { - r, err := c.doApiPostBytes(c.GetUsersRoute()+"/search", search.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserListFromJson(r.Body), BuildResponse(r) -} - -// UpdateUser updates a user in the system based on the provided user struct. -func (c *Client4) UpdateUser(user *User) (*User, *Response) { - r, err := c.DoApiPut(c.GetUserRoute(user.Id), user.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) -} - -// PatchUser partially updates a user in the system. Any missing fields are not updated. -func (c *Client4) PatchUser(userId string, patch *UserPatch) (*User, *Response) { - r, err := c.DoApiPut(c.GetUserRoute(userId)+"/patch", patch.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) -} - -// UpdateUserAuth updates a user AuthData (uthData, authService and password) in the system. -func (c *Client4) UpdateUserAuth(userId string, userAuth *UserAuth) (*UserAuth, *Response) { - r, err := c.DoApiPut(c.GetUserRoute(userId)+"/auth", userAuth.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserAuthFromJson(r.Body), BuildResponse(r) -} - -// UpdateUserMfa activates multi-factor authentication for a user if activate -// is true and a valid code is provided. If activate is false, then code is not -// required and multi-factor authentication is disabled for the user. -func (c *Client4) UpdateUserMfa(userId, code string, activate bool) (bool, *Response) { - requestBody := make(map[string]interface{}) - requestBody["activate"] = activate - requestBody["code"] = code - - r, err := c.DoApiPut(c.GetUserRoute(userId)+"/mfa", StringInterfaceToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// CheckUserMfa checks whether a user has MFA active on their account or not based on the -// provided login id. -// Deprecated: Clients should use Login method and check for MFA Error -func (c *Client4) CheckUserMfa(loginId string) (bool, *Response) { - requestBody := make(map[string]interface{}) - requestBody["login_id"] = loginId - r, err := c.DoApiPost(c.GetUsersRoute()+"/mfa", StringInterfaceToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - - data := StringInterfaceFromJson(r.Body) - mfaRequired, ok := data["mfa_required"].(bool) - if !ok { - return false, BuildResponse(r) - } - return mfaRequired, BuildResponse(r) -} - -// GenerateMfaSecret will generate a new MFA secret for a user and return it as a string and -// as a base64 encoded image QR code. -func (c *Client4) GenerateMfaSecret(userId string) (*MfaSecret, *Response) { - r, err := c.DoApiPost(c.GetUserRoute(userId)+"/mfa/generate", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return MfaSecretFromJson(r.Body), BuildResponse(r) -} - -// UpdateUserPassword updates a user's password. Must be logged in as the user or be a system administrator. -func (c *Client4) UpdateUserPassword(userId, currentPassword, newPassword string) (bool, *Response) { - requestBody := map[string]string{"current_password": currentPassword, "new_password": newPassword} - r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UpdateUserHashedPassword updates a user's password with an already-hashed password. Must be a system administrator. -func (c *Client4) UpdateUserHashedPassword(userId, newHashedPassword string) (bool, *Response) { - requestBody := map[string]string{"already_hashed": "true", "new_password": newHashedPassword} - r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// PromoteGuestToUser convert a guest into a regular user -func (c *Client4) PromoteGuestToUser(guestId string) (bool, *Response) { - r, err := c.DoApiPost(c.GetUserRoute(guestId)+"/promote", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// DemoteUserToGuest convert a regular user into a guest -func (c *Client4) DemoteUserToGuest(guestId string) (bool, *Response) { - r, err := c.DoApiPost(c.GetUserRoute(guestId)+"/demote", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UpdateUserRoles updates a user's roles in the system. A user can have "system_user" and "system_admin" roles. -func (c *Client4) UpdateUserRoles(userId, roles string) (bool, *Response) { - requestBody := map[string]string{"roles": roles} - r, err := c.DoApiPut(c.GetUserRoute(userId)+"/roles", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UpdateUserActive updates status of a user whether active or not. -func (c *Client4) UpdateUserActive(userId string, active bool) (bool, *Response) { - requestBody := make(map[string]interface{}) - requestBody["active"] = active - r, err := c.DoApiPut(c.GetUserRoute(userId)+"/active", StringInterfaceToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - - return CheckStatusOK(r), BuildResponse(r) -} - -// DeleteUser deactivates a user in the system based on the provided user id string. -func (c *Client4) DeleteUser(userId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetUserRoute(userId)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// PermanentDeleteUser deletes a user in the system based on the provided user id string. -func (c *Client4) PermanentDeleteUser(userId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetUserRoute(userId) + "?permanent=" + c.boolString(true)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// ConvertUserToBot converts a user to a bot user. -func (c *Client4) ConvertUserToBot(userId string) (*Bot, *Response) { - r, err := c.DoApiPost(c.GetUserRoute(userId)+"/convert_to_bot", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return BotFromJson(r.Body), BuildResponse(r) -} - -// ConvertBotToUser converts a bot user to a user. -func (c *Client4) ConvertBotToUser(userId string, userPatch *UserPatch, setSystemAdmin bool) (*User, *Response) { - var query string - if setSystemAdmin { - query = "?set_system_admin=true" - } - r, err := c.DoApiPost(c.GetBotRoute(userId)+"/convert_to_user"+query, userPatch.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) -} - -// PermanentDeleteAll permanently deletes all users in the system. This is a local only endpoint -func (c *Client4) PermanentDeleteAllUsers() (bool, *Response) { - r, err := c.DoApiDelete(c.GetUsersRoute()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// SendPasswordResetEmail will send a link for password resetting to a user with the -// provided email. -func (c *Client4) SendPasswordResetEmail(email string) (bool, *Response) { - requestBody := map[string]string{"email": email} - r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset/send", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// ResetPassword uses a recovery code to update reset a user's password. -func (c *Client4) ResetPassword(token, newPassword string) (bool, *Response) { - requestBody := map[string]string{"token": token, "new_password": newPassword} - r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetSessions returns a list of sessions based on the provided user id string. -func (c *Client4) GetSessions(userId, etag string) ([]*Session, *Response) { - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/sessions", etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return SessionsFromJson(r.Body), BuildResponse(r) -} - -// RevokeSession revokes a user session based on the provided user id and session id strings. -func (c *Client4) RevokeSession(userId, sessionId string) (bool, *Response) { - requestBody := map[string]string{"session_id": sessionId} - r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// RevokeAllSessions revokes all sessions for the provided user id string. -func (c *Client4) RevokeAllSessions(userId string) (bool, *Response) { - r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke/all", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// RevokeAllSessions revokes all sessions for all the users. -func (c *Client4) RevokeSessionsFromAllUsers() (bool, *Response) { - r, err := c.DoApiPost(c.GetUsersRoute()+"/sessions/revoke/all", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// AttachDeviceId attaches a mobile device ID to the current session. -func (c *Client4) AttachDeviceId(deviceId string) (bool, *Response) { - requestBody := map[string]string{"device_id": deviceId} - r, err := c.DoApiPut(c.GetUsersRoute()+"/sessions/device", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetTeamsUnreadForUser will return an array with TeamUnread objects that contain the amount -// of unread messages and mentions the current user has for the teams it belongs to. -// An optional team ID can be set to exclude that team from the results. -// An optional boolean can be set to include collapsed thread unreads. Must be authenticated. -func (c *Client4) GetTeamsUnreadForUser(userId, teamIdToExclude string, includeCollapsedThreads bool) ([]*TeamUnread, *Response) { - query := url.Values{} - - if teamIdToExclude != "" { - query.Set("exclude_team", teamIdToExclude) - } - - if includeCollapsedThreads { - query.Set("include_collapsed_threads", "true") - } - - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread?"+query.Encode(), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamsUnreadFromJson(r.Body), BuildResponse(r) -} - -// GetUserAudits returns a list of audit based on the provided user id string. -func (c *Client4) GetUserAudits(userId string, page int, perPage int, etag string) (Audits, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/audits"+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return AuditsFromJson(r.Body), BuildResponse(r) -} - -// VerifyUserEmail will verify a user's email using the supplied token. -func (c *Client4) VerifyUserEmail(token string) (bool, *Response) { - requestBody := map[string]string{"token": token} - r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// VerifyUserEmailWithoutToken will verify a user's email by its Id. (Requires manage system role) -func (c *Client4) VerifyUserEmailWithoutToken(userId string) (*User, *Response) { - r, err := c.DoApiPost(c.GetUserRoute(userId)+"/email/verify/member", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserFromJson(r.Body), BuildResponse(r) -} - -// SendVerificationEmail will send an email to the user with the provided email address, if -// that user exists. The email will contain a link that can be used to verify the user's -// email address. -func (c *Client4) SendVerificationEmail(email string) (bool, *Response) { - requestBody := map[string]string{"email": email} - r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify/send", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// SetDefaultProfileImage resets the profile image to a default generated one. -func (c *Client4) SetDefaultProfileImage(userId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetUserRoute(userId) + "/image") - if err != nil { - return false, BuildErrorResponse(r, err) - } - return CheckStatusOK(r), BuildResponse(r) -} - -// SetProfileImage sets profile image of the user. -func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) { - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - - part, err := writer.CreateFormFile("image", "profile.png") - if err != nil { - return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { - return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if err = writer.Close(); err != nil { - return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - rq, err := http.NewRequest("POST", c.ApiUrl+c.GetUserRoute(userId)+"/image", bytes.NewReader(body.Bytes())) - if err != nil { - return false, &Response{Error: NewAppError("SetProfileImage", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - rq.Header.Set("Content-Type", writer.FormDataContentType()) - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetUserRoute(userId)+"/image", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)} - } - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } - - return CheckStatusOK(rp), BuildResponse(rp) -} - -// CreateUserAccessToken will generate a user access token that can be used in place -// of a session token to access the REST API. Must have the 'create_user_access_token' -// permission and if generating for another user, must have the 'edit_other_users' -// permission. A non-blank description is required. -func (c *Client4) CreateUserAccessToken(userId, description string) (*UserAccessToken, *Response) { - requestBody := map[string]string{"description": description} - r, err := c.DoApiPost(c.GetUserRoute(userId)+"/tokens", MapToJson(requestBody)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserAccessTokenFromJson(r.Body), BuildResponse(r) -} - -// GetUserAccessTokens will get a page of access tokens' id, description, is_active -// and the user_id in the system. The actual token will not be returned. Must have -// the 'manage_system' permission. -func (c *Client4) GetUserAccessTokens(page int, perPage int) ([]*UserAccessToken, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetUserAccessTokensRoute()+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserAccessTokenListFromJson(r.Body), BuildResponse(r) -} - -// GetUserAccessToken will get a user access tokens' id, description, is_active -// and the user_id of the user it is for. The actual token will not be returned. -// Must have the 'read_user_access_token' permission and if getting for another -// user, must have the 'edit_other_users' permission. -func (c *Client4) GetUserAccessToken(tokenId string) (*UserAccessToken, *Response) { - r, err := c.DoApiGet(c.GetUserAccessTokenRoute(tokenId), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserAccessTokenFromJson(r.Body), BuildResponse(r) -} - -// GetUserAccessTokensForUser will get a paged list of user access tokens showing id, -// description and user_id for each. The actual tokens will not be returned. Must have -// the 'read_user_access_token' permission and if getting for another user, must have the -// 'edit_other_users' permission. -func (c *Client4) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*UserAccessToken, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/tokens"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserAccessTokenListFromJson(r.Body), BuildResponse(r) -} - -// RevokeUserAccessToken will revoke a user access token by id. Must have the -// 'revoke_user_access_token' permission and if revoking for another user, must have the -// 'edit_other_users' permission. -func (c *Client4) RevokeUserAccessToken(tokenId string) (bool, *Response) { - requestBody := map[string]string{"token_id": tokenId} - r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/revoke", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// SearchUserAccessTokens returns user access tokens matching the provided search term. -func (c *Client4) SearchUserAccessTokens(search *UserAccessTokenSearch) ([]*UserAccessToken, *Response) { - r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/search", search.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserAccessTokenListFromJson(r.Body), BuildResponse(r) -} - -// DisableUserAccessToken will disable a user access token by id. Must have the -// 'revoke_user_access_token' permission and if disabling for another user, must have the -// 'edit_other_users' permission. -func (c *Client4) DisableUserAccessToken(tokenId string) (bool, *Response) { - requestBody := map[string]string{"token_id": tokenId} - r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/disable", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// EnableUserAccessToken will enable a user access token by id. Must have the -// 'create_user_access_token' permission and if enabling for another user, must have the -// 'edit_other_users' permission. -func (c *Client4) EnableUserAccessToken(tokenId string) (bool, *Response) { - requestBody := map[string]string{"token_id": tokenId} - r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/enable", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// Bots section - -// CreateBot creates a bot in the system based on the provided bot struct. -func (c *Client4) CreateBot(bot *Bot) (*Bot, *Response) { - r, err := c.doApiPostBytes(c.GetBotsRoute(), bot.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return BotFromJson(r.Body), BuildResponse(r) -} - -// PatchBot partially updates a bot. Any missing fields are not updated. -func (c *Client4) PatchBot(userId string, patch *BotPatch) (*Bot, *Response) { - r, err := c.doApiPutBytes(c.GetBotRoute(userId), patch.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return BotFromJson(r.Body), BuildResponse(r) -} - -// GetBot fetches the given, undeleted bot. -func (c *Client4) GetBot(userId string, etag string) (*Bot, *Response) { - r, err := c.DoApiGet(c.GetBotRoute(userId), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return BotFromJson(r.Body), BuildResponse(r) -} - -// GetBot fetches the given bot, even if it is deleted. -func (c *Client4) GetBotIncludeDeleted(userId string, etag string) (*Bot, *Response) { - r, err := c.DoApiGet(c.GetBotRoute(userId)+"?include_deleted="+c.boolString(true), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return BotFromJson(r.Body), BuildResponse(r) -} - -// GetBots fetches the given page of bots, excluding deleted. -func (c *Client4) GetBots(page, perPage int, etag string) ([]*Bot, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetBotsRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return BotListFromJson(r.Body), BuildResponse(r) -} - -// GetBotsIncludeDeleted fetches the given page of bots, including deleted. -func (c *Client4) GetBotsIncludeDeleted(page, perPage int, etag string) ([]*Bot, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&include_deleted="+c.boolString(true), page, perPage) - r, err := c.DoApiGet(c.GetBotsRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return BotListFromJson(r.Body), BuildResponse(r) -} - -// GetBotsOrphaned fetches the given page of bots, only including orphanded bots. -func (c *Client4) GetBotsOrphaned(page, perPage int, etag string) ([]*Bot, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&only_orphaned="+c.boolString(true), page, perPage) - r, err := c.DoApiGet(c.GetBotsRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return BotListFromJson(r.Body), BuildResponse(r) -} - -// DisableBot disables the given bot in the system. -func (c *Client4) DisableBot(botUserId string) (*Bot, *Response) { - r, err := c.doApiPostBytes(c.GetBotRoute(botUserId)+"/disable", nil) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return BotFromJson(r.Body), BuildResponse(r) -} - -// EnableBot disables the given bot in the system. -func (c *Client4) EnableBot(botUserId string) (*Bot, *Response) { - r, err := c.doApiPostBytes(c.GetBotRoute(botUserId)+"/enable", nil) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return BotFromJson(r.Body), BuildResponse(r) -} - -// AssignBot assigns the given bot to the given user -func (c *Client4) AssignBot(botUserId, newOwnerId string) (*Bot, *Response) { - r, err := c.doApiPostBytes(c.GetBotRoute(botUserId)+"/assign/"+newOwnerId, nil) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return BotFromJson(r.Body), BuildResponse(r) -} - -// SetBotIconImage sets LHS bot icon image. -func (c *Client4) SetBotIconImage(botUserId string, data []byte) (bool, *Response) { - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - - part, err := writer.CreateFormFile("image", "icon.svg") - if err != nil { - return false, &Response{Error: NewAppError("SetBotIconImage", "model.client.set_bot_icon_image.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { - return false, &Response{Error: NewAppError("SetBotIconImage", "model.client.set_bot_icon_image.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if err = writer.Close(); err != nil { - return false, &Response{Error: NewAppError("SetBotIconImage", "model.client.set_bot_icon_image.writer.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - rq, err := http.NewRequest("POST", c.ApiUrl+c.GetBotRoute(botUserId)+"/icon", bytes.NewReader(body.Bytes())) - if err != nil { - return false, &Response{Error: NewAppError("SetBotIconImage", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - rq.Header.Set("Content-Type", writer.FormDataContentType()) - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetBotRoute(botUserId)+"/icon", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)} - } - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } - - return CheckStatusOK(rp), BuildResponse(rp) -} - -// GetBotIconImage gets LHS bot icon image. Must be logged in. -func (c *Client4) GetBotIconImage(botUserId string) ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetBotRoute(botUserId)+"/icon", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetBotIconImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } - return data, BuildResponse(r) -} - -// DeleteBotIconImage deletes LHS bot icon image. Must be logged in. -func (c *Client4) DeleteBotIconImage(botUserId string) (bool, *Response) { - r, appErr := c.DoApiDelete(c.GetBotRoute(botUserId) + "/icon") - if appErr != nil { - return false, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// Team Section - -// CreateTeam creates a team in the system based on the provided team struct. -func (c *Client4) CreateTeam(team *Team) (*Team, *Response) { - r, err := c.DoApiPost(c.GetTeamsRoute(), team.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) -} - -// GetTeam returns a team based on the provided team id string. -func (c *Client4) GetTeam(teamId, etag string) (*Team, *Response) { - r, err := c.DoApiGet(c.GetTeamRoute(teamId), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) -} - -// GetAllTeams returns all teams based on permissions. -func (c *Client4) GetAllTeams(etag string, page int, perPage int) ([]*Team, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) -} - -// GetAllTeamsWithTotalCount returns all teams based on permissions. -func (c *Client4) GetAllTeamsWithTotalCount(etag string, page int, perPage int) ([]*Team, int64, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&include_total_count="+c.boolString(true), page, perPage) - r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag) - if err != nil { - return nil, 0, BuildErrorResponse(r, err) - } - defer closeBody(r) - teamsListWithCount := TeamsWithCountFromJson(r.Body) - return teamsListWithCount.Teams, teamsListWithCount.TotalCount, BuildResponse(r) -} - -// GetAllTeamsExcludePolicyConstrained returns all teams which are not part of a data retention policy. -// Must be a system administrator. -func (c *Client4) GetAllTeamsExcludePolicyConstrained(etag string, page int, perPage int) ([]*Team, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&exclude_policy_constrained=%v", page, perPage, true) - r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) -} - -// GetTeamByName returns a team based on the provided team name string. -func (c *Client4) GetTeamByName(name, etag string) (*Team, *Response) { - r, err := c.DoApiGet(c.GetTeamByNameRoute(name), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) -} - -// SearchTeams returns teams matching the provided search term. -func (c *Client4) SearchTeams(search *TeamSearch) ([]*Team, *Response) { - r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) -} - -// SearchTeamsPaged returns a page of teams and the total count matching the provided search term. -func (c *Client4) SearchTeamsPaged(search *TeamSearch) ([]*Team, int64, *Response) { - if search.Page == nil { - search.Page = NewInt(0) - } - if search.PerPage == nil { - search.PerPage = NewInt(100) - } - r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson()) - if err != nil { - return nil, 0, BuildErrorResponse(r, err) - } - defer closeBody(r) - twc := TeamsWithCountFromJson(r.Body) - return twc.Teams, twc.TotalCount, BuildResponse(r) -} - -// TeamExists returns true or false if the team exist or not. -func (c *Client4) TeamExists(name, etag string) (bool, *Response) { - r, err := c.DoApiGet(c.GetTeamByNameRoute(name)+"/exists", etag) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapBoolFromJson(r.Body)["exists"], BuildResponse(r) -} - -// GetTeamsForUser returns a list of teams a user is on. Must be logged in as the user -// or be a system administrator. -func (c *Client4) GetTeamsForUser(userId, etag string) ([]*Team, *Response) { - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams", etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) -} - -// GetTeamMember returns a team member based on the provided team and user id strings. -func (c *Client4) GetTeamMember(teamId, userId, etag string) (*TeamMember, *Response) { - r, err := c.DoApiGet(c.GetTeamMemberRoute(teamId, userId), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamMemberFromJson(r.Body), BuildResponse(r) -} - -// UpdateTeamMemberRoles will update the roles on a team for a user. -func (c *Client4) UpdateTeamMemberRoles(teamId, userId, newRoles string) (bool, *Response) { - requestBody := map[string]string{"roles": newRoles} - r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/roles", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UpdateTeamMemberSchemeRoles will update the scheme-derived roles on a team for a user. -func (c *Client4) UpdateTeamMemberSchemeRoles(teamId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) { - r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/schemeRoles", schemeRoles.ToJson()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UpdateTeam will update a team. -func (c *Client4) UpdateTeam(team *Team) (*Team, *Response) { - r, err := c.DoApiPut(c.GetTeamRoute(team.Id), team.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) -} - -// PatchTeam partially updates a team. Any missing fields are not updated. -func (c *Client4) PatchTeam(teamId string, patch *TeamPatch) (*Team, *Response) { - r, err := c.DoApiPut(c.GetTeamRoute(teamId)+"/patch", patch.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) -} - -// RestoreTeam restores a previously deleted team. -func (c *Client4) RestoreTeam(teamId string) (*Team, *Response) { - r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/restore", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) -} - -// RegenerateTeamInviteId requests a new invite ID to be generated. -func (c *Client4) RegenerateTeamInviteId(teamId string) (*Team, *Response) { - r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/regenerate_invite_id", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) -} - -// SoftDeleteTeam deletes the team softly (archive only, not permanent delete). -func (c *Client4) SoftDeleteTeam(teamId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetTeamRoute(teamId)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// PermanentDeleteTeam deletes the team, should only be used when needed for -// compliance and the like. -func (c *Client4) PermanentDeleteTeam(teamId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "?permanent=" + c.boolString(true)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UpdateTeamPrivacy modifies the team type (model.TEAM_OPEN <--> model.TEAM_INVITE) and sets -// the corresponding AllowOpenInvite appropriately. -func (c *Client4) UpdateTeamPrivacy(teamId string, privacy string) (*Team, *Response) { - requestBody := map[string]string{"privacy": privacy} - r, err := c.DoApiPut(c.GetTeamRoute(teamId)+"/privacy", MapToJson(requestBody)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) -} - -// GetTeamMembers returns team members based on the provided team id string. -func (c *Client4) GetTeamMembers(teamId string, page int, perPage int, etag string) ([]*TeamMember, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) -} - -// GetTeamMembersWithoutDeletedUsers returns team members based on the provided team id string. Additional parameters of sort and exclude_deleted_users accepted as well -// Could not add it to above function due to it be a breaking change. -func (c *Client4) GetTeamMembersSortAndWithoutDeletedUsers(teamId string, page int, perPage int, sort string, exclude_deleted_users bool, etag string) ([]*TeamMember, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&sort=%v&exclude_deleted_users=%v", page, perPage, sort, exclude_deleted_users) - r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) -} - -// GetTeamMembersForUser returns the team members for a user. -func (c *Client4) GetTeamMembersForUser(userId string, etag string) ([]*TeamMember, *Response) { - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/members", etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) -} - -// GetTeamMembersByIds will return an array of team members based on the -// team id and a list of user ids provided. Must be authenticated. -func (c *Client4) GetTeamMembersByIds(teamId string, userIds []string) ([]*TeamMember, *Response) { - r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) -} - -// AddTeamMember adds user to a team and return a team member. -func (c *Client4) AddTeamMember(teamId, userId string) (*TeamMember, *Response) { - member := &TeamMember{TeamId: teamId, UserId: userId} - r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId), member.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamMemberFromJson(r.Body), BuildResponse(r) -} - -// AddTeamMemberFromInvite adds a user to a team and return a team member using an invite id -// or an invite token/data pair. -func (c *Client4) AddTeamMemberFromInvite(token, inviteId string) (*TeamMember, *Response) { - var query string - - if inviteId != "" { - query += fmt.Sprintf("?invite_id=%v", inviteId) - } - - if token != "" { - query += fmt.Sprintf("?token=%v", token) - } - - r, err := c.DoApiPost(c.GetTeamsRoute()+"/members/invite"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamMemberFromJson(r.Body), BuildResponse(r) -} - -// AddTeamMembers adds a number of users to a team and returns the team members. -func (c *Client4) AddTeamMembers(teamId string, userIds []string) ([]*TeamMember, *Response) { - var members []*TeamMember - for _, userId := range userIds { - member := &TeamMember{TeamId: teamId, UserId: userId} - members = append(members, member) - } - - r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch", TeamMembersToJson(members)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamMembersFromJson(r.Body), BuildResponse(r) -} - -// AddTeamMembers adds a number of users to a team and returns the team members. -func (c *Client4) AddTeamMembersGracefully(teamId string, userIds []string) ([]*TeamMemberWithError, *Response) { - var members []*TeamMember - for _, userId := range userIds { - member := &TeamMember{TeamId: teamId, UserId: userId} - members = append(members, member) - } - - r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch?graceful="+c.boolString(true), TeamMembersToJson(members)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamMembersWithErrorFromJson(r.Body), BuildResponse(r) -} - -// RemoveTeamMember will remove a user from a team. -func (c *Client4) RemoveTeamMember(teamId, userId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetTeamStats returns a team stats based on the team id string. -// Must be authenticated. -func (c *Client4) GetTeamStats(teamId, etag string) (*TeamStats, *Response) { - r, err := c.DoApiGet(c.GetTeamStatsRoute(teamId), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamStatsFromJson(r.Body), BuildResponse(r) -} - -// GetTotalUsersStats returns a total system user stats. -// Must be authenticated. -func (c *Client4) GetTotalUsersStats(etag string) (*UsersStats, *Response) { - r, err := c.DoApiGet(c.GetTotalUsersStatsRoute(), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UsersStatsFromJson(r.Body), BuildResponse(r) -} - -// GetTeamUnread will return a TeamUnread object that contains the amount of -// unread messages and mentions the user has for the specified team. -// Must be authenticated. -func (c *Client4) GetTeamUnread(teamId, userId string) (*TeamUnread, *Response) { - r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/unread", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamUnreadFromJson(r.Body), BuildResponse(r) -} - -// ImportTeam will import an exported team from other app into a existing team. -func (c *Client4) ImportTeam(data []byte, filesize int, importFrom, filename, teamId string) (map[string]string, *Response) { - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - - part, err := writer.CreateFormFile("file", filename) - if err != nil { - return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { - return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - part, err = writer.CreateFormField("filesize") - if err != nil { - return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if _, err = io.Copy(part, strings.NewReader(strconv.Itoa(filesize))); err != nil { - return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - part, err = writer.CreateFormField("importFrom") - if err != nil { - return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if _, err := io.Copy(part, strings.NewReader(importFrom)); err != nil { - return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if err := writer.Close(); err != nil { - return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - return c.DoUploadImportTeam(c.GetTeamImportRoute(teamId), body.Bytes(), writer.FormDataContentType()) -} - -// InviteUsersToTeam invite users by email to the team. -func (c *Client4) InviteUsersToTeam(teamId string, userEmails []string) (bool, *Response) { - r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email", ArrayToJson(userEmails)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// InviteGuestsToTeam invite guest by email to some channels in a team. -func (c *Client4) InviteGuestsToTeam(teamId string, userEmails []string, channels []string, message string) (bool, *Response) { - guestsInvite := GuestsInvite{ - Emails: userEmails, - Channels: channels, - Message: message, - } - r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite-guests/email", guestsInvite.ToJson()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// InviteUsersToTeam invite users by email to the team. -func (c *Client4) InviteUsersToTeamGracefully(teamId string, userEmails []string) ([]*EmailInviteWithError, *Response) { - r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email?graceful="+c.boolString(true), ArrayToJson(userEmails)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return EmailInviteWithErrorFromJson(r.Body), BuildResponse(r) -} - -// InviteGuestsToTeam invite guest by email to some channels in a team. -func (c *Client4) InviteGuestsToTeamGracefully(teamId string, userEmails []string, channels []string, message string) ([]*EmailInviteWithError, *Response) { - guestsInvite := GuestsInvite{ - Emails: userEmails, - Channels: channels, - Message: message, - } - r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite-guests/email?graceful="+c.boolString(true), guestsInvite.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return EmailInviteWithErrorFromJson(r.Body), BuildResponse(r) -} - -// InvalidateEmailInvites will invalidate active email invitations that have not been accepted by the user. -func (c *Client4) InvalidateEmailInvites() (bool, *Response) { - r, err := c.DoApiDelete(c.GetTeamsRoute() + "/invites/email") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetTeamInviteInfo returns a team object from an invite id containing sanitized information. -func (c *Client4) GetTeamInviteInfo(inviteId string) (*Team, *Response) { - r, err := c.DoApiGet(c.GetTeamsRoute()+"/invite/"+inviteId, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamFromJson(r.Body), BuildResponse(r) -} - -// SetTeamIcon sets team icon of the team. -func (c *Client4) SetTeamIcon(teamId string, data []byte) (bool, *Response) { - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - - part, err := writer.CreateFormFile("image", "teamIcon.png") - if err != nil { - return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { - return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if err = writer.Close(); err != nil { - return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.writer.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - rq, err := http.NewRequest("POST", c.ApiUrl+c.GetTeamRoute(teamId)+"/image", bytes.NewReader(body.Bytes())) - if err != nil { - return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - rq.Header.Set("Content-Type", writer.FormDataContentType()) - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - // set to http.StatusForbidden(403) - return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetTeamRoute(teamId)+"/image", "model.client.connecting.app_error", nil, err.Error(), 403)} - } - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } - - return CheckStatusOK(rp), BuildResponse(rp) -} - -// GetTeamIcon gets the team icon of the team. -func (c *Client4) GetTeamIcon(teamId, etag string) ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetTeamRoute(teamId)+"/image", etag) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetTeamIcon", "model.client.get_team_icon.app_error", nil, err.Error(), r.StatusCode)) - } - return data, BuildResponse(r) -} - -// RemoveTeamIcon updates LastTeamIconUpdate to 0 which indicates team icon is removed. -func (c *Client4) RemoveTeamIcon(teamId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "/image") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// Channel Section - -// GetAllChannels get all the channels. Must be a system administrator. -func (c *Client4) GetAllChannels(page int, perPage int, etag string) (*ChannelListWithTeamData, *Response) { - return c.getAllChannels(page, perPage, etag, ChannelSearchOpts{}) -} - -// GetAllChannelsIncludeDeleted get all the channels. Must be a system administrator. -func (c *Client4) GetAllChannelsIncludeDeleted(page int, perPage int, etag string) (*ChannelListWithTeamData, *Response) { - return c.getAllChannels(page, perPage, etag, ChannelSearchOpts{IncludeDeleted: true}) -} - -// GetAllChannelsExcludePolicyConstrained gets all channels which are not part of a data retention policy. -// Must be a system administrator. -func (c *Client4) GetAllChannelsExcludePolicyConstrained(page, perPage int, etag string) (*ChannelListWithTeamData, *Response) { - return c.getAllChannels(page, perPage, etag, ChannelSearchOpts{ExcludePolicyConstrained: true}) -} - -func (c *Client4) getAllChannels(page int, perPage int, etag string, opts ChannelSearchOpts) (*ChannelListWithTeamData, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&include_deleted=%v&exclude_policy_constrained=%v", - page, perPage, opts.IncludeDeleted, opts.ExcludePolicyConstrained) - r, err := c.DoApiGet(c.GetChannelsRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelListWithTeamDataFromJson(r.Body), BuildResponse(r) -} - -// GetAllChannelsWithCount get all the channels including the total count. Must be a system administrator. -func (c *Client4) GetAllChannelsWithCount(page int, perPage int, etag string) (*ChannelListWithTeamData, int64, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&include_total_count="+c.boolString(true), page, perPage) - r, err := c.DoApiGet(c.GetChannelsRoute()+query, etag) - if err != nil { - return nil, 0, BuildErrorResponse(r, err) - } - defer closeBody(r) - cwc := ChannelsWithCountFromJson(r.Body) - return cwc.Channels, cwc.TotalCount, BuildResponse(r) -} - -// CreateChannel creates a channel based on the provided channel struct. -func (c *Client4) CreateChannel(channel *Channel) (*Channel, *Response) { - r, err := c.DoApiPost(c.GetChannelsRoute(), channel.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// UpdateChannel updates a channel based on the provided channel struct. -func (c *Client4) UpdateChannel(channel *Channel) (*Channel, *Response) { - r, err := c.DoApiPut(c.GetChannelRoute(channel.Id), channel.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// PatchChannel partially updates a channel. Any missing fields are not updated. -func (c *Client4) PatchChannel(channelId string, patch *ChannelPatch) (*Channel, *Response) { - r, err := c.DoApiPut(c.GetChannelRoute(channelId)+"/patch", patch.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// ConvertChannelToPrivate converts public to private channel. -func (c *Client4) ConvertChannelToPrivate(channelId string) (*Channel, *Response) { - r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/convert", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// UpdateChannelPrivacy updates channel privacy -func (c *Client4) UpdateChannelPrivacy(channelId string, privacy string) (*Channel, *Response) { - requestBody := map[string]string{"privacy": privacy} - r, err := c.DoApiPut(c.GetChannelRoute(channelId)+"/privacy", MapToJson(requestBody)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// RestoreChannel restores a previously deleted channel. Any missing fields are not updated. -func (c *Client4) RestoreChannel(channelId string) (*Channel, *Response) { - r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/restore", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// CreateDirectChannel creates a direct message channel based on the two user -// ids provided. -func (c *Client4) CreateDirectChannel(userId1, userId2 string) (*Channel, *Response) { - requestBody := []string{userId1, userId2} - r, err := c.DoApiPost(c.GetChannelsRoute()+"/direct", ArrayToJson(requestBody)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// CreateGroupChannel creates a group message channel based on userIds provided. -func (c *Client4) CreateGroupChannel(userIds []string) (*Channel, *Response) { - r, err := c.DoApiPost(c.GetChannelsRoute()+"/group", ArrayToJson(userIds)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// GetChannel returns a channel based on the provided channel id string. -func (c *Client4) GetChannel(channelId, etag string) (*Channel, *Response) { - r, err := c.DoApiGet(c.GetChannelRoute(channelId), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// GetChannelStats returns statistics for a channel. -func (c *Client4) GetChannelStats(channelId string, etag string) (*ChannelStats, *Response) { - r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/stats", etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelStatsFromJson(r.Body), BuildResponse(r) -} - -// GetChannelMembersTimezones gets a list of timezones for a channel. -func (c *Client4) GetChannelMembersTimezones(channelId string) ([]string, *Response) { - r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/timezones", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ArrayFromJson(r.Body), BuildResponse(r) -} - -// GetPinnedPosts gets a list of pinned posts. -func (c *Client4) GetPinnedPosts(channelId string, etag string) (*PostList, *Response) { - r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) -} - -// GetPrivateChannelsForTeam returns a list of private channels based on the provided team id string. -func (c *Client4) GetPrivateChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) { - query := fmt.Sprintf("/private?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) -} - -// GetPublicChannelsForTeam returns a list of public channels based on the provided team id string. -func (c *Client4) GetPublicChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) -} - -// GetDeletedChannelsForTeam returns a list of public channels based on the provided team id string. -func (c *Client4) GetDeletedChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) { - query := fmt.Sprintf("/deleted?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) -} - -// GetPublicChannelsByIdsForTeam returns a list of public channels based on provided team id string. -func (c *Client4) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) ([]*Channel, *Response) { - r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/ids", ArrayToJson(channelIds)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) -} - -// GetChannelsForTeamForUser returns a list channels of on a team for a user. -func (c *Client4) GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool, etag string) ([]*Channel, *Response) { - r, err := c.DoApiGet(c.GetChannelsForTeamForUserRoute(teamId, userId, includeDeleted), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) -} - -// GetChannelsForTeamAndUserWithLastDeleteAt returns a list channels of a team for a user, additionally filtered with lastDeleteAt. This does not have any effect if includeDeleted is set to false. -func (c *Client4) GetChannelsForTeamAndUserWithLastDeleteAt(teamId, userId string, includeDeleted bool, lastDeleteAt int, etag string) ([]*Channel, *Response) { - route := fmt.Sprintf(c.GetUserRoute(userId) + c.GetTeamRoute(teamId) + "/channels") - route += fmt.Sprintf("?include_deleted=%v&last_delete_at=%d", includeDeleted, lastDeleteAt) - r, err := c.DoApiGet(route, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) -} - -// SearchChannels returns the channels on a team matching the provided search term. -func (c *Client4) SearchChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response) { - r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search", search.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) -} - -// SearchArchivedChannels returns the archived channels on a team matching the provided search term. -func (c *Client4) SearchArchivedChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response) { - r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search_archived", search.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) -} - -// SearchAllChannels search in all the channels. Must be a system administrator. -func (c *Client4) SearchAllChannels(search *ChannelSearch) (*ChannelListWithTeamData, *Response) { - r, err := c.DoApiPost(c.GetChannelsRoute()+"/search", search.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelListWithTeamDataFromJson(r.Body), BuildResponse(r) -} - -// SearchAllChannelsPaged searches all the channels and returns the results paged with the total count. -func (c *Client4) SearchAllChannelsPaged(search *ChannelSearch) (*ChannelsWithCount, *Response) { - r, err := c.DoApiPost(c.GetChannelsRoute()+"/search", search.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelsWithCountFromJson(r.Body), BuildResponse(r) -} - -// SearchGroupChannels returns the group channels of the user whose members' usernames match the search term. -func (c *Client4) SearchGroupChannels(search *ChannelSearch) ([]*Channel, *Response) { - r, err := c.DoApiPost(c.GetChannelsRoute()+"/group/search", search.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelSliceFromJson(r.Body), BuildResponse(r) -} - -// DeleteChannel deletes channel based on the provided channel id string. -func (c *Client4) DeleteChannel(channelId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetChannelRoute(channelId)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// PermanentDeleteChannel deletes a channel based on the provided channel id string. -func (c *Client4) PermanentDeleteChannel(channelId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetChannelRoute(channelId) + "?permanent=" + c.boolString(true)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// MoveChannel moves the channel to the destination team. -func (c *Client4) MoveChannel(channelId, teamId string, force bool) (*Channel, *Response) { - requestBody := map[string]interface{}{ - "team_id": teamId, - "force": force, - } - r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/move", StringInterfaceToJson(requestBody)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// GetChannelByName returns a channel based on the provided channel name and team id strings. -func (c *Client4) GetChannelByName(channelName, teamId string, etag string) (*Channel, *Response) { - r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// GetChannelByNameIncludeDeleted returns a channel based on the provided channel name and team id strings. Other then GetChannelByName it will also return deleted channels. -func (c *Client4) GetChannelByNameIncludeDeleted(channelName, teamId string, etag string) (*Channel, *Response) { - r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId)+"?include_deleted="+c.boolString(true), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// GetChannelByNameForTeamName returns a channel based on the provided channel name and team name strings. -func (c *Client4) GetChannelByNameForTeamName(channelName, teamName string, etag string) (*Channel, *Response) { - r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// GetChannelByNameForTeamNameIncludeDeleted returns a channel based on the provided channel name and team name strings. Other then GetChannelByNameForTeamName it will also return deleted channels. -func (c *Client4) GetChannelByNameForTeamNameIncludeDeleted(channelName, teamName string, etag string) (*Channel, *Response) { - r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName)+"?include_deleted="+c.boolString(true), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelFromJson(r.Body), BuildResponse(r) -} - -// GetChannelMembers gets a page of channel members. -func (c *Client4) GetChannelMembers(channelId string, page, perPage int, etag string) (*ChannelMembers, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetChannelMembersRoute(channelId)+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelMembersFromJson(r.Body), BuildResponse(r) -} - -// GetChannelMembersByIds gets the channel members in a channel for a list of user ids. -func (c *Client4) GetChannelMembersByIds(channelId string, userIds []string) (*ChannelMembers, *Response) { - r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"/ids", ArrayToJson(userIds)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelMembersFromJson(r.Body), BuildResponse(r) -} - -// GetChannelMember gets a channel member. -func (c *Client4) GetChannelMember(channelId, userId, etag string) (*ChannelMember, *Response) { - r, err := c.DoApiGet(c.GetChannelMemberRoute(channelId, userId), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelMemberFromJson(r.Body), BuildResponse(r) -} - -// GetChannelMembersForUser gets all the channel members for a user on a team. -func (c *Client4) GetChannelMembersForUser(userId, teamId, etag string) (*ChannelMembers, *Response) { - r, err := c.DoApiGet(fmt.Sprintf(c.GetUserRoute(userId)+"/teams/%v/channels/members", teamId), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelMembersFromJson(r.Body), BuildResponse(r) -} - -// ViewChannel performs a view action for a user. Synonymous with switching channels or marking channels as read by a user. -func (c *Client4) ViewChannel(userId string, view *ChannelView) (*ChannelViewResponse, *Response) { - url := fmt.Sprintf(c.GetChannelsRoute()+"/members/%v/view", userId) - r, err := c.DoApiPost(url, view.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelViewResponseFromJson(r.Body), BuildResponse(r) -} - -// GetChannelUnread will return a ChannelUnread object that contains the number of -// unread messages and mentions for a user. -func (c *Client4) GetChannelUnread(channelId, userId string) (*ChannelUnread, *Response) { - r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/unread", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelUnreadFromJson(r.Body), BuildResponse(r) -} - -// UpdateChannelRoles will update the roles on a channel for a user. -func (c *Client4) UpdateChannelRoles(channelId, userId, roles string) (bool, *Response) { - requestBody := map[string]string{"roles": roles} - r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/roles", MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UpdateChannelMemberSchemeRoles will update the scheme-derived roles on a channel for a user. -func (c *Client4) UpdateChannelMemberSchemeRoles(channelId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) { - r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/schemeRoles", schemeRoles.ToJson()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UpdateChannelNotifyProps will update the notification properties on a channel for a user. -func (c *Client4) UpdateChannelNotifyProps(channelId, userId string, props map[string]string) (bool, *Response) { - r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/notify_props", MapToJson(props)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// AddChannelMember adds user to channel and return a channel member. -func (c *Client4) AddChannelMember(channelId, userId string) (*ChannelMember, *Response) { - requestBody := map[string]string{"user_id": userId} - r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelMemberFromJson(r.Body), BuildResponse(r) -} - -// AddChannelMemberWithRootId adds user to channel and return a channel member. Post add to channel message has the postRootId. -func (c *Client4) AddChannelMemberWithRootId(channelId, userId, postRootId string) (*ChannelMember, *Response) { - requestBody := map[string]string{"user_id": userId, "post_root_id": postRootId} - r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelMemberFromJson(r.Body), BuildResponse(r) -} - -// RemoveUserFromChannel will delete the channel member object for a user, effectively removing the user from a channel. -func (c *Client4) RemoveUserFromChannel(channelId, userId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetChannelMemberRoute(channelId, userId)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// AutocompleteChannelsForTeam will return an ordered list of channels autocomplete suggestions. -func (c *Client4) AutocompleteChannelsForTeam(teamId, name string) (*ChannelList, *Response) { - query := fmt.Sprintf("?name=%v", name) - r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/autocomplete"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelListFromJson(r.Body), BuildResponse(r) -} - -// AutocompleteChannelsForTeamForSearch will return an ordered list of your channels autocomplete suggestions. -func (c *Client4) AutocompleteChannelsForTeamForSearch(teamId, name string) (*ChannelList, *Response) { - query := fmt.Sprintf("?name=%v", name) - r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/search_autocomplete"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelListFromJson(r.Body), BuildResponse(r) -} - -// Post Section - -// CreatePost creates a post based on the provided post struct. -func (c *Client4) CreatePost(post *Post) (*Post, *Response) { - r, err := c.DoApiPost(c.GetPostsRoute(), post.ToUnsanitizedJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) -} - -// CreatePostEphemeral creates a ephemeral post based on the provided post struct which is send to the given user id. -func (c *Client4) CreatePostEphemeral(post *PostEphemeral) (*Post, *Response) { - r, err := c.DoApiPost(c.GetPostsEphemeralRoute(), post.ToUnsanitizedJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) -} - -// UpdatePost updates a post based on the provided post struct. -func (c *Client4) UpdatePost(postId string, post *Post) (*Post, *Response) { - r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToUnsanitizedJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) -} - -// PatchPost partially updates a post. Any missing fields are not updated. -func (c *Client4) PatchPost(postId string, patch *PostPatch) (*Post, *Response) { - r, err := c.DoApiPut(c.GetPostRoute(postId)+"/patch", patch.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) -} - -// SetPostUnread marks channel where post belongs as unread on the time of the provided post. -func (c *Client4) SetPostUnread(userId string, postId string, collapsedThreadsSupported bool) *Response { - b, _ := json.Marshal(map[string]bool{"collapsed_threads_supported": collapsedThreadsSupported}) - r, err := c.DoApiPost(c.GetUserRoute(userId)+c.GetPostRoute(postId)+"/set_unread", string(b)) - if err != nil { - return BuildErrorResponse(r, err) - } - defer closeBody(r) - return BuildResponse(r) -} - -// PinPost pin a post based on provided post id string. -func (c *Client4) PinPost(postId string) (bool, *Response) { - r, err := c.DoApiPost(c.GetPostRoute(postId)+"/pin", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UnpinPost unpin a post based on provided post id string. -func (c *Client4) UnpinPost(postId string) (bool, *Response) { - r, err := c.DoApiPost(c.GetPostRoute(postId)+"/unpin", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetPost gets a single post. -func (c *Client4) GetPost(postId string, etag string) (*Post, *Response) { - r, err := c.DoApiGet(c.GetPostRoute(postId), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostFromJson(r.Body), BuildResponse(r) -} - -// DeletePost deletes a post from the provided post id string. -func (c *Client4) DeletePost(postId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetPostRoute(postId)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetPostThread gets a post with all the other posts in the same thread. -func (c *Client4) GetPostThread(postId string, etag string, collapsedThreads bool) (*PostList, *Response) { - url := c.GetPostRoute(postId) + "/thread" - if collapsedThreads { - url += "?collapsedThreads=true" - } - r, err := c.DoApiGet(url, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) -} - -// GetPostsForChannel gets a page of posts with an array for ordering for a channel. -func (c *Client4) GetPostsForChannel(channelId string, page, perPage int, etag string, collapsedThreads bool) (*PostList, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - if collapsedThreads { - query += "&collapsedThreads=true" - } - r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) -} - -// GetFlaggedPostsForUser returns flagged posts of a user based on user id string. -func (c *Client4) GetFlaggedPostsForUser(userId string, page int, perPage int) (*PostList, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) -} - -// GetFlaggedPostsForUserInTeam returns flagged posts in team of a user based on user id string. -func (c *Client4) GetFlaggedPostsForUserInTeam(userId string, teamId string, page int, perPage int) (*PostList, *Response) { - if !IsValidId(teamId) { - return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError("GetFlaggedPostsForUserInTeam", "model.client.get_flagged_posts_in_team.missing_parameter.app_error", nil, "", http.StatusBadRequest)} - } - - query := fmt.Sprintf("?team_id=%v&page=%v&per_page=%v", teamId, page, perPage) - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) -} - -// GetFlaggedPostsForUserInChannel returns flagged posts in channel of a user based on user id string. -func (c *Client4) GetFlaggedPostsForUserInChannel(userId string, channelId string, page int, perPage int) (*PostList, *Response) { - if !IsValidId(channelId) { - return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError("GetFlaggedPostsForUserInChannel", "model.client.get_flagged_posts_in_channel.missing_parameter.app_error", nil, "", http.StatusBadRequest)} - } - - query := fmt.Sprintf("?channel_id=%v&page=%v&per_page=%v", channelId, page, perPage) - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) -} - -// GetPostsSince gets posts created after a specified time as Unix time in milliseconds. -func (c *Client4) GetPostsSince(channelId string, time int64, collapsedThreads bool) (*PostList, *Response) { - query := fmt.Sprintf("?since=%v", time) - if collapsedThreads { - query += "&collapsedThreads=true" - } - r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) -} - -// GetPostsAfter gets a page of posts that were posted after the post provided. -func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, etag string, collapsedThreads bool) (*PostList, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&after=%v", page, perPage, postId) - if collapsedThreads { - query += "&collapsedThreads=true" - } - r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) -} - -// GetPostsBefore gets a page of posts that were posted before the post provided. -func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, etag string, collapsedThreads bool) (*PostList, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&before=%v", page, perPage, postId) - if collapsedThreads { - query += "&collapsedThreads=true" - } - r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) -} - -// GetPostsAroundLastUnread gets a list of posts around last unread post by a user in a channel. -func (c *Client4) GetPostsAroundLastUnread(userId, channelId string, limitBefore, limitAfter int, collapsedThreads bool) (*PostList, *Response) { - query := fmt.Sprintf("?limit_before=%v&limit_after=%v", limitBefore, limitAfter) - if collapsedThreads { - query += "&collapsedThreads=true" - } - r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/posts/unread"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) -} - -// SearchFiles returns any posts with matching terms string. -func (c *Client4) SearchFiles(teamId string, terms string, isOrSearch bool) (*FileInfoList, *Response) { - params := SearchParameter{ - Terms: &terms, - IsOrSearch: &isOrSearch, - } - return c.SearchFilesWithParams(teamId, ¶ms) -} - -// SearchFilesWithParams returns any posts with matching terms string. -func (c *Client4) SearchFilesWithParams(teamId string, params *SearchParameter) (*FileInfoList, *Response) { - r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/files/search", params.SearchParameterToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return FileInfoListFromJson(r.Body), BuildResponse(r) -} - -// SearchPosts returns any posts with matching terms string. -func (c *Client4) SearchPosts(teamId string, terms string, isOrSearch bool) (*PostList, *Response) { - params := SearchParameter{ - Terms: &terms, - IsOrSearch: &isOrSearch, - } - return c.SearchPostsWithParams(teamId, ¶ms) -} - -// SearchPostsWithParams returns any posts with matching terms string. -func (c *Client4) SearchPostsWithParams(teamId string, params *SearchParameter) (*PostList, *Response) { - r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", params.SearchParameterToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostListFromJson(r.Body), BuildResponse(r) -} - -// SearchPostsWithMatches returns any posts with matching terms string, including. -func (c *Client4) SearchPostsWithMatches(teamId string, terms string, isOrSearch bool) (*PostSearchResults, *Response) { - requestBody := map[string]interface{}{"terms": terms, "is_or_search": isOrSearch} - r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", StringInterfaceToJson(requestBody)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PostSearchResultsFromJson(r.Body), BuildResponse(r) -} - -// DoPostAction performs a post action. -func (c *Client4) DoPostAction(postId, actionId string) (bool, *Response) { - r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// DoPostActionWithCookie performs a post action with extra arguments -func (c *Client4) DoPostActionWithCookie(postId, actionId, selected, cookieStr string) (bool, *Response) { - var body []byte - if selected != "" || cookieStr != "" { - body, _ = json.Marshal(DoPostActionRequest{ - SelectedOption: selected, - Cookie: cookieStr, - }) - } - r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, string(body)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// OpenInteractiveDialog sends a WebSocket event to a user's clients to -// open interactive dialogs, based on the provided trigger ID and other -// provided data. Used with interactive message buttons, menus and -// slash commands. -func (c *Client4) OpenInteractiveDialog(request OpenDialogRequest) (bool, *Response) { - b, _ := json.Marshal(request) - r, err := c.DoApiPost("/actions/dialogs/open", string(b)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// SubmitInteractiveDialog will submit the provided dialog data to the integration -// configured by the URL. Used with the interactive dialogs integration feature. -func (c *Client4) SubmitInteractiveDialog(request SubmitDialogRequest) (*SubmitDialogResponse, *Response) { - b, _ := json.Marshal(request) - r, err := c.DoApiPost("/actions/dialogs/submit", string(b)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - - var resp SubmitDialogResponse - json.NewDecoder(r.Body).Decode(&resp) - return &resp, BuildResponse(r) -} - -// UploadFile will upload a file to a channel using a multipart request, to be later attached to a post. -// This method is functionally equivalent to Client4.UploadFileAsRequestBody. -func (c *Client4) UploadFile(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) { - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - - part, err := writer.CreateFormField("channel_id") - if err != nil { - return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - _, err = io.Copy(part, strings.NewReader(channelId)) - if err != nil { - return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - part, err = writer.CreateFormFile("files", filename) - if err != nil { - return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - _, err = io.Copy(part, bytes.NewBuffer(data)) - if err != nil { - return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - err = writer.Close() - if err != nil { - return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - return c.DoUploadFile(c.GetFilesRoute(), body.Bytes(), writer.FormDataContentType()) -} - -// UploadFileAsRequestBody will upload a file to a channel as the body of a request, to be later attached -// to a post. This method is functionally equivalent to Client4.UploadFile. -func (c *Client4) UploadFileAsRequestBody(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) { - return c.DoUploadFile(c.GetFilesRoute()+fmt.Sprintf("?channel_id=%v&filename=%v", url.QueryEscape(channelId), url.QueryEscape(filename)), data, http.DetectContentType(data)) -} - -// GetFile gets the bytes for a file by id. -func (c *Client4) GetFile(fileId string) ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetFileRoute(fileId), "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } - return data, BuildResponse(r) -} - -// DownloadFile gets the bytes for a file by id, optionally adding headers to force the browser to download it. -func (c *Client4) DownloadFile(fileId string, download bool) ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("?download=%v", download), "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("DownloadFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } - return data, BuildResponse(r) -} - -// GetFileThumbnail gets the bytes for a file by id. -func (c *Client4) GetFileThumbnail(fileId string) ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+"/thumbnail", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } - return data, BuildResponse(r) -} - -// DownloadFileThumbnail gets the bytes for a file by id, optionally adding headers to force the browser to download it. -func (c *Client4) DownloadFileThumbnail(fileId string, download bool) ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/thumbnail?download=%v", download), "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("DownloadFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } - return data, BuildResponse(r) -} - -// GetFileLink gets the public link of a file by id. -func (c *Client4) GetFileLink(fileId string) (string, *Response) { - r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/link", "") - if err != nil { - return "", BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body)["link"], BuildResponse(r) -} - -// GetFilePreview gets the bytes for a file by id. -func (c *Client4) GetFilePreview(fileId string) ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+"/preview", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } - return data, BuildResponse(r) -} - -// DownloadFilePreview gets the bytes for a file by id. -func (c *Client4) DownloadFilePreview(fileId string, download bool) ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/preview?download=%v", download), "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("DownloadFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } - return data, BuildResponse(r) -} - -// GetFileInfo gets all the file info objects. -func (c *Client4) GetFileInfo(fileId string) (*FileInfo, *Response) { - r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/info", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return FileInfoFromJson(r.Body), BuildResponse(r) -} - -// GetFileInfosForPost gets all the file info objects attached to a post. -func (c *Client4) GetFileInfosForPost(postId string, etag string) ([]*FileInfo, *Response) { - r, err := c.DoApiGet(c.GetPostRoute(postId)+"/files/info", etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return FileInfosFromJson(r.Body), BuildResponse(r) -} - -// General/System Section - -// GenerateSupportPacket downloads the generated support packet -func (c *Client4) GenerateSupportPacket() ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetSystemRoute()+"/support_packet", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_job_result_file.app_error", nil, err.Error(), r.StatusCode)) - } - return data, BuildResponse(r) -} - -// GetPing will return ok if the running goRoutines are below the threshold and unhealthy for above. -func (c *Client4) GetPing() (string, *Response) { - r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", "") - if r != nil && r.StatusCode == 500 { - defer r.Body.Close() - return STATUS_UNHEALTHY, BuildErrorResponse(r, err) - } - if err != nil { - return "", BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body)["status"], BuildResponse(r) -} - -// GetPingWithServerStatus will return ok if several basic server health checks -// all pass successfully. -func (c *Client4) GetPingWithServerStatus() (string, *Response) { - r, err := c.DoApiGet(c.GetSystemRoute()+"/ping?get_server_status="+c.boolString(true), "") - if r != nil && r.StatusCode == 500 { - defer r.Body.Close() - return STATUS_UNHEALTHY, BuildErrorResponse(r, err) - } - if err != nil { - return "", BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body)["status"], BuildResponse(r) -} - -// GetPingWithFullServerStatus will return the full status if several basic server -// health checks all pass successfully. -func (c *Client4) GetPingWithFullServerStatus() (map[string]string, *Response) { - r, err := c.DoApiGet(c.GetSystemRoute()+"/ping?get_server_status="+c.boolString(true), "") - if r != nil && r.StatusCode == 500 { - defer r.Body.Close() - return map[string]string{"status": STATUS_UNHEALTHY}, BuildErrorResponse(r, err) - } - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) -} - -// TestEmail will attempt to connect to the configured SMTP server. -func (c *Client4) TestEmail(config *Config) (bool, *Response) { - r, err := c.DoApiPost(c.GetTestEmailRoute(), config.ToJson()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// TestSiteURL will test the validity of a site URL. -func (c *Client4) TestSiteURL(siteURL string) (bool, *Response) { - requestBody := make(map[string]string) - requestBody["site_url"] = siteURL - r, err := c.DoApiPost(c.GetTestSiteURLRoute(), MapToJson(requestBody)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// TestS3Connection will attempt to connect to the AWS S3. -func (c *Client4) TestS3Connection(config *Config) (bool, *Response) { - r, err := c.DoApiPost(c.GetTestS3Route(), config.ToJson()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetConfig will retrieve the server config with some sanitized items. -func (c *Client4) GetConfig() (*Config, *Response) { - r, err := c.DoApiGet(c.GetConfigRoute(), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ConfigFromJson(r.Body), BuildResponse(r) -} - -// ReloadConfig will reload the server configuration. -func (c *Client4) ReloadConfig() (bool, *Response) { - r, err := c.DoApiPost(c.GetConfigRoute()+"/reload", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetOldClientConfig will retrieve the parts of the server configuration needed by the -// client, formatted in the old format. -func (c *Client4) GetOldClientConfig(etag string) (map[string]string, *Response) { - r, err := c.DoApiGet(c.GetConfigRoute()+"/client?format=old", etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) -} - -// GetEnvironmentConfig will retrieve a map mirroring the server configuration where fields -// are set to true if the corresponding config setting is set through an environment variable. -// Settings that haven't been set through environment variables will be missing from the map. -func (c *Client4) GetEnvironmentConfig() (map[string]interface{}, *Response) { - r, err := c.DoApiGet(c.GetConfigRoute()+"/environment", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return StringInterfaceFromJson(r.Body), BuildResponse(r) -} - -// GetOldClientLicense will retrieve the parts of the server license needed by the -// client, formatted in the old format. -func (c *Client4) GetOldClientLicense(etag string) (map[string]string, *Response) { - r, err := c.DoApiGet(c.GetLicenseRoute()+"/client?format=old", etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) -} - -// DatabaseRecycle will recycle the connections. Discard current connection and get new one. -func (c *Client4) DatabaseRecycle() (bool, *Response) { - r, err := c.DoApiPost(c.GetDatabaseRoute()+"/recycle", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// InvalidateCaches will purge the cache and can affect the performance while is cleaning. -func (c *Client4) InvalidateCaches() (bool, *Response) { - r, err := c.DoApiPost(c.GetCacheRoute()+"/invalidate", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UpdateConfig will update the server configuration. -func (c *Client4) UpdateConfig(config *Config) (*Config, *Response) { - r, err := c.DoApiPut(c.GetConfigRoute(), config.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ConfigFromJson(r.Body), BuildResponse(r) -} - -// MigrateConfig will migrate existing config to the new one. -func (c *Client4) MigrateConfig(from, to string) (bool, *Response) { - m := make(map[string]string, 2) - m["from"] = from - m["to"] = to - r, err := c.DoApiPost(c.GetConfigRoute()+"/migrate", MapToJson(m)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return true, BuildResponse(r) -} - -// UploadLicenseFile will add a license file to the system. -func (c *Client4) UploadLicenseFile(data []byte) (bool, *Response) { - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - - part, err := writer.CreateFormFile("license", "test-license.mattermost-license") - if err != nil { - return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { - return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if err = writer.Close(); err != nil { - return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - rq, err := http.NewRequest("POST", c.ApiUrl+c.GetLicenseRoute(), bytes.NewReader(body.Bytes())) - if err != nil { - return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - rq.Header.Set("Content-Type", writer.FormDataContentType()) - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetLicenseRoute(), "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)} - } - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } - - return CheckStatusOK(rp), BuildResponse(rp) -} - -// RemoveLicenseFile will remove the server license it exists. Note that this will -// disable all enterprise features. -func (c *Client4) RemoveLicenseFile() (bool, *Response) { - r, err := c.DoApiDelete(c.GetLicenseRoute()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetAnalyticsOld will retrieve analytics using the old format. New format is not -// available but the "/analytics" endpoint is reserved for it. The "name" argument is optional -// and defaults to "standard". The "teamId" argument is optional and will limit results -// to a specific team. -func (c *Client4) GetAnalyticsOld(name, teamId string) (AnalyticsRows, *Response) { - query := fmt.Sprintf("?name=%v&team_id=%v", name, teamId) - r, err := c.DoApiGet(c.GetAnalyticsRoute()+"/old"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return AnalyticsRowsFromJson(r.Body), BuildResponse(r) -} - -// Webhooks Section - -// CreateIncomingWebhook creates an incoming webhook for a channel. -func (c *Client4) CreateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) { - r, err := c.DoApiPost(c.GetIncomingWebhooksRoute(), hook.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return IncomingWebhookFromJson(r.Body), BuildResponse(r) -} - -// UpdateIncomingWebhook updates an incoming webhook for a channel. -func (c *Client4) UpdateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) { - r, err := c.DoApiPut(c.GetIncomingWebhookRoute(hook.Id), hook.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return IncomingWebhookFromJson(r.Body), BuildResponse(r) -} - -// GetIncomingWebhooks returns a page of incoming webhooks on the system. Page counting starts at 0. -func (c *Client4) GetIncomingWebhooks(page int, perPage int, etag string) ([]*IncomingWebhook, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return IncomingWebhookListFromJson(r.Body), BuildResponse(r) -} - -// GetIncomingWebhooksForTeam returns a page of incoming webhooks for a team. Page counting starts at 0. -func (c *Client4) GetIncomingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*IncomingWebhook, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId) - r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return IncomingWebhookListFromJson(r.Body), BuildResponse(r) -} - -// GetIncomingWebhook returns an Incoming webhook given the hook ID. -func (c *Client4) GetIncomingWebhook(hookID string, etag string) (*IncomingWebhook, *Response) { - r, err := c.DoApiGet(c.GetIncomingWebhookRoute(hookID), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return IncomingWebhookFromJson(r.Body), BuildResponse(r) -} - -// DeleteIncomingWebhook deletes and Incoming Webhook given the hook ID. -func (c *Client4) DeleteIncomingWebhook(hookID string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetIncomingWebhookRoute(hookID)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// CreateOutgoingWebhook creates an outgoing webhook for a team or channel. -func (c *Client4) CreateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) { - r, err := c.DoApiPost(c.GetOutgoingWebhooksRoute(), hook.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) -} - -// UpdateOutgoingWebhook creates an outgoing webhook for a team or channel. -func (c *Client4) UpdateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) { - r, err := c.DoApiPut(c.GetOutgoingWebhookRoute(hook.Id), hook.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) -} - -// GetOutgoingWebhooks returns a page of outgoing webhooks on the system. Page counting starts at 0. -func (c *Client4) GetOutgoingWebhooks(page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) -} - -// GetOutgoingWebhook outgoing webhooks on the system requested by Hook Id. -func (c *Client4) GetOutgoingWebhook(hookId string) (*OutgoingWebhook, *Response) { - r, err := c.DoApiGet(c.GetOutgoingWebhookRoute(hookId), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) -} - -// GetOutgoingWebhooksForChannel returns a page of outgoing webhooks for a channel. Page counting starts at 0. -func (c *Client4) GetOutgoingWebhooksForChannel(channelId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&channel_id=%v", page, perPage, channelId) - r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) -} - -// GetOutgoingWebhooksForTeam returns a page of outgoing webhooks for a team. Page counting starts at 0. -func (c *Client4) GetOutgoingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId) - r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OutgoingWebhookListFromJson(r.Body), BuildResponse(r) -} - -// RegenOutgoingHookToken regenerate the outgoing webhook token. -func (c *Client4) RegenOutgoingHookToken(hookId string) (*OutgoingWebhook, *Response) { - r, err := c.DoApiPost(c.GetOutgoingWebhookRoute(hookId)+"/regen_token", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OutgoingWebhookFromJson(r.Body), BuildResponse(r) -} - -// DeleteOutgoingWebhook delete the outgoing webhook on the system requested by Hook Id. -func (c *Client4) DeleteOutgoingWebhook(hookId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetOutgoingWebhookRoute(hookId)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// Preferences Section - -// GetPreferences returns the user's preferences. -func (c *Client4) GetPreferences(userId string) (Preferences, *Response) { - r, err := c.DoApiGet(c.GetPreferencesRoute(userId), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - preferences, _ := PreferencesFromJson(r.Body) - return preferences, BuildResponse(r) -} - -// UpdatePreferences saves the user's preferences. -func (c *Client4) UpdatePreferences(userId string, preferences *Preferences) (bool, *Response) { - r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return true, BuildResponse(r) -} - -// DeletePreferences deletes the user's preferences. -func (c *Client4) DeletePreferences(userId string, preferences *Preferences) (bool, *Response) { - r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return true, BuildResponse(r) -} - -// GetPreferencesByCategory returns the user's preferences from the provided category string. -func (c *Client4) GetPreferencesByCategory(userId string, category string) (Preferences, *Response) { - url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s", category) - r, err := c.DoApiGet(url, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - preferences, _ := PreferencesFromJson(r.Body) - return preferences, BuildResponse(r) -} - -// GetPreferenceByCategoryAndName returns the user's preferences from the provided category and preference name string. -func (c *Client4) GetPreferenceByCategoryAndName(userId string, category string, preferenceName string) (*Preference, *Response) { - url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s/name/%v", category, preferenceName) - r, err := c.DoApiGet(url, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PreferenceFromJson(r.Body), BuildResponse(r) -} - -// SAML Section - -// GetSamlMetadata returns metadata for the SAML configuration. -func (c *Client4) GetSamlMetadata() (string, *Response) { - r, err := c.DoApiGet(c.GetSamlRoute()+"/metadata", "") - if err != nil { - return "", BuildErrorResponse(r, err) - } - defer closeBody(r) - buf := new(bytes.Buffer) - _, _ = buf.ReadFrom(r.Body) - return buf.String(), BuildResponse(r) -} - -func fileToMultipart(data []byte, filename string) ([]byte, *multipart.Writer, error) { - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - - part, err := writer.CreateFormFile("certificate", filename) - if err != nil { - return nil, nil, err - } - - if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { - return nil, nil, err - } - - if err := writer.Close(); err != nil { - return nil, nil, err - } - - return body.Bytes(), writer, nil -} - -// UploadSamlIdpCertificate will upload an IDP certificate for SAML and set the config to use it. -// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk. -func (c *Client4) UploadSamlIdpCertificate(data []byte, filename string) (bool, *Response) { - body, writer, err := fileToMultipart(data, filename) - if err != nil { - return false, &Response{Error: NewAppError("UploadSamlIdpCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - _, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/idp", body, writer.FormDataContentType()) - return resp.Error == nil, resp -} - -// UploadSamlPublicCertificate will upload a public certificate for SAML and set the config to use it. -// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk. -func (c *Client4) UploadSamlPublicCertificate(data []byte, filename string) (bool, *Response) { - body, writer, err := fileToMultipart(data, filename) - if err != nil { - return false, &Response{Error: NewAppError("UploadSamlPublicCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - _, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/public", body, writer.FormDataContentType()) - return resp.Error == nil, resp -} - -// UploadSamlPrivateCertificate will upload a private key for SAML and set the config to use it. -// The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk. -func (c *Client4) UploadSamlPrivateCertificate(data []byte, filename string) (bool, *Response) { - body, writer, err := fileToMultipart(data, filename) - if err != nil { - return false, &Response{Error: NewAppError("UploadSamlPrivateCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - _, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/private", body, writer.FormDataContentType()) - return resp.Error == nil, resp -} - -// DeleteSamlIdpCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML. -func (c *Client4) DeleteSamlIdpCertificate() (bool, *Response) { - r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/idp") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// DeleteSamlPublicCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML. -func (c *Client4) DeleteSamlPublicCertificate() (bool, *Response) { - r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/public") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// DeleteSamlPrivateCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML. -func (c *Client4) DeleteSamlPrivateCertificate() (bool, *Response) { - r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/private") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetSamlCertificateStatus returns metadata for the SAML configuration. -func (c *Client4) GetSamlCertificateStatus() (*SamlCertificateStatus, *Response) { - r, err := c.DoApiGet(c.GetSamlRoute()+"/certificate/status", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return SamlCertificateStatusFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) GetSamlMetadataFromIdp(samlMetadataURL string) (*SamlMetadataResponse, *Response) { - requestBody := make(map[string]string) - requestBody["saml_metadata_url"] = samlMetadataURL - r, err := c.DoApiPost(c.GetSamlRoute()+"/metadatafromidp", MapToJson(requestBody)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - - defer closeBody(r) - return SamlMetadataResponseFromJson(r.Body), BuildResponse(r) -} - -// ResetSamlAuthDataToEmail resets the AuthData field of SAML users to their Email. -func (c *Client4) ResetSamlAuthDataToEmail(includeDeleted bool, dryRun bool, userIDs []string) (int64, *Response) { - params := map[string]interface{}{ - "include_deleted": includeDeleted, - "dry_run": dryRun, - "user_ids": userIDs, - } - b, _ := json.Marshal(params) - r, err := c.doApiPostBytes(c.GetSamlRoute()+"/reset_auth_data", b) - if err != nil { - return 0, BuildErrorResponse(r, err) - } - defer closeBody(r) - respBody := map[string]int64{} - jsonErr := json.NewDecoder(r.Body).Decode(&respBody) - if jsonErr != nil { - appErr := NewAppError("Api4.ResetSamlAuthDataToEmail", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError) - return 0, BuildErrorResponse(r, appErr) - } - return respBody["num_affected"], BuildResponse(r) -} - -// Compliance Section - -// CreateComplianceReport creates an incoming webhook for a channel. -func (c *Client4) CreateComplianceReport(report *Compliance) (*Compliance, *Response) { - r, err := c.DoApiPost(c.GetComplianceReportsRoute(), report.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ComplianceFromJson(r.Body), BuildResponse(r) -} - -// GetComplianceReports returns list of compliance reports. -func (c *Client4) GetComplianceReports(page, perPage int) (Compliances, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetComplianceReportsRoute()+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CompliancesFromJson(r.Body), BuildResponse(r) -} - -// GetComplianceReport returns a compliance report. -func (c *Client4) GetComplianceReport(reportId string) (*Compliance, *Response) { - r, err := c.DoApiGet(c.GetComplianceReportRoute(reportId), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ComplianceFromJson(r.Body), BuildResponse(r) -} - -// DownloadComplianceReport returns a full compliance report as a file. -func (c *Client4) DownloadComplianceReport(reportId string) ([]byte, *Response) { - rq, err := http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportDownloadRoute(reportId), nil) - if err != nil { - return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken) - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } - - data, err := ioutil.ReadAll(rp.Body) - if err != nil { - return nil, BuildErrorResponse(rp, NewAppError("DownloadComplianceReport", "model.client.read_file.app_error", nil, err.Error(), rp.StatusCode)) - } - - return data, BuildResponse(rp) -} - -// Cluster Section - -// GetClusterStatus returns the status of all the configured cluster nodes. -func (c *Client4) GetClusterStatus() ([]*ClusterInfo, *Response) { - r, err := c.DoApiGet(c.GetClusterRoute()+"/status", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ClusterInfosFromJson(r.Body), BuildResponse(r) -} - -// LDAP Section - -// SyncLdap will force a sync with the configured LDAP server. -// If includeRemovedMembers is true, then group members who left or were removed from a -// synced team/channel will be re-joined; otherwise, they will be excluded. -func (c *Client4) SyncLdap(includeRemovedMembers bool) (bool, *Response) { - reqBody, _ := json.Marshal(map[string]interface{}{ - "include_removed_members": includeRemovedMembers, - }) - r, err := c.doApiPostBytes(c.GetLdapRoute()+"/sync", reqBody) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// TestLdap will attempt to connect to the configured LDAP server and return OK if configured -// correctly. -func (c *Client4) TestLdap() (bool, *Response) { - r, err := c.DoApiPost(c.GetLdapRoute()+"/test", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetLdapGroups retrieves the immediate child groups of the given parent group. -func (c *Client4) GetLdapGroups() ([]*Group, *Response) { - path := fmt.Sprintf("%s/groups", c.GetLdapRoute()) - - r, appErr := c.DoApiGet(path, "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - responseData := struct { - Count int `json:"count"` - Groups []*Group `json:"groups"` - }{} - if err := json.NewDecoder(r.Body).Decode(&responseData); err != nil { - appErr := NewAppError("Api4.GetLdapGroups", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError) - return nil, BuildErrorResponse(r, appErr) - } - for i := range responseData.Groups { - responseData.Groups[i].DisplayName = *responseData.Groups[i].Name - } - - return responseData.Groups, BuildResponse(r) -} - -// LinkLdapGroup creates or undeletes a Mattermost group and associates it to the given LDAP group DN. -func (c *Client4) LinkLdapGroup(dn string) (*Group, *Response) { - path := fmt.Sprintf("%s/groups/%s/link", c.GetLdapRoute(), dn) - - r, appErr := c.DoApiPost(path, "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - return GroupFromJson(r.Body), BuildResponse(r) -} - -// UnlinkLdapGroup deletes the Mattermost group associated with the given LDAP group DN. -func (c *Client4) UnlinkLdapGroup(dn string) (*Group, *Response) { - path := fmt.Sprintf("%s/groups/%s/link", c.GetLdapRoute(), dn) - - r, appErr := c.DoApiDelete(path) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - return GroupFromJson(r.Body), BuildResponse(r) -} - -// MigrateIdLdap migrates the LDAP enabled users to given attribute -func (c *Client4) MigrateIdLdap(toAttribute string) (bool, *Response) { - r, err := c.DoApiPost(c.GetLdapRoute()+"/migrateid", MapToJson(map[string]string{ - "toAttribute": toAttribute, - })) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetGroupsByChannel retrieves the Mattermost Groups associated with a given channel -func (c *Client4) GetGroupsByChannel(channelId string, opts GroupSearchOpts) ([]*GroupWithSchemeAdmin, int, *Response) { - path := fmt.Sprintf("%s/groups?q=%v&include_member_count=%v&filter_allow_reference=%v", c.GetChannelRoute(channelId), opts.Q, opts.IncludeMemberCount, opts.FilterAllowReference) - if opts.PageOpts != nil { - path = fmt.Sprintf("%s&page=%v&per_page=%v", path, opts.PageOpts.Page, opts.PageOpts.PerPage) - } - r, appErr := c.DoApiGet(path, "") - if appErr != nil { - return nil, 0, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - responseData := struct { - Groups []*GroupWithSchemeAdmin `json:"groups"` - Count int `json:"total_group_count"` - }{} - if err := json.NewDecoder(r.Body).Decode(&responseData); err != nil { - appErr := NewAppError("Api4.GetGroupsByChannel", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError) - return nil, 0, BuildErrorResponse(r, appErr) - } - - return responseData.Groups, responseData.Count, BuildResponse(r) -} - -// GetGroupsByTeam retrieves the Mattermost Groups associated with a given team -func (c *Client4) GetGroupsByTeam(teamId string, opts GroupSearchOpts) ([]*GroupWithSchemeAdmin, int, *Response) { - path := fmt.Sprintf("%s/groups?q=%v&include_member_count=%v&filter_allow_reference=%v", c.GetTeamRoute(teamId), opts.Q, opts.IncludeMemberCount, opts.FilterAllowReference) - if opts.PageOpts != nil { - path = fmt.Sprintf("%s&page=%v&per_page=%v", path, opts.PageOpts.Page, opts.PageOpts.PerPage) - } - r, appErr := c.DoApiGet(path, "") - if appErr != nil { - return nil, 0, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - responseData := struct { - Groups []*GroupWithSchemeAdmin `json:"groups"` - Count int `json:"total_group_count"` - }{} - if err := json.NewDecoder(r.Body).Decode(&responseData); err != nil { - appErr := NewAppError("Api4.GetGroupsByTeam", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError) - return nil, 0, BuildErrorResponse(r, appErr) - } - - return responseData.Groups, responseData.Count, BuildResponse(r) -} - -// GetGroupsAssociatedToChannelsByTeam retrieves the Mattermost Groups associated with channels in a given team -func (c *Client4) GetGroupsAssociatedToChannelsByTeam(teamId string, opts GroupSearchOpts) (map[string][]*GroupWithSchemeAdmin, *Response) { - path := fmt.Sprintf("%s/groups_by_channels?q=%v&filter_allow_reference=%v", c.GetTeamRoute(teamId), opts.Q, opts.FilterAllowReference) - if opts.PageOpts != nil { - path = fmt.Sprintf("%s&page=%v&per_page=%v", path, opts.PageOpts.Page, opts.PageOpts.PerPage) - } - r, appErr := c.DoApiGet(path, "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - responseData := struct { - GroupsAssociatedToChannels map[string][]*GroupWithSchemeAdmin `json:"groups"` - }{} - if err := json.NewDecoder(r.Body).Decode(&responseData); err != nil { - appErr := NewAppError("Api4.GetGroupsAssociatedToChannelsByTeam", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError) - return nil, BuildErrorResponse(r, appErr) - } - - return responseData.GroupsAssociatedToChannels, BuildResponse(r) -} - -// GetGroups retrieves Mattermost Groups -func (c *Client4) GetGroups(opts GroupSearchOpts) ([]*Group, *Response) { - path := fmt.Sprintf( - "%s?include_member_count=%v¬_associated_to_team=%v¬_associated_to_channel=%v&filter_allow_reference=%v&q=%v&filter_parent_team_permitted=%v", - c.GetGroupsRoute(), - opts.IncludeMemberCount, - opts.NotAssociatedToTeam, - opts.NotAssociatedToChannel, - opts.FilterAllowReference, - opts.Q, - opts.FilterParentTeamPermitted, - ) - if opts.Since > 0 { - path = fmt.Sprintf("%s&since=%v", path, opts.Since) - } - if opts.PageOpts != nil { - path = fmt.Sprintf("%s&page=%v&per_page=%v", path, opts.PageOpts.Page, opts.PageOpts.PerPage) - } - r, appErr := c.DoApiGet(path, "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - return GroupsFromJson(r.Body), BuildResponse(r) -} - -// GetGroupsByUserId retrieves Mattermost Groups for a user -func (c *Client4) GetGroupsByUserId(userId string) ([]*Group, *Response) { - path := fmt.Sprintf( - "%s/%v/groups", - c.GetUsersRoute(), - userId, - ) - - r, appErr := c.DoApiGet(path, "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return GroupsFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) MigrateAuthToLdap(fromAuthService string, matchField string, force bool) (bool, *Response) { - r, err := c.DoApiPost(c.GetUsersRoute()+"/migrate_auth/ldap", StringInterfaceToJson(map[string]interface{}{ - "from": fromAuthService, - "force": force, - "match_field": matchField, - })) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -func (c *Client4) MigrateAuthToSaml(fromAuthService string, usersMap map[string]string, auto bool) (bool, *Response) { - r, err := c.DoApiPost(c.GetUsersRoute()+"/migrate_auth/saml", StringInterfaceToJson(map[string]interface{}{ - "from": fromAuthService, - "auto": auto, - "matches": usersMap, - })) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UploadLdapPublicCertificate will upload a public certificate for LDAP and set the config to use it. -func (c *Client4) UploadLdapPublicCertificate(data []byte) (bool, *Response) { - body, writer, err := fileToMultipart(data, LDAP_PUBLIC_CERTIFICATE_NAME) - if err != nil { - return false, &Response{Error: NewAppError("UploadLdapPublicCertificate", "model.client.upload_ldap_cert.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - _, resp := c.DoUploadFile(c.GetLdapRoute()+"/certificate/public", body, writer.FormDataContentType()) - return resp.Error == nil, resp -} - -// UploadLdapPrivateCertificate will upload a private key for LDAP and set the config to use it. -func (c *Client4) UploadLdapPrivateCertificate(data []byte) (bool, *Response) { - body, writer, err := fileToMultipart(data, LDAP_PRIVATE_KEY_NAME) - if err != nil { - return false, &Response{Error: NewAppError("UploadLdapPrivateCertificate", "model.client.upload_Ldap_cert.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - _, resp := c.DoUploadFile(c.GetLdapRoute()+"/certificate/private", body, writer.FormDataContentType()) - return resp.Error == nil, resp -} - -// DeleteLdapPublicCertificate deletes the LDAP IDP certificate from the server and updates the config to not use it and disable LDAP. -func (c *Client4) DeleteLdapPublicCertificate() (bool, *Response) { - r, err := c.DoApiDelete(c.GetLdapRoute() + "/certificate/public") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// DeleteLDAPPrivateCertificate deletes the LDAP IDP certificate from the server and updates the config to not use it and disable LDAP. -func (c *Client4) DeleteLdapPrivateCertificate() (bool, *Response) { - r, err := c.DoApiDelete(c.GetLdapRoute() + "/certificate/private") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// Audits Section - -// GetAudits returns a list of audits for the whole system. -func (c *Client4) GetAudits(page int, perPage int, etag string) (Audits, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet("/audits"+query, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return AuditsFromJson(r.Body), BuildResponse(r) -} - -// Brand Section - -// GetBrandImage retrieves the previously uploaded brand image. -func (c *Client4) GetBrandImage() ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetBrandRoute()+"/image", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - if r.StatusCode >= 300 { - return nil, BuildErrorResponse(r, AppErrorFromJson(r.Body)) - } - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetBrandImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } - - return data, BuildResponse(r) -} - -// DeleteBrandImage deletes the brand image for the system. -func (c *Client4) DeleteBrandImage() *Response { - r, err := c.DoApiDelete(c.GetBrandRoute() + "/image") - if err != nil { - return BuildErrorResponse(r, err) - } - return BuildResponse(r) -} - -// UploadBrandImage sets the brand image for the system. -func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) { - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - - part, err := writer.CreateFormFile("image", "brand.png") - if err != nil { - return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil { - return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - if err = writer.Close(); err != nil { - return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)} - } - - rq, err := http.NewRequest("POST", c.ApiUrl+c.GetBrandRoute()+"/image", bytes.NewReader(body.Bytes())) - if err != nil { - return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - rq.Header.Set("Content-Type", writer.FormDataContentType()) - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetBrandRoute()+"/image", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)} - } - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } - - return CheckStatusOK(rp), BuildResponse(rp) -} - -// Logs Section - -// GetLogs page of logs as a string array. -func (c *Client4) GetLogs(page, perPage int) ([]string, *Response) { - query := fmt.Sprintf("?page=%v&logs_per_page=%v", page, perPage) - r, err := c.DoApiGet("/logs"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ArrayFromJson(r.Body), BuildResponse(r) -} - -// PostLog is a convenience Web Service call so clients can log messages into -// the server-side logs. For example we typically log javascript error messages -// into the server-side. It returns the log message if the logging was successful. -func (c *Client4) PostLog(message map[string]string) (map[string]string, *Response) { - r, err := c.DoApiPost("/logs", MapToJson(message)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) -} - -// OAuth Section - -// CreateOAuthApp will register a new OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider. -func (c *Client4) CreateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) { - r, err := c.DoApiPost(c.GetOAuthAppsRoute(), app.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) -} - -// UpdateOAuthApp updates a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider. -func (c *Client4) UpdateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) { - r, err := c.DoApiPut(c.GetOAuthAppRoute(app.Id), app.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) -} - -// GetOAuthApps gets a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider. -func (c *Client4) GetOAuthApps(page, perPage int) ([]*OAuthApp, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetOAuthAppsRoute()+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OAuthAppListFromJson(r.Body), BuildResponse(r) -} - -// GetOAuthApp gets a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider. -func (c *Client4) GetOAuthApp(appId string) (*OAuthApp, *Response) { - r, err := c.DoApiGet(c.GetOAuthAppRoute(appId), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) -} - -// GetOAuthAppInfo gets a sanitized version of a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider. -func (c *Client4) GetOAuthAppInfo(appId string) (*OAuthApp, *Response) { - r, err := c.DoApiGet(c.GetOAuthAppRoute(appId)+"/info", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) -} - -// DeleteOAuthApp deletes a registered OAuth 2.0 client application. -func (c *Client4) DeleteOAuthApp(appId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetOAuthAppRoute(appId)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// RegenerateOAuthAppSecret regenerates the client secret for a registered OAuth 2.0 client application. -func (c *Client4) RegenerateOAuthAppSecret(appId string) (*OAuthApp, *Response) { - r, err := c.DoApiPost(c.GetOAuthAppRoute(appId)+"/regen_secret", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OAuthAppFromJson(r.Body), BuildResponse(r) -} - -// GetAuthorizedOAuthAppsForUser gets a page of OAuth 2.0 client applications the user has authorized to use access their account. -func (c *Client4) GetAuthorizedOAuthAppsForUser(userId string, page, perPage int) ([]*OAuthApp, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/oauth/apps/authorized"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return OAuthAppListFromJson(r.Body), BuildResponse(r) -} - -// AuthorizeOAuthApp will authorize an OAuth 2.0 client application to access a user's account and provide a redirect link to follow. -func (c *Client4) AuthorizeOAuthApp(authRequest *AuthorizeRequest) (string, *Response) { - r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/authorize", authRequest.ToJson(), "") - if err != nil { - return "", BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body)["redirect"], BuildResponse(r) -} - -// DeauthorizeOAuthApp will deauthorize an OAuth 2.0 client application from accessing a user's account. -func (c *Client4) DeauthorizeOAuthApp(appId string) (bool, *Response) { - requestData := map[string]string{"client_id": appId} - r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/deauthorize", MapToJson(requestData), "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetOAuthAccessToken is a test helper function for the OAuth access token endpoint. -func (c *Client4) GetOAuthAccessToken(data url.Values) (*AccessResponse, *Response) { - rq, err := http.NewRequest(http.MethodPost, c.Url+"/oauth/access_token", strings.NewReader(data.Encode())) - if err != nil { - return nil, &Response{Error: NewAppError(c.Url+"/oauth/access_token", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - rq.Header.Set("Content-Type", "application/x-www-form-urlencoded") - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.Url+"/oauth/access_token", "model.client.connecting.app_error", nil, err.Error(), 403)} - } - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } - - return AccessResponseFromJson(rp.Body), BuildResponse(rp) -} - -// Elasticsearch Section - -// TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured. -// correctly. -func (c *Client4) TestElasticsearch() (bool, *Response) { - r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/test", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// PurgeElasticsearchIndexes immediately deletes all Elasticsearch indexes. -func (c *Client4) PurgeElasticsearchIndexes() (bool, *Response) { - r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/purge_indexes", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// Bleve Section - -// PurgeBleveIndexes immediately deletes all Bleve indexes. -func (c *Client4) PurgeBleveIndexes() (bool, *Response) { - r, err := c.DoApiPost(c.GetBleveRoute()+"/purge_indexes", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// Data Retention Section - -// GetDataRetentionPolicy will get the current global data retention policy details. -func (c *Client4) GetDataRetentionPolicy() (*GlobalRetentionPolicy, *Response) { - r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return GlobalRetentionPolicyFromJson(r.Body), BuildResponse(r) -} - -// GetDataRetentionPolicyByID will get the details for the granular data retention policy with the specified ID. -func (c *Client4) GetDataRetentionPolicyByID(policyID string) (*RetentionPolicyWithTeamAndChannelCounts, *Response) { - r, appErr := c.DoApiGet(c.GetDataRetentionPolicyRoute(policyID), "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - policy, err := RetentionPolicyWithTeamAndChannelCountsFromJson(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.GetDataRetentionPolicyByID", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) - } - return policy, BuildResponse(r) -} - -// GetDataRetentionPoliciesCount will get the total number of granular data retention policies. -func (c *Client4) GetDataRetentionPoliciesCount() (int64, *Response) { - type CountBody struct { - TotalCount int64 `json:"total_count"` - } - r, appErr := c.DoApiGet(c.GetDataRetentionRoute()+"/policies_count", "") - if appErr != nil { - return 0, BuildErrorResponse(r, appErr) - } - var countObj CountBody - jsonErr := json.NewDecoder(r.Body).Decode(&countObj) - if jsonErr != nil { - return 0, BuildErrorResponse(r, NewAppError("Client4.GetDataRetentionPoliciesCount", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) - } - return countObj.TotalCount, BuildResponse(r) -} - -// GetDataRetentionPolicies will get the current granular data retention policies' details. -func (c *Client4) GetDataRetentionPolicies(page, perPage int) (*RetentionPolicyWithTeamAndChannelCountsList, *Response) { - query := fmt.Sprintf("?page=%d&per_page=%d", page, perPage) - r, appErr := c.DoApiGet(c.GetDataRetentionRoute()+"/policies"+query, "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - policies, err := RetentionPolicyWithTeamAndChannelCountsListFromJson(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.GetDataRetentionPolicies", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) - } - return policies, BuildResponse(r) -} - -// CreateDataRetentionPolicy will create a new granular data retention policy which will be applied to -// the specified teams and channels. The Id field of `policy` must be empty. -func (c *Client4) CreateDataRetentionPolicy(policy *RetentionPolicyWithTeamAndChannelIDs) (*RetentionPolicyWithTeamAndChannelCounts, *Response) { - r, appErr := c.doApiPostBytes(c.GetDataRetentionRoute()+"/policies", policy.ToJson()) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - newPolicy, err := RetentionPolicyWithTeamAndChannelCountsFromJson(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.CreateDataRetentionPolicy", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) - } - return newPolicy, BuildResponse(r) -} - -// DeleteDataRetentionPolicy will delete the granular data retention policy with the specified ID. -func (c *Client4) DeleteDataRetentionPolicy(policyID string) *Response { - r, appErr := c.DoApiDelete(c.GetDataRetentionPolicyRoute(policyID)) - if appErr != nil { - return BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return BuildResponse(r) -} - -// PatchDataRetentionPolicy will patch the granular data retention policy with the specified ID. -// The Id field of `patch` must be non-empty. -func (c *Client4) PatchDataRetentionPolicy(patch *RetentionPolicyWithTeamAndChannelIDs) (*RetentionPolicyWithTeamAndChannelCounts, *Response) { - r, appErr := c.doApiPatchBytes(c.GetDataRetentionPolicyRoute(patch.ID), patch.ToJson()) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - policy, err := RetentionPolicyWithTeamAndChannelCountsFromJson(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.PatchDataRetentionPolicy", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) - } - return policy, BuildResponse(r) -} - -// GetTeamsForRetentionPolicy will get the teams to which the specified policy is currently applied. -func (c *Client4) GetTeamsForRetentionPolicy(policyID string, page, perPage int) (*TeamsWithCount, *Response) { - query := fmt.Sprintf("?page=%d&per_page=%d", page, perPage) - r, appErr := c.DoApiGet(c.GetDataRetentionPolicyRoute(policyID)+"/teams"+query, "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - var teams *TeamsWithCount - jsonErr := json.NewDecoder(r.Body).Decode(&teams) - if jsonErr != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.GetTeamsForRetentionPolicy", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) - } - return teams, BuildResponse(r) -} - -// SearchTeamsForRetentionPolicy will search the teams to which the specified policy is currently applied. -func (c *Client4) SearchTeamsForRetentionPolicy(policyID string, term string) ([]*Team, *Response) { - body, _ := json.Marshal(map[string]interface{}{"term": term}) - r, appErr := c.doApiPostBytes(c.GetDataRetentionPolicyRoute(policyID)+"/teams/search", body) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - var teams []*Team - jsonErr := json.NewDecoder(r.Body).Decode(&teams) - if jsonErr != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.SearchTeamsForRetentionPolicy", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) - } - return teams, BuildResponse(r) -} - -// AddTeamsToRetentionPolicy will add the specified teams to the granular data retention policy -// with the specified ID. -func (c *Client4) AddTeamsToRetentionPolicy(policyID string, teamIDs []string) *Response { - body, _ := json.Marshal(teamIDs) - r, appErr := c.doApiPostBytes(c.GetDataRetentionPolicyRoute(policyID)+"/teams", body) - if appErr != nil { - return BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return BuildResponse(r) -} - -// RemoveTeamsFromRetentionPolicy will remove the specified teams from the granular data retention policy -// with the specified ID. -func (c *Client4) RemoveTeamsFromRetentionPolicy(policyID string, teamIDs []string) *Response { - body, _ := json.Marshal(teamIDs) - r, appErr := c.doApiDeleteBytes(c.GetDataRetentionPolicyRoute(policyID)+"/teams", body) - if appErr != nil { - return BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return BuildResponse(r) -} - -// GetChannelsForRetentionPolicy will get the channels to which the specified policy is currently applied. -func (c *Client4) GetChannelsForRetentionPolicy(policyID string, page, perPage int) (*ChannelsWithCount, *Response) { - query := fmt.Sprintf("?page=%d&per_page=%d", page, perPage) - r, appErr := c.DoApiGet(c.GetDataRetentionPolicyRoute(policyID)+"/channels"+query, "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - var channels *ChannelsWithCount - jsonErr := json.NewDecoder(r.Body).Decode(&channels) - if jsonErr != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.GetChannelsForRetentionPolicy", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) - } - return channels, BuildResponse(r) -} - -// SearchChannelsForRetentionPolicy will search the channels to which the specified policy is currently applied. -func (c *Client4) SearchChannelsForRetentionPolicy(policyID string, term string) (ChannelListWithTeamData, *Response) { - body, _ := json.Marshal(map[string]interface{}{"term": term}) - r, appErr := c.doApiPostBytes(c.GetDataRetentionPolicyRoute(policyID)+"/channels/search", body) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - var channels ChannelListWithTeamData - jsonErr := json.NewDecoder(r.Body).Decode(&channels) - if jsonErr != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.SearchChannelsForRetentionPolicy", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) - } - return channels, BuildResponse(r) -} - -// AddChannelsToRetentionPolicy will add the specified channels to the granular data retention policy -// with the specified ID. -func (c *Client4) AddChannelsToRetentionPolicy(policyID string, channelIDs []string) *Response { - body, _ := json.Marshal(channelIDs) - r, appErr := c.doApiPostBytes(c.GetDataRetentionPolicyRoute(policyID)+"/channels", body) - if appErr != nil { - return BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return BuildResponse(r) -} - -// RemoveChannelsFromRetentionPolicy will remove the specified channels from the granular data retention policy -// with the specified ID. -func (c *Client4) RemoveChannelsFromRetentionPolicy(policyID string, channelIDs []string) *Response { - body, _ := json.Marshal(channelIDs) - r, appErr := c.doApiDeleteBytes(c.GetDataRetentionPolicyRoute(policyID)+"/channels", body) - if appErr != nil { - return BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return BuildResponse(r) -} - -// GetTeamPoliciesForUser will get the data retention policies for the teams to which a user belongs. -func (c *Client4) GetTeamPoliciesForUser(userID string, offset, limit int) (*RetentionPolicyForTeamList, *Response) { - r, appErr := c.DoApiGet(c.GetUserRoute(userID)+"/data_retention/team_policies", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - var teams RetentionPolicyForTeamList - jsonErr := json.NewDecoder(r.Body).Decode(&teams) - if jsonErr != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.GetTeamPoliciesForUser", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) - } - return &teams, BuildResponse(r) -} - -// GetChannelPoliciesForUser will get the data retention policies for the channels to which a user belongs. -func (c *Client4) GetChannelPoliciesForUser(userID string, offset, limit int) (*RetentionPolicyForChannelList, *Response) { - r, appErr := c.DoApiGet(c.GetUserRoute(userID)+"/data_retention/channel_policies", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - var channels RetentionPolicyForChannelList - jsonErr := json.NewDecoder(r.Body).Decode(&channels) - if jsonErr != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.GetChannelPoliciesForUser", "model.utils.decode_json.app_error", nil, jsonErr.Error(), r.StatusCode)) - } - return &channels, BuildResponse(r) -} - -// Commands Section - -// CreateCommand will create a new command if the user have the right permissions. -func (c *Client4) CreateCommand(cmd *Command) (*Command, *Response) { - r, err := c.DoApiPost(c.GetCommandsRoute(), cmd.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CommandFromJson(r.Body), BuildResponse(r) -} - -// UpdateCommand updates a command based on the provided Command struct. -func (c *Client4) UpdateCommand(cmd *Command) (*Command, *Response) { - r, err := c.DoApiPut(c.GetCommandRoute(cmd.Id), cmd.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CommandFromJson(r.Body), BuildResponse(r) -} - -// MoveCommand moves a command to a different team. -func (c *Client4) MoveCommand(teamId string, commandId string) (bool, *Response) { - cmr := CommandMoveRequest{TeamId: teamId} - r, err := c.DoApiPut(c.GetCommandMoveRoute(commandId), cmr.ToJson()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// DeleteCommand deletes a command based on the provided command id string. -func (c *Client4) DeleteCommand(commandId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetCommandRoute(commandId)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// ListCommands will retrieve a list of commands available in the team. -func (c *Client4) ListCommands(teamId string, customOnly bool) ([]*Command, *Response) { - query := fmt.Sprintf("?team_id=%v&custom_only=%v", teamId, customOnly) - r, err := c.DoApiGet(c.GetCommandsRoute()+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CommandListFromJson(r.Body), BuildResponse(r) -} - -// ListCommandAutocompleteSuggestions will retrieve a list of suggestions for a userInput. -func (c *Client4) ListCommandAutocompleteSuggestions(userInput, teamId string) ([]AutocompleteSuggestion, *Response) { - query := fmt.Sprintf("/commands/autocomplete_suggestions?user_input=%v", userInput) - r, err := c.DoApiGet(c.GetTeamRoute(teamId)+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return AutocompleteSuggestionsFromJSON(r.Body), BuildResponse(r) -} - -// GetCommandById will retrieve a command by id. -func (c *Client4) GetCommandById(cmdId string) (*Command, *Response) { - url := fmt.Sprintf("%s/%s", c.GetCommandsRoute(), cmdId) - r, err := c.DoApiGet(url, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CommandFromJson(r.Body), BuildResponse(r) -} - -// ExecuteCommand executes a given slash command. -func (c *Client4) ExecuteCommand(channelId, command string) (*CommandResponse, *Response) { - commandArgs := &CommandArgs{ - ChannelId: channelId, - Command: command, - } - r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - - response, _ := CommandResponseFromJson(r.Body) - return response, BuildResponse(r) -} - -// ExecuteCommandWithTeam executes a given slash command against the specified team. -// Use this when executing slash commands in a DM/GM, since the team id cannot be inferred in that case. -func (c *Client4) ExecuteCommandWithTeam(channelId, teamId, command string) (*CommandResponse, *Response) { - commandArgs := &CommandArgs{ - ChannelId: channelId, - TeamId: teamId, - Command: command, - } - r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - - response, _ := CommandResponseFromJson(r.Body) - return response, BuildResponse(r) -} - -// ListAutocompleteCommands will retrieve a list of commands available in the team. -func (c *Client4) ListAutocompleteCommands(teamId string) ([]*Command, *Response) { - r, err := c.DoApiGet(c.GetTeamAutoCompleteCommandsRoute(teamId), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CommandListFromJson(r.Body), BuildResponse(r) -} - -// RegenCommandToken will create a new token if the user have the right permissions. -func (c *Client4) RegenCommandToken(commandId string) (string, *Response) { - r, err := c.DoApiPut(c.GetCommandRoute(commandId)+"/regen_token", "") - if err != nil { - return "", BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body)["token"], BuildResponse(r) -} - -// Status Section - -// GetUserStatus returns a user based on the provided user id string. -func (c *Client4) GetUserStatus(userId, etag string) (*Status, *Response) { - r, err := c.DoApiGet(c.GetUserStatusRoute(userId), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return StatusFromJson(r.Body), BuildResponse(r) -} - -// GetUsersStatusesByIds returns a list of users status based on the provided user ids. -func (c *Client4) GetUsersStatusesByIds(userIds []string) ([]*Status, *Response) { - r, err := c.DoApiPost(c.GetUserStatusesRoute()+"/ids", ArrayToJson(userIds)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return StatusListFromJson(r.Body), BuildResponse(r) -} - -// UpdateUserStatus sets a user's status based on the provided user id string. -func (c *Client4) UpdateUserStatus(userId string, userStatus *Status) (*Status, *Response) { - r, err := c.DoApiPut(c.GetUserStatusRoute(userId), userStatus.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return StatusFromJson(r.Body), BuildResponse(r) -} - -// Emoji Section - -// CreateEmoji will save an emoji to the server if the current user has permission -// to do so. If successful, the provided emoji will be returned with its Id field -// filled in. Otherwise, an error will be returned. -func (c *Client4) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoji, *Response) { - body := &bytes.Buffer{} - writer := multipart.NewWriter(body) - - part, err := writer.CreateFormFile("image", filename) - if err != nil { - return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)} - } - - if _, err := io.Copy(part, bytes.NewBuffer(image)); err != nil { - return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)} - } - - if err := writer.WriteField("emoji", emoji.ToJson()); err != nil { - return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error(), 0)} - } - - if err := writer.Close(); err != nil { - return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error(), 0)} - } - - return c.DoEmojiUploadFile(c.GetEmojisRoute(), body.Bytes(), writer.FormDataContentType()) -} - -// GetEmojiList returns a page of custom emoji on the system. -func (c *Client4) GetEmojiList(page, perPage int) ([]*Emoji, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage) - r, err := c.DoApiGet(c.GetEmojisRoute()+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) -} - -// GetSortedEmojiList returns a page of custom emoji on the system sorted based on the sort -// parameter, blank for no sorting and "name" to sort by emoji names. -func (c *Client4) GetSortedEmojiList(page, perPage int, sort string) ([]*Emoji, *Response) { - query := fmt.Sprintf("?page=%v&per_page=%v&sort=%v", page, perPage, sort) - r, err := c.DoApiGet(c.GetEmojisRoute()+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) -} - -// DeleteEmoji delete an custom emoji on the provided emoji id string. -func (c *Client4) DeleteEmoji(emojiId string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetEmojiRoute(emojiId)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetEmoji returns a custom emoji based on the emojiId string. -func (c *Client4) GetEmoji(emojiId string) (*Emoji, *Response) { - r, err := c.DoApiGet(c.GetEmojiRoute(emojiId), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return EmojiFromJson(r.Body), BuildResponse(r) -} - -// GetEmojiByName returns a custom emoji based on the name string. -func (c *Client4) GetEmojiByName(name string) (*Emoji, *Response) { - r, err := c.DoApiGet(c.GetEmojiByNameRoute(name), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return EmojiFromJson(r.Body), BuildResponse(r) -} - -// GetEmojiImage returns the emoji image. -func (c *Client4) GetEmojiImage(emojiId string) ([]byte, *Response) { - r, apErr := c.DoApiGet(c.GetEmojiRoute(emojiId)+"/image", "") - if apErr != nil { - return nil, BuildErrorResponse(r, apErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetEmojiImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)) - } - - return data, BuildResponse(r) -} - -// SearchEmoji returns a list of emoji matching some search criteria. -func (c *Client4) SearchEmoji(search *EmojiSearch) ([]*Emoji, *Response) { - r, err := c.DoApiPost(c.GetEmojisRoute()+"/search", search.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) -} - -// AutocompleteEmoji returns a list of emoji starting with or matching name. -func (c *Client4) AutocompleteEmoji(name string, etag string) ([]*Emoji, *Response) { - query := fmt.Sprintf("?name=%v", name) - r, err := c.DoApiGet(c.GetEmojisRoute()+"/autocomplete"+query, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return EmojiListFromJson(r.Body), BuildResponse(r) -} - -// Reaction Section - -// SaveReaction saves an emoji reaction for a post. Returns the saved reaction if successful, otherwise an error will be returned. -func (c *Client4) SaveReaction(reaction *Reaction) (*Reaction, *Response) { - r, err := c.DoApiPost(c.GetReactionsRoute(), reaction.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ReactionFromJson(r.Body), BuildResponse(r) -} - -// GetReactions returns a list of reactions to a post. -func (c *Client4) GetReactions(postId string) ([]*Reaction, *Response) { - r, err := c.DoApiGet(c.GetPostRoute(postId)+"/reactions", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ReactionsFromJson(r.Body), BuildResponse(r) -} - -// DeleteReaction deletes reaction of a user in a post. -func (c *Client4) DeleteReaction(reaction *Reaction) (bool, *Response) { - r, err := c.DoApiDelete(c.GetUserRoute(reaction.UserId) + c.GetPostRoute(reaction.PostId) + fmt.Sprintf("/reactions/%v", reaction.EmojiName)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// FetchBulkReactions returns a map of postIds and corresponding reactions -func (c *Client4) GetBulkReactions(postIds []string) (map[string][]*Reaction, *Response) { - r, err := c.DoApiPost(c.GetPostsRoute()+"/ids/reactions", ArrayToJson(postIds)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapPostIdToReactionsFromJson(r.Body), BuildResponse(r) -} - -// Timezone Section - -// GetSupportedTimezone returns a page of supported timezones on the system. -func (c *Client4) GetSupportedTimezone() ([]string, *Response) { - r, err := c.DoApiGet(c.GetTimezonesRoute(), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - var timezones []string - json.NewDecoder(r.Body).Decode(&timezones) - return timezones, BuildResponse(r) -} - -// Open Graph Metadata Section - -// OpenGraph return the open graph metadata for a particular url if the site have the metadata. -func (c *Client4) OpenGraph(url string) (map[string]string, *Response) { - requestBody := make(map[string]string) - requestBody["url"] = url - - r, err := c.DoApiPost(c.GetOpenGraphRoute(), MapToJson(requestBody)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body), BuildResponse(r) -} - -// Jobs Section - -// GetJob gets a single job. -func (c *Client4) GetJob(id string) (*Job, *Response) { - r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v", id), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return JobFromJson(r.Body), BuildResponse(r) -} - -// GetJobs gets all jobs, sorted with the job that was created most recently first. -func (c *Client4) GetJobs(page int, perPage int) ([]*Job, *Response) { - r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("?page=%v&per_page=%v", page, perPage), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return JobsFromJson(r.Body), BuildResponse(r) -} - -// GetJobsByType gets all jobs of a given type, sorted with the job that was created most recently first. -func (c *Client4) GetJobsByType(jobType string, page int, perPage int) ([]*Job, *Response) { - r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/type/%v?page=%v&per_page=%v", jobType, page, perPage), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return JobsFromJson(r.Body), BuildResponse(r) -} - -// CreateJob creates a job based on the provided job struct. -func (c *Client4) CreateJob(job *Job) (*Job, *Response) { - r, err := c.DoApiPost(c.GetJobsRoute(), job.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return JobFromJson(r.Body), BuildResponse(r) -} - -// CancelJob requests the cancellation of the job with the provided Id. -func (c *Client4) CancelJob(jobId string) (bool, *Response) { - r, err := c.DoApiPost(c.GetJobsRoute()+fmt.Sprintf("/%v/cancel", jobId), "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// DownloadJob downloads the results of the job -func (c *Client4) DownloadJob(jobId string) ([]byte, *Response) { - r, appErr := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v/download", jobId), "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_job_result_file.app_error", nil, err.Error(), r.StatusCode)) - } - return data, BuildResponse(r) -} - -// Roles Section - -// GetRole gets a single role by ID. -func (c *Client4) GetRole(id string) (*Role, *Response) { - r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/%v", id), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return RoleFromJson(r.Body), BuildResponse(r) -} - -// GetRoleByName gets a single role by Name. -func (c *Client4) GetRoleByName(name string) (*Role, *Response) { - r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/name/%v", name), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return RoleFromJson(r.Body), BuildResponse(r) -} - -// GetRolesByNames returns a list of roles based on the provided role names. -func (c *Client4) GetRolesByNames(roleNames []string) ([]*Role, *Response) { - r, err := c.DoApiPost(c.GetRolesRoute()+"/names", ArrayToJson(roleNames)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return RoleListFromJson(r.Body), BuildResponse(r) -} - -// PatchRole partially updates a role in the system. Any missing fields are not updated. -func (c *Client4) PatchRole(roleId string, patch *RolePatch) (*Role, *Response) { - r, err := c.DoApiPut(c.GetRolesRoute()+fmt.Sprintf("/%v/patch", roleId), patch.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return RoleFromJson(r.Body), BuildResponse(r) -} - -// Schemes Section - -// CreateScheme creates a new Scheme. -func (c *Client4) CreateScheme(scheme *Scheme) (*Scheme, *Response) { - r, err := c.DoApiPost(c.GetSchemesRoute(), scheme.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return SchemeFromJson(r.Body), BuildResponse(r) -} - -// GetScheme gets a single scheme by ID. -func (c *Client4) GetScheme(id string) (*Scheme, *Response) { - r, err := c.DoApiGet(c.GetSchemeRoute(id), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return SchemeFromJson(r.Body), BuildResponse(r) -} - -// GetSchemes gets all schemes, sorted with the most recently created first, optionally filtered by scope. -func (c *Client4) GetSchemes(scope string, page int, perPage int) ([]*Scheme, *Response) { - r, err := c.DoApiGet(c.GetSchemesRoute()+fmt.Sprintf("?scope=%v&page=%v&per_page=%v", scope, page, perPage), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return SchemesFromJson(r.Body), BuildResponse(r) -} - -// DeleteScheme deletes a single scheme by ID. -func (c *Client4) DeleteScheme(id string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetSchemeRoute(id)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// PatchScheme partially updates a scheme in the system. Any missing fields are not updated. -func (c *Client4) PatchScheme(id string, patch *SchemePatch) (*Scheme, *Response) { - r, err := c.DoApiPut(c.GetSchemeRoute(id)+"/patch", patch.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return SchemeFromJson(r.Body), BuildResponse(r) -} - -// GetTeamsForScheme gets the teams using this scheme, sorted alphabetically by display name. -func (c *Client4) GetTeamsForScheme(schemeId string, page int, perPage int) ([]*Team, *Response) { - r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/teams?page=%v&per_page=%v", page, perPage), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TeamListFromJson(r.Body), BuildResponse(r) -} - -// GetChannelsForScheme gets the channels using this scheme, sorted alphabetically by display name. -func (c *Client4) GetChannelsForScheme(schemeId string, page int, perPage int) (ChannelList, *Response) { - r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/channels?page=%v&per_page=%v", page, perPage), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return *ChannelListFromJson(r.Body), BuildResponse(r) -} - -// Plugin Section - -// UploadPlugin takes an io.Reader stream pointing to the contents of a .tar.gz plugin. -// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. -func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) { - return c.uploadPlugin(file, false) -} - -func (c *Client4) UploadPluginForced(file io.Reader) (*Manifest, *Response) { - return c.uploadPlugin(file, true) -} - -func (c *Client4) uploadPlugin(file io.Reader, force bool) (*Manifest, *Response) { - body := new(bytes.Buffer) - writer := multipart.NewWriter(body) - - if force { - err := writer.WriteField("force", c.boolString(true)) - if err != nil { - return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} - } - } - - part, err := writer.CreateFormFile("plugin", "plugin.tar.gz") - if err != nil { - return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} - } - - if _, err = io.Copy(part, file); err != nil { - return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} - } - - if err = writer.Close(); err != nil { - return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)} - } - - rq, err := http.NewRequest("POST", c.ApiUrl+c.GetPluginsRoute(), body) - if err != nil { - return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)} - } - rq.Header.Set("Content-Type", writer.FormDataContentType()) - - if c.AuthToken != "" { - rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken) - } - - rp, err := c.HttpClient.Do(rq) - if err != nil || rp == nil { - return nil, BuildErrorResponse(rp, NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), 0)) - } - defer closeBody(rp) - - if rp.StatusCode >= 300 { - return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body)) - } - - return ManifestFromJson(rp.Body), BuildResponse(rp) -} - -func (c *Client4) InstallPluginFromUrl(downloadUrl string, force bool) (*Manifest, *Response) { - forceStr := c.boolString(force) - - url := fmt.Sprintf("%s?plugin_download_url=%s&force=%s", c.GetPluginsRoute()+"/install_from_url", url.QueryEscape(downloadUrl), forceStr) - r, err := c.DoApiPost(url, "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ManifestFromJson(r.Body), BuildResponse(r) -} - -// InstallMarketplacePlugin will install marketplace plugin. -// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. -func (c *Client4) InstallMarketplacePlugin(request *InstallMarketplacePluginRequest) (*Manifest, *Response) { - json, err := request.ToJson() - if err != nil { - return nil, &Response{Error: NewAppError("InstallMarketplacePlugin", "model.client.plugin_request_to_json.app_error", nil, err.Error(), http.StatusBadRequest)} - } - r, appErr := c.DoApiPost(c.GetPluginsRoute()+"/marketplace", json) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return ManifestFromJson(r.Body), BuildResponse(r) -} - -// GetPlugins will return a list of plugin manifests for currently active plugins. -// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. -func (c *Client4) GetPlugins() (*PluginsResponse, *Response) { - r, err := c.DoApiGet(c.GetPluginsRoute(), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PluginsResponseFromJson(r.Body), BuildResponse(r) -} - -// GetPluginStatuses will return the plugins installed on any server in the cluster, for reporting -// to the administrator via the system console. -// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. -func (c *Client4) GetPluginStatuses() (PluginStatuses, *Response) { - r, err := c.DoApiGet(c.GetPluginsRoute()+"/statuses", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return PluginStatusesFromJson(r.Body), BuildResponse(r) -} - -// RemovePlugin will disable and delete a plugin. -// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. -func (c *Client4) RemovePlugin(id string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetPluginRoute(id)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetWebappPlugins will return a list of plugins that the webapp should download. -// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. -func (c *Client4) GetWebappPlugins() ([]*Manifest, *Response) { - r, err := c.DoApiGet(c.GetPluginsRoute()+"/webapp", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ManifestListFromJson(r.Body), BuildResponse(r) -} - -// EnablePlugin will enable an plugin installed. -// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. -func (c *Client4) EnablePlugin(id string) (bool, *Response) { - r, err := c.DoApiPost(c.GetPluginRoute(id)+"/enable", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// DisablePlugin will disable an enabled plugin. -// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. -func (c *Client4) DisablePlugin(id string) (bool, *Response) { - r, err := c.DoApiPost(c.GetPluginRoute(id)+"/disable", "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetMarketplacePlugins will return a list of plugins that an admin can install. -// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE. -func (c *Client4) GetMarketplacePlugins(filter *MarketplacePluginFilter) ([]*MarketplacePlugin, *Response) { - route := c.GetPluginsRoute() + "/marketplace" - u, parseErr := url.Parse(route) - if parseErr != nil { - return nil, &Response{Error: NewAppError("GetMarketplacePlugins", "model.client.parse_plugins.app_error", nil, parseErr.Error(), http.StatusBadRequest)} - } - - filter.ApplyToURL(u) - - r, err := c.DoApiGet(u.String(), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - - plugins, readerErr := MarketplacePluginsFromReader(r.Body) - if readerErr != nil { - return nil, BuildErrorResponse(r, NewAppError(route, "model.client.parse_plugins.app_error", nil, err.Error(), http.StatusBadRequest)) - } - - return plugins, BuildResponse(r) -} - -// UpdateChannelScheme will update a channel's scheme. -func (c *Client4) UpdateChannelScheme(channelId, schemeId string) (bool, *Response) { - sip := &SchemeIDPatch{SchemeID: &schemeId} - r, err := c.DoApiPut(c.GetChannelSchemeRoute(channelId), sip.ToJson()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// UpdateTeamScheme will update a team's scheme. -func (c *Client4) UpdateTeamScheme(teamId, schemeId string) (bool, *Response) { - sip := &SchemeIDPatch{SchemeID: &schemeId} - r, err := c.DoApiPut(c.GetTeamSchemeRoute(teamId), sip.ToJson()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetRedirectLocation retrieves the value of the 'Location' header of an HTTP response for a given URL. -func (c *Client4) GetRedirectLocation(urlParam, etag string) (string, *Response) { - url := fmt.Sprintf("%s?url=%s", c.GetRedirectLocationRoute(), url.QueryEscape(urlParam)) - r, err := c.DoApiGet(url, etag) - if err != nil { - return "", BuildErrorResponse(r, err) - } - defer closeBody(r) - return MapFromJson(r.Body)["location"], BuildResponse(r) -} - -// SetServerBusy will mark the server as busy, which disables non-critical services for `secs` seconds. -func (c *Client4) SetServerBusy(secs int) (bool, *Response) { - url := fmt.Sprintf("%s?seconds=%d", c.GetServerBusyRoute(), secs) - r, err := c.DoApiPost(url, "") - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// ClearServerBusy will mark the server as not busy. -func (c *Client4) ClearServerBusy() (bool, *Response) { - r, err := c.DoApiDelete(c.GetServerBusyRoute()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetServerBusy returns the current ServerBusyState including the time when a server marked busy -// will automatically have the flag cleared. -func (c *Client4) GetServerBusy() (*ServerBusyState, *Response) { - r, err := c.DoApiGet(c.GetServerBusyRoute(), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - - sbs := ServerBusyStateFromJson(r.Body) - return sbs, BuildResponse(r) -} - -// GetServerBusyExpires returns the time when a server marked busy -// will automatically have the flag cleared. -// -// Deprecated: Use GetServerBusy instead. -func (c *Client4) GetServerBusyExpires() (*time.Time, *Response) { - r, err := c.DoApiGet(c.GetServerBusyRoute(), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - - sbs := ServerBusyStateFromJson(r.Body) - expires := time.Unix(sbs.Expires, 0) - return &expires, BuildResponse(r) -} - -// RegisterTermsOfServiceAction saves action performed by a user against a specific terms of service. -func (c *Client4) RegisterTermsOfServiceAction(userId, termsOfServiceId string, accepted bool) (*bool, *Response) { - url := c.GetUserTermsOfServiceRoute(userId) - data := map[string]interface{}{"termsOfServiceId": termsOfServiceId, "accepted": accepted} - r, err := c.DoApiPost(url, StringInterfaceToJson(data)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return NewBool(CheckStatusOK(r)), BuildResponse(r) -} - -// GetTermsOfService fetches the latest terms of service -func (c *Client4) GetTermsOfService(etag string) (*TermsOfService, *Response) { - url := c.GetTermsOfServiceRoute() - r, err := c.DoApiGet(url, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TermsOfServiceFromJson(r.Body), BuildResponse(r) -} - -// GetUserTermsOfService fetches user's latest terms of service action if the latest action was for acceptance. -func (c *Client4) GetUserTermsOfService(userId, etag string) (*UserTermsOfService, *Response) { - url := c.GetUserTermsOfServiceRoute(userId) - r, err := c.DoApiGet(url, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UserTermsOfServiceFromJson(r.Body), BuildResponse(r) -} - -// CreateTermsOfService creates new terms of service. -func (c *Client4) CreateTermsOfService(text, userId string) (*TermsOfService, *Response) { - url := c.GetTermsOfServiceRoute() - data := map[string]interface{}{"text": text} - r, err := c.DoApiPost(url, StringInterfaceToJson(data)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return TermsOfServiceFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) GetGroup(groupID, etag string) (*Group, *Response) { - r, appErr := c.DoApiGet(c.GetGroupRoute(groupID), etag) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return GroupFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) PatchGroup(groupID string, patch *GroupPatch) (*Group, *Response) { - payload, _ := json.Marshal(patch) - r, appErr := c.DoApiPut(c.GetGroupRoute(groupID)+"/patch", string(payload)) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return GroupFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) LinkGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType, patch *GroupSyncablePatch) (*GroupSyncable, *Response) { - payload, _ := json.Marshal(patch) - url := fmt.Sprintf("%s/link", c.GetGroupSyncableRoute(groupID, syncableID, syncableType)) - r, appErr := c.DoApiPost(url, string(payload)) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return GroupSyncableFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) UnlinkGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType) *Response { - url := fmt.Sprintf("%s/link", c.GetGroupSyncableRoute(groupID, syncableID, syncableType)) - r, appErr := c.DoApiDelete(url) - if appErr != nil { - return BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return BuildResponse(r) -} - -func (c *Client4) GetGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType, etag string) (*GroupSyncable, *Response) { - r, appErr := c.DoApiGet(c.GetGroupSyncableRoute(groupID, syncableID, syncableType), etag) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return GroupSyncableFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) GetGroupSyncables(groupID string, syncableType GroupSyncableType, etag string) ([]*GroupSyncable, *Response) { - r, appErr := c.DoApiGet(c.GetGroupSyncablesRoute(groupID, syncableType), etag) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return GroupSyncablesFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) PatchGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType, patch *GroupSyncablePatch) (*GroupSyncable, *Response) { - payload, _ := json.Marshal(patch) - r, appErr := c.DoApiPut(c.GetGroupSyncableRoute(groupID, syncableID, syncableType)+"/patch", string(payload)) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return GroupSyncableFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) TeamMembersMinusGroupMembers(teamID string, groupIDs []string, page, perPage int, etag string) ([]*UserWithGroups, int64, *Response) { - groupIDStr := strings.Join(groupIDs, ",") - query := fmt.Sprintf("?group_ids=%s&page=%d&per_page=%d", groupIDStr, page, perPage) - r, err := c.DoApiGet(c.GetTeamRoute(teamID)+"/members_minus_group_members"+query, etag) - if err != nil { - return nil, 0, BuildErrorResponse(r, err) - } - defer closeBody(r) - ugc := UsersWithGroupsAndCountFromJson(r.Body) - return ugc.Users, ugc.Count, BuildResponse(r) -} - -func (c *Client4) ChannelMembersMinusGroupMembers(channelID string, groupIDs []string, page, perPage int, etag string) ([]*UserWithGroups, int64, *Response) { - groupIDStr := strings.Join(groupIDs, ",") - query := fmt.Sprintf("?group_ids=%s&page=%d&per_page=%d", groupIDStr, page, perPage) - r, err := c.DoApiGet(c.GetChannelRoute(channelID)+"/members_minus_group_members"+query, etag) - if err != nil { - return nil, 0, BuildErrorResponse(r, err) - } - defer closeBody(r) - ugc := UsersWithGroupsAndCountFromJson(r.Body) - return ugc.Users, ugc.Count, BuildResponse(r) -} - -func (c *Client4) PatchConfig(config *Config) (*Config, *Response) { - r, err := c.DoApiPut(c.GetConfigRoute()+"/patch", config.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ConfigFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) GetChannelModerations(channelID string, etag string) ([]*ChannelModeration, *Response) { - r, err := c.DoApiGet(c.GetChannelRoute(channelID)+"/moderations", etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelModerationsFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) PatchChannelModerations(channelID string, patch []*ChannelModerationPatch) ([]*ChannelModeration, *Response) { - payload, _ := json.Marshal(patch) - r, err := c.DoApiPut(c.GetChannelRoute(channelID)+"/moderations/patch", string(payload)) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelModerationsFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) GetKnownUsers() ([]string, *Response) { - r, err := c.DoApiGet(c.GetUsersRoute()+"/known", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - var userIds []string - json.NewDecoder(r.Body).Decode(&userIds) - return userIds, BuildResponse(r) -} - -// PublishUserTyping publishes a user is typing websocket event based on the provided TypingRequest. -func (c *Client4) PublishUserTyping(userID string, typingRequest TypingRequest) (bool, *Response) { - r, err := c.DoApiPost(c.GetPublishUserTypingRoute(userID), typingRequest.ToJson()) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -func (c *Client4) GetChannelMemberCountsByGroup(channelID string, includeTimezones bool, etag string) ([]*ChannelMemberCountByGroup, *Response) { - r, err := c.DoApiGet(c.GetChannelRoute(channelID)+"/member_counts_by_group?include_timezones="+strconv.FormatBool(includeTimezones), etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ChannelMemberCountsByGroupFromJson(r.Body), BuildResponse(r) -} - -// RequestTrialLicense will request a trial license and install it in the server -func (c *Client4) RequestTrialLicense(users int) (bool, *Response) { - b, _ := json.Marshal(map[string]interface{}{"users": users, "terms_accepted": true}) - r, err := c.DoApiPost("/trial-license", string(b)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -// GetGroupStats retrieves stats for a Mattermost Group -func (c *Client4) GetGroupStats(groupID string) (*GroupStats, *Response) { - r, appErr := c.DoApiGet(c.GetGroupRoute(groupID)+"/stats", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - return GroupStatsFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) GetSidebarCategoriesForTeamForUser(userID, teamID, etag string) (*OrderedSidebarCategories, *Response) { - route := c.GetUserCategoryRoute(userID, teamID) - r, appErr := c.DoApiGet(route, etag) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - cat, err := OrderedSidebarCategoriesFromJson(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.GetSidebarCategoriesForTeamForUser", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) - } - return cat, BuildResponse(r) -} - -func (c *Client4) CreateSidebarCategoryForTeamForUser(userID, teamID string, category *SidebarCategoryWithChannels) (*SidebarCategoryWithChannels, *Response) { - payload, _ := json.Marshal(category) - route := c.GetUserCategoryRoute(userID, teamID) - r, appErr := c.doApiPostBytes(route, payload) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - cat, err := SidebarCategoryFromJson(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.CreateSidebarCategoryForTeamForUser", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) - } - return cat, BuildResponse(r) -} - -func (c *Client4) UpdateSidebarCategoriesForTeamForUser(userID, teamID string, categories []*SidebarCategoryWithChannels) ([]*SidebarCategoryWithChannels, *Response) { - payload, _ := json.Marshal(categories) - route := c.GetUserCategoryRoute(userID, teamID) - - r, appErr := c.doApiPutBytes(route, payload) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - categories, err := SidebarCategoriesFromJson(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.UpdateSidebarCategoriesForTeamForUser", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) - } - - return categories, BuildResponse(r) -} - -func (c *Client4) GetSidebarCategoryOrderForTeamForUser(userID, teamID, etag string) ([]string, *Response) { - route := c.GetUserCategoryRoute(userID, teamID) + "/order" - r, err := c.DoApiGet(route, etag) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ArrayFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) UpdateSidebarCategoryOrderForTeamForUser(userID, teamID string, order []string) ([]string, *Response) { - payload, _ := json.Marshal(order) - route := c.GetUserCategoryRoute(userID, teamID) + "/order" - r, err := c.doApiPutBytes(route, payload) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ArrayFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) GetSidebarCategoryForTeamForUser(userID, teamID, categoryID, etag string) (*SidebarCategoryWithChannels, *Response) { - route := c.GetUserCategoryRoute(userID, teamID) + "/" + categoryID - r, appErr := c.DoApiGet(route, etag) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - cat, err := SidebarCategoryFromJson(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.UpdateSidebarCategoriesForTeamForUser", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) - } - - return cat, BuildResponse(r) -} - -func (c *Client4) UpdateSidebarCategoryForTeamForUser(userID, teamID, categoryID string, category *SidebarCategoryWithChannels) (*SidebarCategoryWithChannels, *Response) { - payload, _ := json.Marshal(category) - route := c.GetUserCategoryRoute(userID, teamID) + "/" + categoryID - r, appErr := c.doApiPutBytes(route, payload) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - cat, err := SidebarCategoryFromJson(r.Body) - if err != nil { - return nil, BuildErrorResponse(r, NewAppError("Client4.UpdateSidebarCategoriesForTeamForUser", "model.utils.decode_json.app_error", nil, err.Error(), r.StatusCode)) - } - - return cat, BuildResponse(r) -} - -// CheckIntegrity performs a database integrity check. -func (c *Client4) CheckIntegrity() ([]IntegrityCheckResult, *Response) { - r, err := c.DoApiPost("/integrity", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - var results []IntegrityCheckResult - if err := json.NewDecoder(r.Body).Decode(&results); err != nil { - appErr := NewAppError("Api4.CheckIntegrity", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError) - return nil, BuildErrorResponse(r, appErr) - } - return results, BuildResponse(r) -} - -func (c *Client4) GetNotices(lastViewed int64, teamId string, client NoticeClientType, clientVersion, locale, etag string) (NoticeMessages, *Response) { - url := fmt.Sprintf("/system/notices/%s?lastViewed=%d&client=%s&clientVersion=%s&locale=%s", teamId, lastViewed, client, clientVersion, locale) - r, appErr := c.DoApiGet(url, etag) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - notices, err := UnmarshalProductNoticeMessages(r.Body) - if err != nil { - return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)} - } - return notices, BuildResponse(r) -} - -func (c *Client4) MarkNoticesViewed(ids []string) *Response { - r, err := c.DoApiPut("/system/notices/view", ArrayToJson(ids)) - if err != nil { - return BuildErrorResponse(r, err) - } - defer closeBody(r) - return BuildResponse(r) -} - -// CreateUpload creates a new upload session. -func (c *Client4) CreateUpload(us *UploadSession) (*UploadSession, *Response) { - r, err := c.DoApiPost(c.GetUploadsRoute(), us.ToJson()) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UploadSessionFromJson(r.Body), BuildResponse(r) -} - -// GetUpload returns the upload session for the specified uploadId. -func (c *Client4) GetUpload(uploadId string) (*UploadSession, *Response) { - r, err := c.DoApiGet(c.GetUploadRoute(uploadId), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UploadSessionFromJson(r.Body), BuildResponse(r) -} - -// GetUploadsForUser returns the upload sessions created by the specified -// userId. -func (c *Client4) GetUploadsForUser(userId string) ([]*UploadSession, *Response) { - r, err := c.DoApiGet(c.GetUserRoute(userId)+"/uploads", "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return UploadSessionsFromJson(r.Body), BuildResponse(r) -} - -// UploadData performs an upload. On success it returns -// a FileInfo object. -func (c *Client4) UploadData(uploadId string, data io.Reader) (*FileInfo, *Response) { - url := c.GetUploadRoute(uploadId) - r, err := c.doApiRequestReader("POST", c.ApiUrl+url, data, nil) - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return FileInfoFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) UpdatePassword(userId, currentPassword, newPassword string) *Response { - requestBody := map[string]string{"current_password": currentPassword, "new_password": newPassword} - r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody)) - if err != nil { - return BuildErrorResponse(r, err) - } - defer closeBody(r) - return BuildResponse(r) -} - -// Cloud Section - -func (c *Client4) GetCloudProducts() ([]*Product, *Response) { - r, appErr := c.DoApiGet(c.GetCloudRoute()+"/products", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var cloudProducts []*Product - json.NewDecoder(r.Body).Decode(&cloudProducts) - - return cloudProducts, BuildResponse(r) -} - -func (c *Client4) CreateCustomerPayment() (*StripeSetupIntent, *Response) { - r, appErr := c.DoApiPost(c.GetCloudRoute()+"/payment", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var setupIntent *StripeSetupIntent - json.NewDecoder(r.Body).Decode(&setupIntent) - - return setupIntent, BuildResponse(r) -} - -func (c *Client4) ConfirmCustomerPayment(confirmRequest *ConfirmPaymentMethodRequest) *Response { - json, _ := json.Marshal(confirmRequest) - - r, appErr := c.doApiPostBytes(c.GetCloudRoute()+"/payment/confirm", json) - if appErr != nil { - return BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - return BuildResponse(r) -} - -func (c *Client4) GetCloudCustomer() (*CloudCustomer, *Response) { - r, appErr := c.DoApiGet(c.GetCloudRoute()+"/customer", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var cloudCustomer *CloudCustomer - json.NewDecoder(r.Body).Decode(&cloudCustomer) - - return cloudCustomer, BuildResponse(r) -} - -func (c *Client4) GetSubscription() (*Subscription, *Response) { - r, appErr := c.DoApiGet(c.GetCloudRoute()+"/subscription", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var subscription *Subscription - json.NewDecoder(r.Body).Decode(&subscription) - - return subscription, BuildResponse(r) -} - -func (c *Client4) GetSubscriptionStats() (*SubscriptionStats, *Response) { - r, appErr := c.DoApiGet(c.GetCloudRoute()+"/subscription/stats", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var stats *SubscriptionStats - json.NewDecoder(r.Body).Decode(&stats) - return stats, BuildResponse(r) -} - -func (c *Client4) GetInvoicesForSubscription() ([]*Invoice, *Response) { - r, appErr := c.DoApiGet(c.GetCloudRoute()+"/subscription/invoices", "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var invoices []*Invoice - json.NewDecoder(r.Body).Decode(&invoices) - - return invoices, BuildResponse(r) -} - -func (c *Client4) UpdateCloudCustomer(customerInfo *CloudCustomerInfo) (*CloudCustomer, *Response) { - customerBytes, _ := json.Marshal(customerInfo) - - r, appErr := c.doApiPutBytes(c.GetCloudRoute()+"/customer", customerBytes) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var customer *CloudCustomer - json.NewDecoder(r.Body).Decode(&customer) - - return customer, BuildResponse(r) -} - -func (c *Client4) UpdateCloudCustomerAddress(address *Address) (*CloudCustomer, *Response) { - addressBytes, _ := json.Marshal(address) - - r, appErr := c.doApiPutBytes(c.GetCloudRoute()+"/customer/address", addressBytes) - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var customer *CloudCustomer - json.NewDecoder(r.Body).Decode(&customer) - - return customer, BuildResponse(r) -} - -func (c *Client4) ListImports() ([]string, *Response) { - r, err := c.DoApiGet(c.GetImportsRoute(), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ArrayFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) ListExports() ([]string, *Response) { - r, err := c.DoApiGet(c.GetExportsRoute(), "") - if err != nil { - return nil, BuildErrorResponse(r, err) - } - defer closeBody(r) - return ArrayFromJson(r.Body), BuildResponse(r) -} - -func (c *Client4) DeleteExport(name string) (bool, *Response) { - r, err := c.DoApiDelete(c.GetExportRoute(name)) - if err != nil { - return false, BuildErrorResponse(r, err) - } - defer closeBody(r) - return CheckStatusOK(r), BuildResponse(r) -} - -func (c *Client4) DownloadExport(name string, wr io.Writer, offset int64) (int64, *Response) { - var headers map[string]string - if offset > 0 { - headers = map[string]string{ - HEADER_RANGE: fmt.Sprintf("bytes=%d-", offset), - } - } - r, appErr := c.DoApiRequestWithHeaders(http.MethodGet, c.ApiUrl+c.GetExportRoute(name), "", headers) - if appErr != nil { - return 0, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - n, err := io.Copy(wr, r.Body) - if err != nil { - return n, BuildErrorResponse(r, NewAppError("DownloadExport", "model.client.copy.app_error", nil, err.Error(), r.StatusCode)) - } - return n, BuildResponse(r) -} - -func (c *Client4) GetUserThreads(userId, teamId string, options GetUserThreadsOpts) (*Threads, *Response) { - v := url.Values{} - if options.Since != 0 { - v.Set("since", fmt.Sprintf("%d", options.Since)) - } - if options.Before != "" { - v.Set("before", options.Before) - } - if options.After != "" { - v.Set("after", options.After) - } - if options.PageSize != 0 { - v.Set("pageSize", fmt.Sprintf("%d", options.PageSize)) - } - if options.Extended { - v.Set("extended", "true") - } - if options.Deleted { - v.Set("deleted", "true") - } - if options.Unread { - v.Set("unread", "true") - } - url := c.GetUserThreadsRoute(userId, teamId) - if len(v) > 0 { - url += "?" + v.Encode() - } - - r, appErr := c.DoApiGet(url, "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var threads Threads - json.NewDecoder(r.Body).Decode(&threads) - - return &threads, BuildResponse(r) -} - -func (c *Client4) GetUserThread(userId, teamId, threadId string, extended bool) (*ThreadResponse, *Response) { - url := c.GetUserThreadRoute(userId, teamId, threadId) - if extended { - url += "?extended=true" - } - r, appErr := c.DoApiGet(url, "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var thread ThreadResponse - json.NewDecoder(r.Body).Decode(&thread) - - return &thread, BuildResponse(r) -} - -func (c *Client4) UpdateThreadsReadForUser(userId, teamId string) *Response { - r, appErr := c.DoApiPut(fmt.Sprintf("%s/read", c.GetUserThreadsRoute(userId, teamId)), "") - if appErr != nil { - return BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - return BuildResponse(r) -} - -func (c *Client4) UpdateThreadReadForUser(userId, teamId, threadId string, timestamp int64) (*ThreadResponse, *Response) { - r, appErr := c.DoApiPut(fmt.Sprintf("%s/read/%d", c.GetUserThreadRoute(userId, teamId, threadId), timestamp), "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - var thread ThreadResponse - json.NewDecoder(r.Body).Decode(&thread) - - return &thread, BuildResponse(r) -} - -func (c *Client4) UpdateThreadFollowForUser(userId, teamId, threadId string, state bool) *Response { - var appErr *AppError - var r *http.Response - if state { - r, appErr = c.DoApiPut(c.GetUserThreadRoute(userId, teamId, threadId)+"/following", "") - } else { - r, appErr = c.DoApiDelete(c.GetUserThreadRoute(userId, teamId, threadId) + "/following") - } - if appErr != nil { - return BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - return BuildResponse(r) -} - -func (c *Client4) SendAdminUpgradeRequestEmail() *Response { - r, appErr := c.DoApiPost(c.GetCloudRoute()+"/subscription/limitreached/invite", "") - if appErr != nil { - return BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - return BuildResponse(r) -} - -func (c *Client4) SendAdminUpgradeRequestEmailOnJoin() *Response { - r, appErr := c.DoApiPost(c.GetCloudRoute()+"/subscription/limitreached/join", "") - if appErr != nil { - return BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - return BuildResponse(r) -} - -func (c *Client4) GetAllSharedChannels(teamID string, page, perPage int) ([]*SharedChannel, *Response) { - url := fmt.Sprintf("%s/%s?page=%d&per_page=%d", c.GetSharedChannelsRoute(), teamID, page, perPage) - r, appErr := c.DoApiGet(url, "") - if appErr != nil { - return nil, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var channels []*SharedChannel - json.NewDecoder(r.Body).Decode(&channels) - - return channels, BuildResponse(r) -} - -func (c *Client4) GetRemoteClusterInfo(remoteID string) (RemoteClusterInfo, *Response) { - url := fmt.Sprintf("%s/remote_info/%s", c.GetSharedChannelsRoute(), remoteID) - r, appErr := c.DoApiGet(url, "") - if appErr != nil { - return RemoteClusterInfo{}, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - var rci RemoteClusterInfo - json.NewDecoder(r.Body).Decode(&rci) - - return rci, BuildResponse(r) -} - -func (c *Client4) GetAncillaryPermissions(subsectionPermissions []string) ([]string, *Response) { - var returnedPermissions []string - url := fmt.Sprintf("%s/ancillary?subsection_permissions=%s", c.GetPermissionsRoute(), strings.Join(subsectionPermissions, ",")) - r, appErr := c.DoApiGet(url, "") - if appErr != nil { - return returnedPermissions, BuildErrorResponse(r, appErr) - } - defer closeBody(r) - - json.NewDecoder(r.Body).Decode(&returnedPermissions) - return returnedPermissions, BuildResponse(r) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/cloud.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cloud.go deleted file mode 100644 index ffd85a2a..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/cloud.go +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import "strings" - -const ( - EventTypeFailedPayment = "failed-payment" - EventTypeFailedPaymentNoCard = "failed-payment-no-card" - EventTypeSendAdminWelcomeEmail = "send-admin-welcome-email" - EventTypeTrialWillEnd = "trial-will-end" - EventTypeTrialEnded = "trial-ended" - JoinLimitation = "join" - InviteLimitation = "invite" -) - -var MockCWS string - -type BillingScheme string - -const ( - BillingSchemePerSeat = BillingScheme("per_seat") - BillingSchemeFlatFee = BillingScheme("flat_fee") -) - -type RecurringInterval string - -const ( - RecurringIntervalYearly = RecurringInterval("year") - RecurringIntervalMonthly = RecurringInterval("month") -) - -type SubscriptionFamily string - -const ( - SubscriptionFamilyCloud = SubscriptionFamily("cloud") - SubscriptionFamilyOnPrem = SubscriptionFamily("on-prem") -) - -// Product model represents a product on the cloud system. -type Product struct { - ID string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - PricePerSeat float64 `json:"price_per_seat"` - AddOns []*AddOn `json:"add_ons"` - SKU string `json:"sku"` - PriceID string `json:"price_id"` - Family SubscriptionFamily `json:"product_family"` - RecurringInterval RecurringInterval `json:"recurring_interval"` - BillingScheme BillingScheme `json:"billing_scheme"` -} - -// AddOn represents an addon to a product. -type AddOn struct { - ID string `json:"id"` - Name string `json:"name"` - DisplayName string `json:"display_name"` - PricePerSeat float64 `json:"price_per_seat"` -} - -// StripeSetupIntent represents the SetupIntent model from Stripe for updating payment methods. -type StripeSetupIntent struct { - ID string `json:"id"` - ClientSecret string `json:"client_secret"` -} - -// ConfirmPaymentMethodRequest contains the fields for the customer payment update API. -type ConfirmPaymentMethodRequest struct { - StripeSetupIntentID string `json:"stripe_setup_intent_id"` -} - -// Customer model represents a customer on the system. -type CloudCustomer struct { - CloudCustomerInfo - ID string `json:"id"` - CreatorID string `json:"creator_id"` - CreateAt int64 `json:"create_at"` - BillingAddress *Address `json:"billing_address"` - CompanyAddress *Address `json:"company_address"` - PaymentMethod *PaymentMethod `json:"payment_method"` -} - -// CloudCustomerInfo represents editable info of a customer. -type CloudCustomerInfo struct { - Name string `json:"name"` - Email string `json:"email,omitempty"` - ContactFirstName string `json:"contact_first_name,omitempty"` - ContactLastName string `json:"contact_last_name,omitempty"` - NumEmployees int `json:"num_employees"` -} - -// Address model represents a customer's address. -type Address struct { - City string `json:"city"` - Country string `json:"country"` - Line1 string `json:"line1"` - Line2 string `json:"line2"` - PostalCode string `json:"postal_code"` - State string `json:"state"` -} - -// PaymentMethod represents methods of payment for a customer. -type PaymentMethod struct { - Type string `json:"type"` - LastFour int `json:"last_four"` - ExpMonth int `json:"exp_month"` - ExpYear int `json:"exp_year"` - CardBrand string `json:"card_brand"` - Name string `json:"name"` -} - -// Subscription model represents a subscription on the system. -type Subscription struct { - ID string `json:"id"` - CustomerID string `json:"customer_id"` - ProductID string `json:"product_id"` - AddOns []string `json:"add_ons"` - StartAt int64 `json:"start_at"` - EndAt int64 `json:"end_at"` - CreateAt int64 `json:"create_at"` - Seats int `json:"seats"` - Status string `json:"status"` - DNS string `json:"dns"` - IsPaidTier string `json:"is_paid_tier"` - LastInvoice *Invoice `json:"last_invoice"` - IsFreeTrial string `json:"is_free_trial"` - TrialEndAt int64 `json:"trial_end_at"` -} - -// GetWorkSpaceNameFromDNS returns the work space name. For example from test.mattermost.cloud.com, it returns test -func (s *Subscription) GetWorkSpaceNameFromDNS() string { - return strings.Split(s.DNS, ".")[0] -} - -// Invoice model represents a cloud invoice -type Invoice struct { - ID string `json:"id"` - Number string `json:"number"` - CreateAt int64 `json:"create_at"` - Total int64 `json:"total"` - Tax int64 `json:"tax"` - Status string `json:"status"` - Description string `json:"description"` - PeriodStart int64 `json:"period_start"` - PeriodEnd int64 `json:"period_end"` - SubscriptionID string `json:"subscription_id"` - Items []*InvoiceLineItem `json:"line_items"` -} - -// InvoiceLineItem model represents a cloud invoice lineitem tied to an invoice. -type InvoiceLineItem struct { - PriceID string `json:"price_id"` - Total int64 `json:"total"` - Quantity int64 `json:"quantity"` - PricePerUnit int64 `json:"price_per_unit"` - Description string `json:"description"` - Type string `json:"type"` - Metadata map[string]interface{} `json:"metadata"` -} - -type CWSWebhookPayload struct { - Event string `json:"event"` - FailedPayment *FailedPayment `json:"failed_payment"` - CloudWorkspaceOwner *CloudWorkspaceOwner `json:"cloud_workspace_owner"` - SubscriptionTrialEndUnixTimeStamp int64 `json:"trial_end_time_stamp"` -} - -type FailedPayment struct { - CardBrand string `json:"card_brand"` - LastFour int `json:"last_four"` - FailureMessage string `json:"failure_message"` -} - -// CloudWorkspaceOwner is part of the CWS Webhook payload that contains information about the user that created the workspace from the CWS -type CloudWorkspaceOwner struct { - UserName string `json:"username"` -} -type SubscriptionStats struct { - RemainingSeats int `json:"remaining_seats"` - IsPaidTier string `json:"is_paid_tier"` - IsFreeTrial string `json:"is_free_trial"` -} - -type SubscriptionChange struct { - ProductID string `json:"product_id"` -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_discovery.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_discovery.go deleted file mode 100644 index 758e4980..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_discovery.go +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" - "os" -) - -const ( - CDS_OFFLINE_AFTER_MILLIS = 1000 * 60 * 30 // 30 minutes - CDS_TYPE_APP = "mattermost_app" -) - -type ClusterDiscovery struct { - Id string `json:"id"` - Type string `json:"type"` - ClusterName string `json:"cluster_name"` - Hostname string `json:"hostname"` - GossipPort int32 `json:"gossip_port"` - Port int32 `json:"port"` - CreateAt int64 `json:"create_at"` - LastPingAt int64 `json:"last_ping_at"` -} - -func (o *ClusterDiscovery) PreSave() { - if o.Id == "" { - o.Id = NewId() - } - - if o.CreateAt == 0 { - o.CreateAt = GetMillis() - o.LastPingAt = o.CreateAt - } -} - -func (o *ClusterDiscovery) AutoFillHostname() { - // attempt to set the hostname from the OS - if o.Hostname == "" { - if hn, err := os.Hostname(); err == nil { - o.Hostname = hn - } - } -} - -func (o *ClusterDiscovery) AutoFillIpAddress(iface string, ipAddress string) { - // attempt to set the hostname to the first non-local IP address - if o.Hostname == "" { - if ipAddress != "" { - o.Hostname = ipAddress - } else { - o.Hostname = GetServerIpAddress(iface) - } - } -} - -func (o *ClusterDiscovery) IsEqual(in *ClusterDiscovery) bool { - if in == nil { - return false - } - - if o.Type != in.Type { - return false - } - - if o.ClusterName != in.ClusterName { - return false - } - - if o.Hostname != in.Hostname { - return false - } - - return true -} - -func FilterClusterDiscovery(vs []*ClusterDiscovery, f func(*ClusterDiscovery) bool) []*ClusterDiscovery { - copy := make([]*ClusterDiscovery, 0) - for _, v := range vs { - if f(v) { - copy = append(copy, v) - } - } - - return copy -} - -func (o *ClusterDiscovery) IsValid() *AppError { - if !IsValidId(o.Id) { - return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.id.app_error", nil, "", http.StatusBadRequest) - } - - if o.ClusterName == "" { - return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.name.app_error", nil, "", http.StatusBadRequest) - } - - if o.Type == "" { - return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.type.app_error", nil, "", http.StatusBadRequest) - } - - if o.Hostname == "" { - return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.hostname.app_error", nil, "", http.StatusBadRequest) - } - - if o.CreateAt == 0 { - return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) - } - - if o.LastPingAt == 0 { - return NewAppError("ClusterDiscovery.IsValid", "model.cluster.is_valid.last_ping_at.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (o *ClusterDiscovery) ToJson() string { - b, err := json.Marshal(o) - if err != nil { - return "" - } - - return string(b) -} - -func ClusterDiscoveryFromJson(data io.Reader) *ClusterDiscovery { - decoder := json.NewDecoder(data) - var me ClusterDiscovery - err := decoder.Decode(&me) - if err == nil { - return &me - } - - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_info.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_info.go deleted file mode 100644 index fc15d38c..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_info.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type ClusterInfo struct { - Id string `json:"id"` - Version string `json:"version"` - ConfigHash string `json:"config_hash"` - IpAddress string `json:"ipaddress"` - Hostname string `json:"hostname"` -} - -func (ci *ClusterInfo) ToJson() string { - b, _ := json.Marshal(ci) - return string(b) -} - -func ClusterInfoFromJson(data io.Reader) *ClusterInfo { - var ci *ClusterInfo - json.NewDecoder(data).Decode(&ci) - return ci -} - -func ClusterInfosToJson(objmap []*ClusterInfo) string { - b, _ := json.Marshal(objmap) - return string(b) -} - -func ClusterInfosFromJson(data io.Reader) []*ClusterInfo { - decoder := json.NewDecoder(data) - - var objmap []*ClusterInfo - if err := decoder.Decode(&objmap); err != nil { - return make([]*ClusterInfo, 0) - } - return objmap -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_message.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_message.go deleted file mode 100644 index bd73ba8d..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_message.go +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -const ( - CLUSTER_EVENT_PUBLISH = "publish" - CLUSTER_EVENT_UPDATE_STATUS = "update_status" - CLUSTER_EVENT_INVALIDATE_ALL_CACHES = "inv_all_caches" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_REACTIONS = "inv_reactions" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_WEBHOOK = "inv_webhook" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_POSTS = "inv_channel_posts" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBERS_NOTIFY_PROPS = "inv_channel_members_notify_props" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBERS = "inv_channel_members" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_BY_NAME = "inv_channel_name" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL = "inv_channel" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_GUEST_COUNT = "inv_channel_guest_count" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_USER = "inv_user" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_USER_TEAMS = "inv_user_teams" - CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_USER = "clear_session_user" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES = "inv_roles" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLE_PERMISSIONS = "inv_role_permissions" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_BY_IDS = "inv_profile_ids" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_PROFILE_IN_CHANNEL = "inv_profile_in_channel" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES = "inv_schemes" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_FILE_INFOS = "inv_file_infos" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_WEBHOOKS = "inv_webhooks" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_BY_ID = "inv_emojis_by_id" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_ID_BY_NAME = "inv_emojis_id_by_name" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_PINNEDPOSTS_COUNTS = "inv_channel_pinnedposts_counts" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBER_COUNTS = "inv_channel_member_counts" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POSTS = "inv_last_posts" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_LAST_POST_TIME = "inv_last_post_time" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TEAMS = "inv_teams" - CLUSTER_EVENT_CLEAR_SESSION_CACHE_FOR_ALL_USERS = "inv_all_user_sessions" - CLUSTER_EVENT_INSTALL_PLUGIN = "install_plugin" - CLUSTER_EVENT_REMOVE_PLUGIN = "remove_plugin" - CLUSTER_EVENT_PLUGIN_EVENT = "plugin_event" - CLUSTER_EVENT_INVALIDATE_CACHE_FOR_TERMS_OF_SERVICE = "inv_terms_of_service" - CLUSTER_EVENT_BUSY_STATE_CHANGED = "busy_state_change" - - // Gossip communication - CLUSTER_GOSSIP_EVENT_REQUEST_GET_LOGS = "gossip_request_get_logs" - CLUSTER_GOSSIP_EVENT_RESPONSE_GET_LOGS = "gossip_response_get_logs" - CLUSTER_GOSSIP_EVENT_REQUEST_GET_CLUSTER_STATS = "gossip_request_cluster_stats" - CLUSTER_GOSSIP_EVENT_RESPONSE_GET_CLUSTER_STATS = "gossip_response_cluster_stats" - CLUSTER_GOSSIP_EVENT_REQUEST_GET_PLUGIN_STATUSES = "gossip_request_plugin_statuses" - CLUSTER_GOSSIP_EVENT_RESPONSE_GET_PLUGIN_STATUSES = "gossip_response_plugin_statuses" - CLUSTER_GOSSIP_EVENT_REQUEST_SAVE_CONFIG = "gossip_request_save_config" - CLUSTER_GOSSIP_EVENT_RESPONSE_SAVE_CONFIG = "gossip_response_save_config" - - // SendTypes for ClusterMessage. - CLUSTER_SEND_BEST_EFFORT = "best_effort" - CLUSTER_SEND_RELIABLE = "reliable" -) - -type ClusterMessage struct { - Event string `json:"event"` - SendType string `json:"-"` - WaitForAllToSend bool `json:"-"` - Data string `json:"data,omitempty"` - Props map[string]string `json:"props,omitempty"` -} - -func (o *ClusterMessage) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func ClusterMessageFromJson(data io.Reader) *ClusterMessage { - var o *ClusterMessage - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_stats.go b/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_stats.go deleted file mode 100644 index 9e8c630c..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/cluster_stats.go +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type ClusterStats struct { - Id string `json:"id"` - TotalWebsocketConnections int `json:"total_websocket_connections"` - TotalReadDbConnections int `json:"total_read_db_connections"` - TotalMasterDbConnections int `json:"total_master_db_connections"` -} - -func (cs *ClusterStats) ToJson() string { - b, _ := json.Marshal(cs) - return string(b) -} - -func ClusterStatsFromJson(data io.Reader) *ClusterStats { - var cs *ClusterStats - json.NewDecoder(data).Decode(&cs) - return cs -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command.go deleted file mode 100644 index 59a4eee4..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/command.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" - "strings" -) - -const ( - COMMAND_METHOD_POST = "P" - COMMAND_METHOD_GET = "G" - MIN_TRIGGER_LENGTH = 1 - MAX_TRIGGER_LENGTH = 128 -) - -type Command struct { - Id string `json:"id"` - Token string `json:"token"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - CreatorId string `json:"creator_id"` - TeamId string `json:"team_id"` - Trigger string `json:"trigger"` - Method string `json:"method"` - Username string `json:"username"` - IconURL string `json:"icon_url"` - AutoComplete bool `json:"auto_complete"` - AutoCompleteDesc string `json:"auto_complete_desc"` - AutoCompleteHint string `json:"auto_complete_hint"` - DisplayName string `json:"display_name"` - Description string `json:"description"` - URL string `json:"url"` - // PluginId records the id of the plugin that created this Command. If it is blank, the Command - // was not created by a plugin. - PluginId string `json:"plugin_id"` - AutocompleteData *AutocompleteData `db:"-" json:"autocomplete_data,omitempty"` - // AutocompleteIconData is a base64 encoded svg - AutocompleteIconData string `db:"-" json:"autocomplete_icon_data,omitempty"` -} - -func (o *Command) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func CommandFromJson(data io.Reader) *Command { - var o *Command - json.NewDecoder(data).Decode(&o) - return o -} - -func CommandListToJson(l []*Command) string { - b, _ := json.Marshal(l) - return string(b) -} - -func CommandListFromJson(data io.Reader) []*Command { - var o []*Command - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *Command) IsValid() *AppError { - - if !IsValidId(o.Id) { - return NewAppError("Command.IsValid", "model.command.is_valid.id.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.Token) != 26 { - return NewAppError("Command.IsValid", "model.command.is_valid.token.app_error", nil, "", http.StatusBadRequest) - } - - if o.CreateAt == 0 { - return NewAppError("Command.IsValid", "model.command.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) - } - - if o.UpdateAt == 0 { - return NewAppError("Command.IsValid", "model.command.is_valid.update_at.app_error", nil, "", http.StatusBadRequest) - } - - // If the CreatorId is blank, this should be a command created by a plugin. - if o.CreatorId == "" && !IsValidPluginId(o.PluginId) { - return NewAppError("Command.IsValid", "model.command.is_valid.plugin_id.app_error", nil, "", http.StatusBadRequest) - } - - // If the PluginId is blank, this should be a command associated with a userId. - if o.PluginId == "" && !IsValidId(o.CreatorId) { - return NewAppError("Command.IsValid", "model.command.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) - } - - if o.CreatorId != "" && o.PluginId != "" { - return NewAppError("Command.IsValid", "model.command.is_valid.plugin_id.app_error", nil, "command cannot have both a CreatorId and a PluginId", http.StatusBadRequest) - } - - if !IsValidId(o.TeamId) { - return NewAppError("Command.IsValid", "model.command.is_valid.team_id.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.Trigger) < MIN_TRIGGER_LENGTH || len(o.Trigger) > MAX_TRIGGER_LENGTH || strings.Index(o.Trigger, "/") == 0 || strings.Contains(o.Trigger, " ") { - return NewAppError("Command.IsValid", "model.command.is_valid.trigger.app_error", nil, "", http.StatusBadRequest) - } - - if o.URL == "" || len(o.URL) > 1024 { - return NewAppError("Command.IsValid", "model.command.is_valid.url.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidHttpUrl(o.URL) { - return NewAppError("Command.IsValid", "model.command.is_valid.url_http.app_error", nil, "", http.StatusBadRequest) - } - - if !(o.Method == COMMAND_METHOD_GET || o.Method == COMMAND_METHOD_POST) { - return NewAppError("Command.IsValid", "model.command.is_valid.method.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.DisplayName) > 64 { - return NewAppError("Command.IsValid", "model.command.is_valid.display_name.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.Description) > 128 { - return NewAppError("Command.IsValid", "model.command.is_valid.description.app_error", nil, "", http.StatusBadRequest) - } - - if o.AutocompleteData != nil { - if err := o.AutocompleteData.IsValid(); err != nil { - return NewAppError("Command.IsValid", "model.command.is_valid.autocomplete_data.app_error", nil, err.Error(), http.StatusBadRequest) - } - } - - return nil -} - -func (o *Command) PreSave() { - if o.Id == "" { - o.Id = NewId() - } - - if o.Token == "" { - o.Token = NewId() - } - - o.CreateAt = GetMillis() - o.UpdateAt = o.CreateAt -} - -func (o *Command) PreUpdate() { - o.UpdateAt = GetMillis() -} - -func (o *Command) Sanitize() { - o.Token = "" - o.CreatorId = "" - o.Method = "" - o.URL = "" - o.Username = "" - o.IconURL = "" -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_args.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_args.go deleted file mode 100644 index 45239d2c..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/command_args.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - - "github.com/mattermost/mattermost-server/v5/shared/i18n" -) - -type CommandArgs struct { - UserId string `json:"user_id"` - ChannelId string `json:"channel_id"` - TeamId string `json:"team_id"` - RootId string `json:"root_id"` - ParentId string `json:"parent_id"` - TriggerId string `json:"trigger_id,omitempty"` - Command string `json:"command"` - SiteURL string `json:"-"` - T i18n.TranslateFunc `json:"-"` - UserMentions UserMentionMap `json:"-"` - ChannelMentions ChannelMentionMap `json:"-"` - - // DO NOT USE Session field is deprecated. MM-26398 - Session Session `json:"-"` -} - -func (o *CommandArgs) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func CommandArgsFromJson(data io.Reader) *CommandArgs { - var o *CommandArgs - json.NewDecoder(data).Decode(&o) - return o -} - -// AddUserMention adds or overrides an entry in UserMentions with name username -// and identifier userId -func (o *CommandArgs) AddUserMention(username, userId string) { - if o.UserMentions == nil { - o.UserMentions = make(UserMentionMap) - } - - o.UserMentions[username] = userId -} - -// AddChannelMention adds or overrides an entry in ChannelMentions with name -// channelName and identifier channelId -func (o *CommandArgs) AddChannelMention(channelName, channelId string) { - if o.ChannelMentions == nil { - o.ChannelMentions = make(ChannelMentionMap) - } - - o.ChannelMentions[channelName] = channelId -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_autocomplete.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_autocomplete.go deleted file mode 100644 index f115ed24..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/command_autocomplete.go +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/url" - "path" - "reflect" - "strings" - - "github.com/pkg/errors" -) - -// AutocompleteArgType describes autocomplete argument type -type AutocompleteArgType string - -// Argument types -const ( - AutocompleteArgTypeText AutocompleteArgType = "TextInput" - AutocompleteArgTypeStaticList AutocompleteArgType = "StaticList" - AutocompleteArgTypeDynamicList AutocompleteArgType = "DynamicList" -) - -// AutocompleteData describes slash command autocomplete information. -type AutocompleteData struct { - // Trigger of the command - Trigger string - // Hint of a command - Hint string - // Text displayed to the user to help with the autocomplete description - HelpText string - // Role of the user who should be able to see the autocomplete info of this command - RoleID string - // Arguments of the command. Arguments can be named or positional. - // If they are positional order in the list matters, if they are named order does not matter. - // All arguments should be either named or positional, no mixing allowed. - Arguments []*AutocompleteArg - // Subcommands of the command - SubCommands []*AutocompleteData -} - -// AutocompleteArg describes an argument of the command. Arguments can be named or positional. -// If Name is empty string Argument is positional otherwise it is named argument. -// Named arguments are passed as --Name Argument_Value. -type AutocompleteArg struct { - // Name of the argument - Name string - // Text displayed to the user to help with the autocomplete - HelpText string - // Type of the argument - Type AutocompleteArgType - // Required determines if argument is optional or not. - Required bool - // Actual data of the argument (depends on the Type) - Data interface{} -} - -// AutocompleteTextArg describes text user can input as an argument. -type AutocompleteTextArg struct { - // Hint of the input text - Hint string - // Regex pattern to match - Pattern string -} - -// AutocompleteListItem describes an item in the AutocompleteStaticListArg. -type AutocompleteListItem struct { - Item string - Hint string - HelpText string -} - -// AutocompleteStaticListArg is used to input one of the arguments from the list, -// for example [yes, no], [on, off], and so on. -type AutocompleteStaticListArg struct { - PossibleArguments []AutocompleteListItem -} - -// AutocompleteDynamicListArg is used when user wants to download possible argument list from the URL. -type AutocompleteDynamicListArg struct { - FetchURL string -} - -// AutocompleteSuggestion describes a single suggestion item sent to the front-end -// Example: for user input `/jira cre` - -// Complete might be `/jira create` -// Suggestion might be `create`, -// Hint might be `[issue text]`, -// Description might be `Create a new Issue` -type AutocompleteSuggestion struct { - // Complete describes completed suggestion - Complete string - // Suggestion describes what user might want to input next - Suggestion string - // Hint describes a hint about the suggested input - Hint string - // Description of the command or a suggestion - Description string - // IconData is base64 encoded svg image - IconData string -} - -// NewAutocompleteData returns new Autocomplete data. -func NewAutocompleteData(trigger, hint, helpText string) *AutocompleteData { - return &AutocompleteData{ - Trigger: trigger, - Hint: hint, - HelpText: helpText, - RoleID: SYSTEM_USER_ROLE_ID, - Arguments: []*AutocompleteArg{}, - SubCommands: []*AutocompleteData{}, - } -} - -// AddCommand adds a subcommand to the autocomplete data. -func (ad *AutocompleteData) AddCommand(command *AutocompleteData) { - ad.SubCommands = append(ad.SubCommands, command) -} - -// AddTextArgument adds positional AutocompleteArgTypeText argument to the command. -func (ad *AutocompleteData) AddTextArgument(helpText, hint, pattern string) { - ad.AddNamedTextArgument("", helpText, hint, pattern, true) -} - -// AddNamedTextArgument adds named AutocompleteArgTypeText argument to the command. -func (ad *AutocompleteData) AddNamedTextArgument(name, helpText, hint, pattern string, required bool) { - argument := AutocompleteArg{ - Name: name, - HelpText: helpText, - Type: AutocompleteArgTypeText, - Required: required, - Data: &AutocompleteTextArg{Hint: hint, Pattern: pattern}, - } - ad.Arguments = append(ad.Arguments, &argument) -} - -// AddStaticListArgument adds positional AutocompleteArgTypeStaticList argument to the command. -func (ad *AutocompleteData) AddStaticListArgument(helpText string, required bool, items []AutocompleteListItem) { - ad.AddNamedStaticListArgument("", helpText, required, items) -} - -// AddNamedStaticListArgument adds named AutocompleteArgTypeStaticList argument to the command. -func (ad *AutocompleteData) AddNamedStaticListArgument(name, helpText string, required bool, items []AutocompleteListItem) { - argument := AutocompleteArg{ - Name: name, - HelpText: helpText, - Type: AutocompleteArgTypeStaticList, - Required: required, - Data: &AutocompleteStaticListArg{PossibleArguments: items}, - } - ad.Arguments = append(ad.Arguments, &argument) -} - -// AddDynamicListArgument adds positional AutocompleteArgTypeDynamicList argument to the command. -func (ad *AutocompleteData) AddDynamicListArgument(helpText, url string, required bool) { - ad.AddNamedDynamicListArgument("", helpText, url, required) -} - -// AddNamedDynamicListArgument adds named AutocompleteArgTypeDynamicList argument to the command. -func (ad *AutocompleteData) AddNamedDynamicListArgument(name, helpText, url string, required bool) { - argument := AutocompleteArg{ - Name: name, - HelpText: helpText, - Type: AutocompleteArgTypeDynamicList, - Required: required, - Data: &AutocompleteDynamicListArg{FetchURL: url}, - } - ad.Arguments = append(ad.Arguments, &argument) -} - -// Equals method checks if command is the same. -func (ad *AutocompleteData) Equals(command *AutocompleteData) bool { - if !(ad.Trigger == command.Trigger && ad.HelpText == command.HelpText && ad.RoleID == command.RoleID && ad.Hint == command.Hint) { - return false - } - if len(ad.Arguments) != len(command.Arguments) || len(ad.SubCommands) != len(command.SubCommands) { - return false - } - for i := range ad.Arguments { - if !ad.Arguments[i].Equals(command.Arguments[i]) { - return false - } - } - for i := range ad.SubCommands { - if !ad.SubCommands[i].Equals(command.SubCommands[i]) { - return false - } - } - return true -} - -// UpdateRelativeURLsForPluginCommands method updates relative urls for plugin commands -func (ad *AutocompleteData) UpdateRelativeURLsForPluginCommands(baseURL *url.URL) error { - for _, arg := range ad.Arguments { - if arg.Type != AutocompleteArgTypeDynamicList { - continue - } - dynamicList, ok := arg.Data.(*AutocompleteDynamicListArg) - if !ok { - return errors.New("Not a proper DynamicList type argument") - } - dynamicListURL, err := url.Parse(dynamicList.FetchURL) - if err != nil { - return errors.Wrapf(err, "FetchURL is not a proper url") - } - if !dynamicListURL.IsAbs() { - absURL := &url.URL{} - *absURL = *baseURL - absURL.Path = path.Join(absURL.Path, dynamicList.FetchURL) - dynamicList.FetchURL = absURL.String() - } - - } - for _, command := range ad.SubCommands { - err := command.UpdateRelativeURLsForPluginCommands(baseURL) - if err != nil { - return err - } - } - return nil -} - -// IsValid method checks if autocomplete data is valid. -func (ad *AutocompleteData) IsValid() error { - if ad == nil { - return errors.New("No nil commands are allowed in AutocompleteData") - } - if ad.Trigger == "" { - return errors.New("An empty command name in the autocomplete data") - } - if strings.ToLower(ad.Trigger) != ad.Trigger { - return errors.New("Command should be lowercase") - } - roles := []string{SYSTEM_ADMIN_ROLE_ID, SYSTEM_USER_ROLE_ID, ""} - if stringNotInSlice(ad.RoleID, roles) { - return errors.New("Wrong role in the autocomplete data") - } - if len(ad.Arguments) > 0 && len(ad.SubCommands) > 0 { - return errors.New("Command can't have arguments and subcommands") - } - if len(ad.Arguments) > 0 { - namedArgumentIndex := -1 - for i, arg := range ad.Arguments { - if arg.Name != "" { // it's a named argument - if namedArgumentIndex == -1 { // first named argument - namedArgumentIndex = i - } - } else { // it's a positional argument - if namedArgumentIndex != -1 { - return errors.New("Named argument should not be before positional argument") - } - } - if arg.Type == AutocompleteArgTypeDynamicList { - dynamicList, ok := arg.Data.(*AutocompleteDynamicListArg) - if !ok { - return errors.New("Not a proper DynamicList type argument") - } - _, err := url.Parse(dynamicList.FetchURL) - if err != nil { - return errors.Wrapf(err, "FetchURL is not a proper url") - } - } else if arg.Type == AutocompleteArgTypeStaticList { - staticList, ok := arg.Data.(*AutocompleteStaticListArg) - if !ok { - return errors.New("Not a proper StaticList type argument") - } - for _, arg := range staticList.PossibleArguments { - if arg.Item == "" { - return errors.New("Possible argument name not set in StaticList argument") - } - } - } else if arg.Type == AutocompleteArgTypeText { - if _, ok := arg.Data.(*AutocompleteTextArg); !ok { - return errors.New("Not a proper TextInput type argument") - } - if arg.Name == "" && !arg.Required { - return errors.New("Positional argument can not be optional") - } - } - } - } - for _, command := range ad.SubCommands { - err := command.IsValid() - if err != nil { - return err - } - } - return nil -} - -// ToJSON encodes AutocompleteData struct to the json -func (ad *AutocompleteData) ToJSON() ([]byte, error) { - b, err := json.Marshal(ad) - if err != nil { - return nil, errors.Wrapf(err, "can't marshal slash command %s", ad.Trigger) - } - return b, nil -} - -// AutocompleteDataFromJSON decodes AutocompleteData struct from the json -func AutocompleteDataFromJSON(data []byte) (*AutocompleteData, error) { - var ad AutocompleteData - if err := json.Unmarshal(data, &ad); err != nil { - return nil, errors.Wrap(err, "can't unmarshal AutocompleteData") - } - return &ad, nil -} - -// Equals method checks if argument is the same. -func (a *AutocompleteArg) Equals(arg *AutocompleteArg) bool { - if a.Name != arg.Name || - a.HelpText != arg.HelpText || - a.Type != arg.Type || - a.Required != arg.Required || - !reflect.DeepEqual(a.Data, arg.Data) { - return false - } - return true -} - -// UnmarshalJSON will unmarshal argument -func (a *AutocompleteArg) UnmarshalJSON(b []byte) error { - var arg map[string]interface{} - if err := json.Unmarshal(b, &arg); err != nil { - return errors.Wrapf(err, "Can't unmarshal argument %s", string(b)) - } - var ok bool - a.Name, ok = arg["Name"].(string) - if !ok { - return errors.Errorf("No field Name in the argument %s", string(b)) - } - - a.HelpText, ok = arg["HelpText"].(string) - if !ok { - return errors.Errorf("No field HelpText in the argument %s", string(b)) - } - - t, ok := arg["Type"].(string) - if !ok { - return errors.Errorf("No field Type in the argument %s", string(b)) - } - a.Type = AutocompleteArgType(t) - - a.Required, ok = arg["Required"].(bool) - if !ok { - return errors.Errorf("No field Required in the argument %s", string(b)) - } - - data, ok := arg["Data"] - if !ok { - return errors.Errorf("No field Data in the argument %s", string(b)) - } - - if a.Type == AutocompleteArgTypeText { - m, ok := data.(map[string]interface{}) - if !ok { - return errors.Errorf("Wrong Data type in the TextInput argument %s", string(b)) - } - pattern, ok := m["Pattern"].(string) - if !ok { - return errors.Errorf("No field Pattern in the TextInput argument %s", string(b)) - } - hint, ok := m["Hint"].(string) - if !ok { - return errors.Errorf("No field Hint in the TextInput argument %s", string(b)) - } - a.Data = &AutocompleteTextArg{Hint: hint, Pattern: pattern} - } else if a.Type == AutocompleteArgTypeStaticList { - m, ok := data.(map[string]interface{}) - if !ok { - return errors.Errorf("Wrong Data type in the StaticList argument %s", string(b)) - } - list, ok := m["PossibleArguments"].([]interface{}) - if !ok { - return errors.Errorf("No field PossibleArguments in the StaticList argument %s", string(b)) - } - - possibleArguments := []AutocompleteListItem{} - for i := range list { - args, ok := list[i].(map[string]interface{}) - if !ok { - return errors.Errorf("Wrong AutocompleteStaticListItem type in the StaticList argument %s", string(b)) - } - item, ok := args["Item"].(string) - if !ok { - return errors.Errorf("No field Item in the StaticList's possible arguments %s", string(b)) - } - - hint, ok := args["Hint"].(string) - if !ok { - return errors.Errorf("No field Hint in the StaticList's possible arguments %s", string(b)) - } - helpText, ok := args["HelpText"].(string) - if !ok { - return errors.Errorf("No field Hint in the StaticList's possible arguments %s", string(b)) - } - - possibleArguments = append(possibleArguments, AutocompleteListItem{ - Item: item, - Hint: hint, - HelpText: helpText, - }) - } - a.Data = &AutocompleteStaticListArg{PossibleArguments: possibleArguments} - } else if a.Type == AutocompleteArgTypeDynamicList { - m, ok := data.(map[string]interface{}) - if !ok { - return errors.Errorf("Wrong type in the DynamicList argument %s", string(b)) - } - url, ok := m["FetchURL"].(string) - if !ok { - return errors.Errorf("No field FetchURL in the DynamicList's argument %s", string(b)) - } - a.Data = &AutocompleteDynamicListArg{FetchURL: url} - } - return nil -} - -// AutocompleteSuggestionsToJSON returns json for a list of AutocompleteSuggestion objects -func AutocompleteSuggestionsToJSON(suggestions []AutocompleteSuggestion) []byte { - b, _ := json.Marshal(suggestions) - return b -} - -// AutocompleteSuggestionsFromJSON returns list of AutocompleteSuggestions from json. -func AutocompleteSuggestionsFromJSON(data io.Reader) []AutocompleteSuggestion { - var o []AutocompleteSuggestion - json.NewDecoder(data).Decode(&o) - return o -} - -// AutocompleteStaticListItemsToJSON returns json for a list of AutocompleteStaticListItem objects -func AutocompleteStaticListItemsToJSON(items []AutocompleteListItem) []byte { - b, _ := json.Marshal(items) - return b -} - -// AutocompleteStaticListItemsFromJSON returns list of AutocompleteStaticListItem from json. -func AutocompleteStaticListItemsFromJSON(data io.Reader) []AutocompleteListItem { - var o []AutocompleteListItem - json.NewDecoder(data).Decode(&o) - return o -} - -func stringNotInSlice(a string, slice []string) bool { - for _, b := range slice { - if b == a { - return false - } - } - return true -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_request.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_request.go deleted file mode 100644 index 9a4e40c8..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/command_request.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type CommandMoveRequest struct { - TeamId string `json:"team_id"` -} - -func CommandMoveRequestFromJson(data io.Reader) (*CommandMoveRequest, error) { - decoder := json.NewDecoder(data) - var cmr CommandMoveRequest - err := decoder.Decode(&cmr) - if err != nil { - return nil, err - } - return &cmr, nil -} - -func (cmr *CommandMoveRequest) ToJson() string { - b, err := json.Marshal(cmr) - if err != nil { - return "" - } - return string(b) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_response.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_response.go deleted file mode 100644 index 80cca5ab..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/command_response.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "io/ioutil" - "strings" - - "github.com/mattermost/mattermost-server/v5/utils/jsonutils" -) - -const ( - COMMAND_RESPONSE_TYPE_IN_CHANNEL = "in_channel" - COMMAND_RESPONSE_TYPE_EPHEMERAL = "ephemeral" -) - -type CommandResponse struct { - ResponseType string `json:"response_type"` - Text string `json:"text"` - Username string `json:"username"` - ChannelId string `json:"channel_id"` - IconURL string `json:"icon_url"` - Type string `json:"type"` - Props StringInterface `json:"props"` - GotoLocation string `json:"goto_location"` - TriggerId string `json:"trigger_id"` - SkipSlackParsing bool `json:"skip_slack_parsing"` // Set to `true` to skip the Slack-compatibility handling of Text. - Attachments []*SlackAttachment `json:"attachments"` - ExtraResponses []*CommandResponse `json:"extra_responses"` -} - -func (o *CommandResponse) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func CommandResponseFromHTTPBody(contentType string, body io.Reader) (*CommandResponse, error) { - if strings.TrimSpace(strings.Split(contentType, ";")[0]) == "application/json" { - return CommandResponseFromJson(body) - } - if b, err := ioutil.ReadAll(body); err == nil { - return CommandResponseFromPlainText(string(b)), nil - } - return nil, nil -} - -func CommandResponseFromPlainText(text string) *CommandResponse { - return &CommandResponse{ - Text: text, - } -} - -func CommandResponseFromJson(data io.Reader) (*CommandResponse, error) { - b, err := ioutil.ReadAll(data) - if err != nil { - return nil, err - } - - var o CommandResponse - err = json.Unmarshal(b, &o) - if err != nil { - return nil, jsonutils.HumanizeJSONError(err, b) - } - - o.Attachments = StringifySlackFieldValue(o.Attachments) - - if o.ExtraResponses != nil { - for _, resp := range o.ExtraResponses { - resp.Attachments = StringifySlackFieldValue(resp.Attachments) - } - } - - return &o, nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/command_webhook.go b/vendor/github.com/mattermost/mattermost-server/v5/model/command_webhook.go deleted file mode 100644 index 3757ecc7..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/command_webhook.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "net/http" -) - -type CommandWebhook struct { - Id string - CreateAt int64 - CommandId string - UserId string - ChannelId string - RootId string - ParentId string - UseCount int -} - -const ( - COMMAND_WEBHOOK_LIFETIME = 1000 * 60 * 30 -) - -func (o *CommandWebhook) PreSave() { - if o.Id == "" { - o.Id = NewId() - } - - if o.CreateAt == 0 { - o.CreateAt = GetMillis() - } -} - -func (o *CommandWebhook) IsValid() *AppError { - if !IsValidId(o.Id) { - return NewAppError("CommandWebhook.IsValid", "model.command_hook.id.app_error", nil, "", http.StatusBadRequest) - } - - if o.CreateAt == 0 { - return NewAppError("CommandWebhook.IsValid", "model.command_hook.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if !IsValidId(o.CommandId) { - return NewAppError("CommandWebhook.IsValid", "model.command_hook.command_id.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidId(o.UserId) { - return NewAppError("CommandWebhook.IsValid", "model.command_hook.user_id.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidId(o.ChannelId) { - return NewAppError("CommandWebhook.IsValid", "model.command_hook.channel_id.app_error", nil, "", http.StatusBadRequest) - } - - if o.RootId != "" && !IsValidId(o.RootId) { - return NewAppError("CommandWebhook.IsValid", "model.command_hook.root_id.app_error", nil, "", http.StatusBadRequest) - } - - if o.ParentId != "" && !IsValidId(o.ParentId) { - return NewAppError("CommandWebhook.IsValid", "model.command_hook.parent_id.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/compliance.go b/vendor/github.com/mattermost/mattermost-server/v5/model/compliance.go deleted file mode 100644 index 0211805e..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/compliance.go +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" - "strings" -) - -const ( - COMPLIANCE_STATUS_CREATED = "created" - COMPLIANCE_STATUS_RUNNING = "running" - COMPLIANCE_STATUS_FINISHED = "finished" - COMPLIANCE_STATUS_FAILED = "failed" - COMPLIANCE_STATUS_REMOVED = "removed" - - COMPLIANCE_TYPE_DAILY = "daily" - COMPLIANCE_TYPE_ADHOC = "adhoc" -) - -type Compliance struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at"` - UserId string `json:"user_id"` - Status string `json:"status"` - Count int `json:"count"` - Desc string `json:"desc"` - Type string `json:"type"` - StartAt int64 `json:"start_at"` - EndAt int64 `json:"end_at"` - Keywords string `json:"keywords"` - Emails string `json:"emails"` -} - -type Compliances []Compliance - -// ComplianceExportCursor is used for paginated iteration of posts -// for compliance export. -// We need to keep track of the last post ID in addition to the last post -// CreateAt to break ties when two posts have the same CreateAt. -type ComplianceExportCursor struct { - LastChannelsQueryPostCreateAt int64 - LastChannelsQueryPostID string - ChannelsQueryCompleted bool - LastDirectMessagesQueryPostCreateAt int64 - LastDirectMessagesQueryPostID string - DirectMessagesQueryCompleted bool -} - -func (c *Compliance) ToJson() string { - b, _ := json.Marshal(c) - return string(b) -} - -func (c *Compliance) PreSave() { - if c.Id == "" { - c.Id = NewId() - } - - if c.Status == "" { - c.Status = COMPLIANCE_STATUS_CREATED - } - - c.Count = 0 - c.Emails = NormalizeEmail(c.Emails) - c.Keywords = strings.ToLower(c.Keywords) - - c.CreateAt = GetMillis() -} - -func (c *Compliance) DeepCopy() *Compliance { - copy := *c - return © -} - -func (c *Compliance) JobName() string { - jobName := c.Type - if c.Type == COMPLIANCE_TYPE_DAILY { - jobName += "-" + c.Desc - } - - jobName += "-" + c.Id - - return jobName -} - -func (c *Compliance) IsValid() *AppError { - - if !IsValidId(c.Id) { - return NewAppError("Compliance.IsValid", "model.compliance.is_valid.id.app_error", nil, "", http.StatusBadRequest) - } - - if c.CreateAt == 0 { - return NewAppError("Compliance.IsValid", "model.compliance.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) - } - - if len(c.Desc) > 512 || c.Desc == "" { - return NewAppError("Compliance.IsValid", "model.compliance.is_valid.desc.app_error", nil, "", http.StatusBadRequest) - } - - if c.StartAt == 0 { - return NewAppError("Compliance.IsValid", "model.compliance.is_valid.start_at.app_error", nil, "", http.StatusBadRequest) - } - - if c.EndAt == 0 { - return NewAppError("Compliance.IsValid", "model.compliance.is_valid.end_at.app_error", nil, "", http.StatusBadRequest) - } - - if c.EndAt <= c.StartAt { - return NewAppError("Compliance.IsValid", "model.compliance.is_valid.start_end_at.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func ComplianceFromJson(data io.Reader) *Compliance { - var c *Compliance - json.NewDecoder(data).Decode(&c) - return c -} - -func (c Compliances) ToJson() string { - b, err := json.Marshal(c) - if err != nil { - return "[]" - } - return string(b) -} - -func CompliancesFromJson(data io.Reader) Compliances { - var o Compliances - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/compliance_post.go b/vendor/github.com/mattermost/mattermost-server/v5/model/compliance_post.go deleted file mode 100644 index 5e18812b..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/compliance_post.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "regexp" - "time" -) - -type CompliancePost struct { - - // From Team - TeamName string - TeamDisplayName string - - // From Channel - ChannelName string - ChannelDisplayName string - ChannelType string - - // From User - UserUsername string - UserEmail string - UserNickname string - - // From Post - PostId string - PostCreateAt int64 - PostUpdateAt int64 - PostDeleteAt int64 - PostRootId string - PostParentId string - PostOriginalId string - PostMessage string - PostType string - PostProps string - PostHashtags string - PostFileIds string - - IsBot bool -} - -func CompliancePostHeader() []string { - return []string{ - "TeamName", - "TeamDisplayName", - - "ChannelName", - "ChannelDisplayName", - "ChannelType", - - "UserUsername", - "UserEmail", - "UserNickname", - "UserType", - - "PostId", - "PostCreateAt", - "PostUpdateAt", - "PostDeleteAt", - "PostRootId", - "PostParentId", - "PostOriginalId", - "PostMessage", - "PostType", - "PostProps", - "PostHashtags", - "PostFileIds", - } -} - -func cleanComplianceStrings(in string) string { - if matched, _ := regexp.MatchString("^\\s*(=|\\+|\\-)", in); matched { - return "'" + in - } - return in -} - -func (cp *CompliancePost) Row() []string { - - postDeleteAt := "" - if cp.PostDeleteAt > 0 { - postDeleteAt = time.Unix(0, cp.PostDeleteAt*int64(1000*1000)).Format(time.RFC3339) - } - - postUpdateAt := "" - if cp.PostUpdateAt != cp.PostCreateAt { - postUpdateAt = time.Unix(0, cp.PostUpdateAt*int64(1000*1000)).Format(time.RFC3339) - } - - userType := "user" - if cp.IsBot { - userType = "bot" - } - - return []string{ - cleanComplianceStrings(cp.TeamName), - cleanComplianceStrings(cp.TeamDisplayName), - - cleanComplianceStrings(cp.ChannelName), - cleanComplianceStrings(cp.ChannelDisplayName), - cleanComplianceStrings(cp.ChannelType), - - cleanComplianceStrings(cp.UserUsername), - cleanComplianceStrings(cp.UserEmail), - cleanComplianceStrings(cp.UserNickname), - userType, - - cp.PostId, - time.Unix(0, cp.PostCreateAt*int64(1000*1000)).Format(time.RFC3339), - postUpdateAt, - postDeleteAt, - - cp.PostRootId, - cp.PostParentId, - cp.PostOriginalId, - cleanComplianceStrings(cp.PostMessage), - cp.PostType, - cp.PostProps, - cp.PostHashtags, - cp.PostFileIds, - } -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/config.go b/vendor/github.com/mattermost/mattermost-server/v5/model/config.go deleted file mode 100644 index 52722161..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/config.go +++ /dev/null @@ -1,3994 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "crypto/tls" - "encoding/json" - "io" - "math" - "net" - "net/http" - "net/url" - "os" - "reflect" - "regexp" - "strconv" - "strings" - "time" - - "github.com/mattermost/ldap" - - "github.com/mattermost/mattermost-server/v5/shared/filestore" - "github.com/mattermost/mattermost-server/v5/shared/mlog" -) - -const ( - CONN_SECURITY_NONE = "" - CONN_SECURITY_PLAIN = "PLAIN" - CONN_SECURITY_TLS = "TLS" - CONN_SECURITY_STARTTLS = "STARTTLS" - - IMAGE_DRIVER_LOCAL = "local" - IMAGE_DRIVER_S3 = "amazons3" - - DATABASE_DRIVER_MYSQL = "mysql" - DATABASE_DRIVER_POSTGRES = "postgres" - - SEARCHENGINE_ELASTICSEARCH = "elasticsearch" - - MINIO_ACCESS_KEY = "minioaccesskey" - MINIO_SECRET_KEY = "miniosecretkey" - MINIO_BUCKET = "mattermost-test" - - PASSWORD_MAXIMUM_LENGTH = 64 - PASSWORD_MINIMUM_LENGTH = 5 - - SERVICE_GITLAB = "gitlab" - SERVICE_GOOGLE = "google" - SERVICE_OFFICE365 = "office365" - SERVICE_OPENID = "openid" - - GENERIC_NO_CHANNEL_NOTIFICATION = "generic_no_channel" - GENERIC_NOTIFICATION = "generic" - GENERIC_NOTIFICATION_SERVER = "https://push-test.mattermost.com" - MM_SUPPORT_ADVISOR_ADDRESS = "support-advisor@mattermost.com" - FULL_NOTIFICATION = "full" - ID_LOADED_NOTIFICATION = "id_loaded" - - DIRECT_MESSAGE_ANY = "any" - DIRECT_MESSAGE_TEAM = "team" - - SHOW_USERNAME = "username" - SHOW_NICKNAME_FULLNAME = "nickname_full_name" - SHOW_FULLNAME = "full_name" - - PERMISSIONS_ALL = "all" - PERMISSIONS_CHANNEL_ADMIN = "channel_admin" - PERMISSIONS_TEAM_ADMIN = "team_admin" - PERMISSIONS_SYSTEM_ADMIN = "system_admin" - - FAKE_SETTING = "********************************" - - RESTRICT_EMOJI_CREATION_ALL = "all" - RESTRICT_EMOJI_CREATION_ADMIN = "admin" - RESTRICT_EMOJI_CREATION_SYSTEM_ADMIN = "system_admin" - - PERMISSIONS_DELETE_POST_ALL = "all" - PERMISSIONS_DELETE_POST_TEAM_ADMIN = "team_admin" - PERMISSIONS_DELETE_POST_SYSTEM_ADMIN = "system_admin" - - ALLOW_EDIT_POST_ALWAYS = "always" - ALLOW_EDIT_POST_NEVER = "never" - ALLOW_EDIT_POST_TIME_LIMIT = "time_limit" - - GROUP_UNREAD_CHANNELS_DISABLED = "disabled" - GROUP_UNREAD_CHANNELS_DEFAULT_ON = "default_on" - GROUP_UNREAD_CHANNELS_DEFAULT_OFF = "default_off" - - COLLAPSED_THREADS_DISABLED = "disabled" - COLLAPSED_THREADS_DEFAULT_ON = "default_on" - COLLAPSED_THREADS_DEFAULT_OFF = "default_off" - - EMAIL_BATCHING_BUFFER_SIZE = 256 - EMAIL_BATCHING_INTERVAL = 30 - - EMAIL_NOTIFICATION_CONTENTS_FULL = "full" - EMAIL_NOTIFICATION_CONTENTS_GENERIC = "generic" - - SITENAME_MAX_LENGTH = 30 - - SERVICE_SETTINGS_DEFAULT_SITE_URL = "http://localhost:8065" - SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE = "" - SERVICE_SETTINGS_DEFAULT_TLS_KEY_FILE = "" - SERVICE_SETTINGS_DEFAULT_READ_TIMEOUT = 300 - SERVICE_SETTINGS_DEFAULT_WRITE_TIMEOUT = 300 - SERVICE_SETTINGS_DEFAULT_IDLE_TIMEOUT = 60 - SERVICE_SETTINGS_DEFAULT_MAX_LOGIN_ATTEMPTS = 10 - SERVICE_SETTINGS_DEFAULT_ALLOW_CORS_FROM = "" - SERVICE_SETTINGS_DEFAULT_LISTEN_AND_ADDRESS = ":8065" - SERVICE_SETTINGS_DEFAULT_GFYCAT_API_KEY = "2_KtH_W5" - SERVICE_SETTINGS_DEFAULT_GFYCAT_API_SECRET = "3wLVZPiswc3DnaiaFoLkDvB4X0IV6CpMkj4tf2inJRsBY6-FnkT08zGmppWFgeof" - - TEAM_SETTINGS_DEFAULT_SITE_NAME = "Mattermost" - TEAM_SETTINGS_DEFAULT_MAX_USERS_PER_TEAM = 50 - TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT = "" - TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT = "" - TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT = 300 - - SQL_SETTINGS_DEFAULT_DATA_SOURCE = "postgres://mmuser:mostest@localhost/mattermost_test?sslmode=disable&connect_timeout=10" - - FILE_SETTINGS_DEFAULT_DIRECTORY = "./data/" - - IMPORT_SETTINGS_DEFAULT_DIRECTORY = "./import" - IMPORT_SETTINGS_DEFAULT_RETENTION_DAYS = 30 - - EXPORT_SETTINGS_DEFAULT_DIRECTORY = "./export" - EXPORT_SETTINGS_DEFAULT_RETENTION_DAYS = 30 - - EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION = "" - - SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK = "https://mattermost.com/terms-of-service/" - SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK = "https://mattermost.com/privacy-policy/" - SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK = "https://about.mattermost.com/default-about/" - SUPPORT_SETTINGS_DEFAULT_HELP_LINK = "https://about.mattermost.com/default-help/" - SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK = "https://about.mattermost.com/default-report-a-problem/" - SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL = "" - SUPPORT_SETTINGS_DEFAULT_RE_ACCEPTANCE_PERIOD = 365 - - LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = "" - LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE = "" - LDAP_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE = "" - LDAP_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE = "" - LDAP_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE = "" - LDAP_SETTINGS_DEFAULT_ID_ATTRIBUTE = "" - LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE = "" - LDAP_SETTINGS_DEFAULT_LOGIN_FIELD_NAME = "" - LDAP_SETTINGS_DEFAULT_GROUP_DISPLAY_NAME_ATTRIBUTE = "" - LDAP_SETTINGS_DEFAULT_GROUP_ID_ATTRIBUTE = "" - LDAP_SETTINGS_DEFAULT_PICTURE_ATTRIBUTE = "" - - SAML_SETTINGS_DEFAULT_ID_ATTRIBUTE = "" - SAML_SETTINGS_DEFAULT_GUEST_ATTRIBUTE = "" - SAML_SETTINGS_DEFAULT_ADMIN_ATTRIBUTE = "" - SAML_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE = "" - SAML_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE = "" - SAML_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE = "" - SAML_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE = "" - SAML_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE = "" - SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE = "" - SAML_SETTINGS_DEFAULT_POSITION_ATTRIBUTE = "" - - SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA1 = "RSAwithSHA1" - SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA256 = "RSAwithSHA256" - SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA512 = "RSAwithSHA512" - SAML_SETTINGS_DEFAULT_SIGNATURE_ALGORITHM = SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA1 - - SAML_SETTINGS_CANONICAL_ALGORITHM_C14N = "Canonical1.0" - SAML_SETTINGS_CANONICAL_ALGORITHM_C14N11 = "Canonical1.1" - SAML_SETTINGS_DEFAULT_CANONICAL_ALGORITHM = SAML_SETTINGS_CANONICAL_ALGORITHM_C14N - - NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK = "https://mattermost.com/download/#mattermostApps" - NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK = "https://about.mattermost.com/mattermost-android-app/" - NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK = "https://about.mattermost.com/mattermost-ios-app/" - - EXPERIMENTAL_SETTINGS_DEFAULT_LINK_METADATA_TIMEOUT_MILLISECONDS = 5000 - - ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS = 2500 - - ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR = "#f2a93b" - ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_TEXT_COLOR = "#333333" - ANNOUNCEMENT_SETTINGS_DEFAULT_NOTICES_JSON_URL = "https://notices.mattermost.com/" - ANNOUNCEMENT_SETTINGS_DEFAULT_NOTICES_FETCH_FREQUENCY_SECONDS = 3600 - - TEAM_SETTINGS_DEFAULT_TEAM_TEXT = "default" - - ELASTICSEARCH_SETTINGS_DEFAULT_CONNECTION_URL = "http://localhost:9200" - ELASTICSEARCH_SETTINGS_DEFAULT_USERNAME = "elastic" - ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD = "changeme" - ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_REPLICAS = 1 - ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_SHARDS = 1 - ELASTICSEARCH_SETTINGS_DEFAULT_CHANNEL_INDEX_REPLICAS = 1 - ELASTICSEARCH_SETTINGS_DEFAULT_CHANNEL_INDEX_SHARDS = 1 - ELASTICSEARCH_SETTINGS_DEFAULT_USER_INDEX_REPLICAS = 1 - ELASTICSEARCH_SETTINGS_DEFAULT_USER_INDEX_SHARDS = 1 - ELASTICSEARCH_SETTINGS_DEFAULT_AGGREGATE_POSTS_AFTER_DAYS = 365 - ELASTICSEARCH_SETTINGS_DEFAULT_POSTS_AGGREGATOR_JOB_START_TIME = "03:00" - ELASTICSEARCH_SETTINGS_DEFAULT_INDEX_PREFIX = "" - ELASTICSEARCH_SETTINGS_DEFAULT_LIVE_INDEXING_BATCH_SIZE = 1 - ELASTICSEARCH_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS = 3600 - ELASTICSEARCH_SETTINGS_DEFAULT_REQUEST_TIMEOUT_SECONDS = 30 - - BLEVE_SETTINGS_DEFAULT_INDEX_DIR = "" - BLEVE_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS = 3600 - - DATA_RETENTION_SETTINGS_DEFAULT_MESSAGE_RETENTION_DAYS = 365 - DATA_RETENTION_SETTINGS_DEFAULT_FILE_RETENTION_DAYS = 365 - DATA_RETENTION_SETTINGS_DEFAULT_DELETION_JOB_START_TIME = "02:00" - DATA_RETENTION_SETTINGS_DEFAULT_BATCH_SIZE = 3000 - - PLUGIN_SETTINGS_DEFAULT_DIRECTORY = "./plugins" - PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY = "./client/plugins" - PLUGIN_SETTINGS_DEFAULT_ENABLE_MARKETPLACE = true - PLUGIN_SETTINGS_DEFAULT_MARKETPLACE_URL = "https://api.integrations.mattermost.com" - PLUGIN_SETTINGS_OLD_MARKETPLACE_URL = "https://marketplace.integrations.mattermost.com" - - COMPLIANCE_EXPORT_TYPE_CSV = "csv" - COMPLIANCE_EXPORT_TYPE_ACTIANCE = "actiance" - COMPLIANCE_EXPORT_TYPE_GLOBALRELAY = "globalrelay" - COMPLIANCE_EXPORT_TYPE_GLOBALRELAY_ZIP = "globalrelay-zip" - GLOBALRELAY_CUSTOMER_TYPE_A9 = "A9" - GLOBALRELAY_CUSTOMER_TYPE_A10 = "A10" - - CLIENT_SIDE_CERT_CHECK_PRIMARY_AUTH = "primary" - CLIENT_SIDE_CERT_CHECK_SECONDARY_AUTH = "secondary" - - IMAGE_PROXY_TYPE_LOCAL = "local" - IMAGE_PROXY_TYPE_ATMOS_CAMO = "atmos/camo" - - GOOGLE_SETTINGS_DEFAULT_SCOPE = "profile email" - GOOGLE_SETTINGS_DEFAULT_AUTH_ENDPOINT = "https://accounts.google.com/o/oauth2/v2/auth" - GOOGLE_SETTINGS_DEFAULT_TOKEN_ENDPOINT = "https://www.googleapis.com/oauth2/v4/token" - GOOGLE_SETTINGS_DEFAULT_USER_API_ENDPOINT = "https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses,nicknames,metadata" - - OFFICE365_SETTINGS_DEFAULT_SCOPE = "User.Read" - OFFICE365_SETTINGS_DEFAULT_AUTH_ENDPOINT = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize" - OFFICE365_SETTINGS_DEFAULT_TOKEN_ENDPOINT = "https://login.microsoftonline.com/common/oauth2/v2.0/token" - OFFICE365_SETTINGS_DEFAULT_USER_API_ENDPOINT = "https://graph.microsoft.com/v1.0/me" - - CLOUD_SETTINGS_DEFAULT_CWS_URL = "https://customers.mattermost.com" - CLOUD_SETTINGS_DEFAULT_CWS_API_URL = "https://portal.internal.prod.cloud.mattermost.com" - OPENID_SETTINGS_DEFAULT_SCOPE = "profile openid email" - - LOCAL_MODE_SOCKET_PATH = "/var/tmp/mattermost_local.socket" -) - -func GetDefaultAppCustomURLSchemes() []string { - return []string{"mmauth://", "mmauthbeta://"} -} - -var ServerTLSSupportedCiphers = map[string]uint16{ - "TLS_RSA_WITH_RC4_128_SHA": tls.TLS_RSA_WITH_RC4_128_SHA, - "TLS_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, - "TLS_RSA_WITH_AES_128_CBC_SHA": tls.TLS_RSA_WITH_AES_128_CBC_SHA, - "TLS_RSA_WITH_AES_256_CBC_SHA": tls.TLS_RSA_WITH_AES_256_CBC_SHA, - "TLS_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_RSA_WITH_AES_128_CBC_SHA256, - "TLS_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_RSA_WITH_AES_128_GCM_SHA256, - "TLS_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_RSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - "TLS_ECDHE_RSA_WITH_RC4_128_SHA": tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, - "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA": tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256": tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384": tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305": tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, -} - -type ServiceSettings struct { - SiteURL *string `access:"environment_web_server,authentication_saml,write_restrictable"` - WebsocketURL *string `access:"write_restrictable,cloud_restrictable"` - LicenseFileLocation *string `access:"write_restrictable,cloud_restrictable"` // telemetry: none - ListenAddress *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` // telemetry: none - ConnectionSecurity *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` - TLSCertFile *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` - TLSKeyFile *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` - TLSMinVer *string `access:"write_restrictable,cloud_restrictable"` // telemetry: none - TLSStrictTransport *bool `access:"write_restrictable,cloud_restrictable"` - TLSStrictTransportMaxAge *int64 `access:"write_restrictable,cloud_restrictable"` // telemetry: none - TLSOverwriteCiphers []string `access:"write_restrictable,cloud_restrictable"` // telemetry: none - UseLetsEncrypt *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` - LetsEncryptCertificateCacheFile *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` // telemetry: none - Forward80To443 *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` - TrustedProxyIPHeader []string `access:"write_restrictable,cloud_restrictable"` // telemetry: none - ReadTimeout *int `access:"environment_web_server,write_restrictable,cloud_restrictable"` - WriteTimeout *int `access:"environment_web_server,write_restrictable,cloud_restrictable"` - IdleTimeout *int `access:"write_restrictable,cloud_restrictable"` - MaximumLoginAttempts *int `access:"authentication_password,write_restrictable,cloud_restrictable"` - GoroutineHealthThreshold *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none - EnableOAuthServiceProvider *bool `access:"integrations_integration_management"` - EnableIncomingWebhooks *bool `access:"integrations_integration_management"` - EnableOutgoingWebhooks *bool `access:"integrations_integration_management"` - EnableCommands *bool `access:"integrations_integration_management"` - EnablePostUsernameOverride *bool `access:"integrations_integration_management"` - EnablePostIconOverride *bool `access:"integrations_integration_management"` - GoogleDeveloperKey *string `access:"site_posts,write_restrictable,cloud_restrictable"` - DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations *bool `json:"EnableOnlyAdminIntegrations" mapstructure:"EnableOnlyAdminIntegrations"` // Deprecated: do not use - EnableLinkPreviews *bool `access:"site_posts"` - RestrictLinkPreviews *string `access:"site_posts"` - EnableTesting *bool `access:"environment_developer,write_restrictable,cloud_restrictable"` - EnableDeveloper *bool `access:"environment_developer,write_restrictable,cloud_restrictable"` - EnableOpenTracing *bool `access:"write_restrictable,cloud_restrictable"` - EnableSecurityFixAlert *bool `access:"environment_smtp,write_restrictable,cloud_restrictable"` - EnableInsecureOutgoingConnections *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` - AllowedUntrustedInternalConnections *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` - EnableMultifactorAuthentication *bool `access:"authentication_mfa"` - EnforceMultifactorAuthentication *bool `access:"authentication_mfa"` - EnableUserAccessTokens *bool `access:"integrations_integration_management"` - AllowCorsFrom *string `access:"integrations_cors,write_restrictable,cloud_restrictable"` - CorsExposedHeaders *string `access:"integrations_cors,write_restrictable,cloud_restrictable"` - CorsAllowCredentials *bool `access:"integrations_cors,write_restrictable,cloud_restrictable"` - CorsDebug *bool `access:"integrations_cors,write_restrictable,cloud_restrictable"` - AllowCookiesForSubdomains *bool `access:"write_restrictable,cloud_restrictable"` - ExtendSessionLengthWithActivity *bool `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - SessionLengthWebInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - SessionLengthMobileInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - SessionLengthSSOInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - SessionCacheInMinutes *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - SessionIdleTimeoutInMinutes *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - WebsocketSecurePort *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none - WebsocketPort *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none - WebserverMode *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` - EnableGifPicker *bool `access:"integrations_gif"` - GfycatApiKey *string `access:"integrations_gif"` - GfycatApiSecret *string `access:"integrations_gif"` - EnableCustomEmoji *bool `access:"site_emoji"` - EnableEmojiPicker *bool `access:"site_emoji"` - DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation *string `json:"RestrictCustomEmojiCreation" mapstructure:"RestrictCustomEmojiCreation"` // Deprecated: do not use - DEPRECATED_DO_NOT_USE_RestrictPostDelete *string `json:"RestrictPostDelete" mapstructure:"RestrictPostDelete"` // Deprecated: do not use - DEPRECATED_DO_NOT_USE_AllowEditPost *string `json:"AllowEditPost" mapstructure:"AllowEditPost"` // Deprecated: do not use - PostEditTimeLimit *int `access:"user_management_permissions"` - TimeBetweenUserTypingUpdatesMilliseconds *int64 `access:"experimental_features,write_restrictable,cloud_restrictable"` - EnablePostSearch *bool `access:"write_restrictable,cloud_restrictable"` - EnableFileSearch *bool `access:"write_restrictable"` - MinimumHashtagLength *int `access:"environment_database,write_restrictable,cloud_restrictable"` - EnableUserTypingMessages *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` - EnableChannelViewedMessages *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` - EnableUserStatuses *bool `access:"write_restrictable,cloud_restrictable"` - ExperimentalEnableAuthenticationTransfer *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` - ClusterLogTimeoutMilliseconds *int `access:"write_restrictable,cloud_restrictable"` - CloseUnusedDirectMessages *bool `access:"experimental_features"` - EnablePreviewFeatures *bool `access:"experimental_features"` - EnableTutorial *bool `access:"experimental_features"` - ExperimentalEnableDefaultChannelLeaveJoinMessages *bool `access:"experimental_features"` - ExperimentalGroupUnreadChannels *string `access:"experimental_features"` - ExperimentalChannelOrganization *bool `access:"experimental_features"` - DEPRECATED_DO_NOT_USE_ImageProxyType *string `json:"ImageProxyType" mapstructure:"ImageProxyType"` // Deprecated: do not use - DEPRECATED_DO_NOT_USE_ImageProxyURL *string `json:"ImageProxyURL" mapstructure:"ImageProxyURL"` // Deprecated: do not use - DEPRECATED_DO_NOT_USE_ImageProxyOptions *string `json:"ImageProxyOptions" mapstructure:"ImageProxyOptions"` // Deprecated: do not use - EnableAPITeamDeletion *bool - EnableAPIUserDeletion *bool - ExperimentalEnableHardenedMode *bool `access:"experimental_features"` - DisableLegacyMFA *bool `access:"write_restrictable,cloud_restrictable"` - ExperimentalStrictCSRFEnforcement *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` - EnableEmailInvitations *bool `access:"authentication_signup"` - DisableBotsWhenOwnerIsDeactivated *bool `access:"integrations_bot_accounts,write_restrictable,cloud_restrictable"` - EnableBotAccountCreation *bool `access:"integrations_bot_accounts"` - EnableSVGs *bool `access:"site_posts"` - EnableLatex *bool `access:"site_posts"` - EnableAPIChannelDeletion *bool - EnableLocalMode *bool - LocalModeSocketLocation *string // telemetry: none - EnableAWSMetering *bool // telemetry: none - SplitKey *string `access:"experimental_feature_flags,write_restrictable"` // telemetry: none - FeatureFlagSyncIntervalSeconds *int `access:"experimental_feature_flags,write_restrictable"` // telemetry: none - DebugSplit *bool `access:"experimental_feature_flags,write_restrictable"` // telemetry: none - ThreadAutoFollow *bool `access:"experimental_features"` - CollapsedThreads *string `access:"experimental_features"` - ManagedResourcePaths *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` - EnableLegacySidebar *bool `access:"experimental_features"` - EnableReliableWebSockets *bool `access:"experimental_features"` // telemetry: none -} - -func (s *ServiceSettings) SetDefaults(isUpdate bool) { - if s.EnableEmailInvitations == nil { - // If the site URL is also not present then assume this is a clean install - if s.SiteURL == nil { - s.EnableEmailInvitations = NewBool(false) - } else { - s.EnableEmailInvitations = NewBool(true) - } - } - - if s.SiteURL == nil { - if s.EnableDeveloper != nil && *s.EnableDeveloper { - s.SiteURL = NewString(SERVICE_SETTINGS_DEFAULT_SITE_URL) - } else { - s.SiteURL = NewString("") - } - } - - if s.WebsocketURL == nil { - s.WebsocketURL = NewString("") - } - - if s.LicenseFileLocation == nil { - s.LicenseFileLocation = NewString("") - } - - if s.ListenAddress == nil { - s.ListenAddress = NewString(SERVICE_SETTINGS_DEFAULT_LISTEN_AND_ADDRESS) - } - - if s.EnableLinkPreviews == nil { - s.EnableLinkPreviews = NewBool(true) - } - - if s.RestrictLinkPreviews == nil { - s.RestrictLinkPreviews = NewString("") - } - - if s.EnableTesting == nil { - s.EnableTesting = NewBool(false) - } - - if s.EnableDeveloper == nil { - s.EnableDeveloper = NewBool(false) - } - - if s.EnableOpenTracing == nil { - s.EnableOpenTracing = NewBool(false) - } - - if s.EnableSecurityFixAlert == nil { - s.EnableSecurityFixAlert = NewBool(true) - } - - if s.EnableInsecureOutgoingConnections == nil { - s.EnableInsecureOutgoingConnections = NewBool(false) - } - - if s.AllowedUntrustedInternalConnections == nil { - s.AllowedUntrustedInternalConnections = NewString("") - } - - if s.EnableMultifactorAuthentication == nil { - s.EnableMultifactorAuthentication = NewBool(false) - } - - if s.EnforceMultifactorAuthentication == nil { - s.EnforceMultifactorAuthentication = NewBool(false) - } - - if s.EnableUserAccessTokens == nil { - s.EnableUserAccessTokens = NewBool(false) - } - - if s.GoroutineHealthThreshold == nil { - s.GoroutineHealthThreshold = NewInt(-1) - } - - if s.GoogleDeveloperKey == nil { - s.GoogleDeveloperKey = NewString("") - } - - if s.EnableOAuthServiceProvider == nil { - s.EnableOAuthServiceProvider = NewBool(false) - } - - if s.EnableIncomingWebhooks == nil { - s.EnableIncomingWebhooks = NewBool(true) - } - - if s.EnableOutgoingWebhooks == nil { - s.EnableOutgoingWebhooks = NewBool(true) - } - - if s.ConnectionSecurity == nil { - s.ConnectionSecurity = NewString("") - } - - if s.TLSKeyFile == nil { - s.TLSKeyFile = NewString(SERVICE_SETTINGS_DEFAULT_TLS_KEY_FILE) - } - - if s.TLSCertFile == nil { - s.TLSCertFile = NewString(SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE) - } - - if s.TLSMinVer == nil { - s.TLSMinVer = NewString("1.2") - } - - if s.TLSStrictTransport == nil { - s.TLSStrictTransport = NewBool(false) - } - - if s.TLSStrictTransportMaxAge == nil { - s.TLSStrictTransportMaxAge = NewInt64(63072000) - } - - if s.TLSOverwriteCiphers == nil { - s.TLSOverwriteCiphers = []string{} - } - - if s.UseLetsEncrypt == nil { - s.UseLetsEncrypt = NewBool(false) - } - - if s.LetsEncryptCertificateCacheFile == nil { - s.LetsEncryptCertificateCacheFile = NewString("./config/letsencrypt.cache") - } - - if s.ReadTimeout == nil { - s.ReadTimeout = NewInt(SERVICE_SETTINGS_DEFAULT_READ_TIMEOUT) - } - - if s.WriteTimeout == nil { - s.WriteTimeout = NewInt(SERVICE_SETTINGS_DEFAULT_WRITE_TIMEOUT) - } - - if s.IdleTimeout == nil { - s.IdleTimeout = NewInt(SERVICE_SETTINGS_DEFAULT_IDLE_TIMEOUT) - } - - if s.MaximumLoginAttempts == nil { - s.MaximumLoginAttempts = NewInt(SERVICE_SETTINGS_DEFAULT_MAX_LOGIN_ATTEMPTS) - } - - if s.Forward80To443 == nil { - s.Forward80To443 = NewBool(false) - } - - if isUpdate { - // When updating an existing configuration, ensure that defaults are set. - if s.TrustedProxyIPHeader == nil { - s.TrustedProxyIPHeader = []string{HEADER_FORWARDED, HEADER_REAL_IP} - } - } else { - // When generating a blank configuration, leave the list empty. - s.TrustedProxyIPHeader = []string{} - } - - if s.TimeBetweenUserTypingUpdatesMilliseconds == nil { - s.TimeBetweenUserTypingUpdatesMilliseconds = NewInt64(5000) - } - - if s.EnablePostSearch == nil { - s.EnablePostSearch = NewBool(true) - } - - if s.EnableFileSearch == nil { - s.EnableFileSearch = NewBool(true) - } - - if s.MinimumHashtagLength == nil { - s.MinimumHashtagLength = NewInt(3) - } - - if s.EnableUserTypingMessages == nil { - s.EnableUserTypingMessages = NewBool(true) - } - - if s.EnableChannelViewedMessages == nil { - s.EnableChannelViewedMessages = NewBool(true) - } - - if s.EnableUserStatuses == nil { - s.EnableUserStatuses = NewBool(true) - } - - if s.ClusterLogTimeoutMilliseconds == nil { - s.ClusterLogTimeoutMilliseconds = NewInt(2000) - } - - if s.CloseUnusedDirectMessages == nil { - s.CloseUnusedDirectMessages = NewBool(false) - } - - if s.EnableTutorial == nil { - s.EnableTutorial = NewBool(true) - } - - // Must be manually enabled for existing installations. - if s.ExtendSessionLengthWithActivity == nil { - s.ExtendSessionLengthWithActivity = NewBool(!isUpdate) - } - - if s.SessionLengthWebInDays == nil { - if isUpdate { - s.SessionLengthWebInDays = NewInt(180) - } else { - s.SessionLengthWebInDays = NewInt(30) - } - } - - if s.SessionLengthMobileInDays == nil { - if isUpdate { - s.SessionLengthMobileInDays = NewInt(180) - } else { - s.SessionLengthMobileInDays = NewInt(30) - } - } - - if s.SessionLengthSSOInDays == nil { - s.SessionLengthSSOInDays = NewInt(30) - } - - if s.SessionCacheInMinutes == nil { - s.SessionCacheInMinutes = NewInt(10) - } - - if s.SessionIdleTimeoutInMinutes == nil { - s.SessionIdleTimeoutInMinutes = NewInt(43200) - } - - if s.EnableCommands == nil { - s.EnableCommands = NewBool(true) - } - - if s.DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations == nil { - s.DEPRECATED_DO_NOT_USE_EnableOnlyAdminIntegrations = NewBool(true) - } - - if s.EnablePostUsernameOverride == nil { - s.EnablePostUsernameOverride = NewBool(false) - } - - if s.EnablePostIconOverride == nil { - s.EnablePostIconOverride = NewBool(false) - } - - if s.WebsocketPort == nil { - s.WebsocketPort = NewInt(80) - } - - if s.WebsocketSecurePort == nil { - s.WebsocketSecurePort = NewInt(443) - } - - if s.AllowCorsFrom == nil { - s.AllowCorsFrom = NewString(SERVICE_SETTINGS_DEFAULT_ALLOW_CORS_FROM) - } - - if s.CorsExposedHeaders == nil { - s.CorsExposedHeaders = NewString("") - } - - if s.CorsAllowCredentials == nil { - s.CorsAllowCredentials = NewBool(false) - } - - if s.CorsDebug == nil { - s.CorsDebug = NewBool(false) - } - - if s.AllowCookiesForSubdomains == nil { - s.AllowCookiesForSubdomains = NewBool(false) - } - - if s.WebserverMode == nil { - s.WebserverMode = NewString("gzip") - } else if *s.WebserverMode == "regular" { - *s.WebserverMode = "gzip" - } - - if s.EnableCustomEmoji == nil { - s.EnableCustomEmoji = NewBool(true) - } - - if s.EnableEmojiPicker == nil { - s.EnableEmojiPicker = NewBool(true) - } - - if s.EnableGifPicker == nil { - s.EnableGifPicker = NewBool(true) - } - - if s.GfycatApiKey == nil || *s.GfycatApiKey == "" { - s.GfycatApiKey = NewString(SERVICE_SETTINGS_DEFAULT_GFYCAT_API_KEY) - } - - if s.GfycatApiSecret == nil || *s.GfycatApiSecret == "" { - s.GfycatApiSecret = NewString(SERVICE_SETTINGS_DEFAULT_GFYCAT_API_SECRET) - } - - if s.DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation == nil { - s.DEPRECATED_DO_NOT_USE_RestrictCustomEmojiCreation = NewString(RESTRICT_EMOJI_CREATION_ALL) - } - - if s.DEPRECATED_DO_NOT_USE_RestrictPostDelete == nil { - s.DEPRECATED_DO_NOT_USE_RestrictPostDelete = NewString(PERMISSIONS_DELETE_POST_ALL) - } - - if s.DEPRECATED_DO_NOT_USE_AllowEditPost == nil { - s.DEPRECATED_DO_NOT_USE_AllowEditPost = NewString(ALLOW_EDIT_POST_ALWAYS) - } - - if s.ExperimentalEnableAuthenticationTransfer == nil { - s.ExperimentalEnableAuthenticationTransfer = NewBool(true) - } - - if s.PostEditTimeLimit == nil { - s.PostEditTimeLimit = NewInt(-1) - } - - if s.EnablePreviewFeatures == nil { - s.EnablePreviewFeatures = NewBool(true) - } - - if s.ExperimentalEnableDefaultChannelLeaveJoinMessages == nil { - s.ExperimentalEnableDefaultChannelLeaveJoinMessages = NewBool(true) - } - - if s.ExperimentalGroupUnreadChannels == nil { - s.ExperimentalGroupUnreadChannels = NewString(GROUP_UNREAD_CHANNELS_DISABLED) - } else if *s.ExperimentalGroupUnreadChannels == "0" { - s.ExperimentalGroupUnreadChannels = NewString(GROUP_UNREAD_CHANNELS_DISABLED) - } else if *s.ExperimentalGroupUnreadChannels == "1" { - s.ExperimentalGroupUnreadChannels = NewString(GROUP_UNREAD_CHANNELS_DEFAULT_ON) - } - - if s.ExperimentalChannelOrganization == nil { - experimentalUnreadEnabled := *s.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DISABLED - s.ExperimentalChannelOrganization = NewBool(experimentalUnreadEnabled) - } - - if s.DEPRECATED_DO_NOT_USE_ImageProxyType == nil { - s.DEPRECATED_DO_NOT_USE_ImageProxyType = NewString("") - } - - if s.DEPRECATED_DO_NOT_USE_ImageProxyURL == nil { - s.DEPRECATED_DO_NOT_USE_ImageProxyURL = NewString("") - } - - if s.DEPRECATED_DO_NOT_USE_ImageProxyOptions == nil { - s.DEPRECATED_DO_NOT_USE_ImageProxyOptions = NewString("") - } - - if s.EnableAPITeamDeletion == nil { - s.EnableAPITeamDeletion = NewBool(false) - } - - if s.EnableAPIUserDeletion == nil { - s.EnableAPIUserDeletion = NewBool(false) - } - - if s.EnableAPIChannelDeletion == nil { - s.EnableAPIChannelDeletion = NewBool(false) - } - - if s.ExperimentalEnableHardenedMode == nil { - s.ExperimentalEnableHardenedMode = NewBool(false) - } - - if s.DisableLegacyMFA == nil { - s.DisableLegacyMFA = NewBool(!isUpdate) - } - - if s.ExperimentalStrictCSRFEnforcement == nil { - s.ExperimentalStrictCSRFEnforcement = NewBool(false) - } - - if s.DisableBotsWhenOwnerIsDeactivated == nil { - s.DisableBotsWhenOwnerIsDeactivated = NewBool(true) - } - - if s.EnableBotAccountCreation == nil { - s.EnableBotAccountCreation = NewBool(false) - } - - if s.EnableSVGs == nil { - if isUpdate { - s.EnableSVGs = NewBool(true) - } else { - s.EnableSVGs = NewBool(false) - } - } - - if s.EnableLatex == nil { - if isUpdate { - s.EnableLatex = NewBool(true) - } else { - s.EnableLatex = NewBool(false) - } - } - - if s.EnableLocalMode == nil { - s.EnableLocalMode = NewBool(false) - } - - if s.LocalModeSocketLocation == nil { - s.LocalModeSocketLocation = NewString(LOCAL_MODE_SOCKET_PATH) - } - - if s.EnableAWSMetering == nil { - s.EnableAWSMetering = NewBool(false) - } - - if s.SplitKey == nil { - s.SplitKey = NewString("") - } - - if s.FeatureFlagSyncIntervalSeconds == nil { - s.FeatureFlagSyncIntervalSeconds = NewInt(30) - } - - if s.DebugSplit == nil { - s.DebugSplit = NewBool(false) - } - - if s.ThreadAutoFollow == nil { - s.ThreadAutoFollow = NewBool(true) - } - - if s.CollapsedThreads == nil { - s.CollapsedThreads = NewString(COLLAPSED_THREADS_DISABLED) - } - - if s.ManagedResourcePaths == nil { - s.ManagedResourcePaths = NewString("") - } - - if s.EnableLegacySidebar == nil { - s.EnableLegacySidebar = NewBool(false) - } - - if s.EnableReliableWebSockets == nil { - s.EnableReliableWebSockets = NewBool(true) - } -} - -type ClusterSettings struct { - Enable *bool `access:"environment_high_availability,write_restrictable"` - ClusterName *string `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none - OverrideHostname *string `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none - NetworkInterface *string `access:"environment_high_availability,write_restrictable,cloud_restrictable"` - BindAddress *string `access:"environment_high_availability,write_restrictable,cloud_restrictable"` - AdvertiseAddress *string `access:"environment_high_availability,write_restrictable,cloud_restrictable"` - UseIpAddress *bool `access:"environment_high_availability,write_restrictable,cloud_restrictable"` - DEPRECATED_DO_NOT_USE_UseExperimentalGossip *bool `json:"UseExperimentalGossip" access:"environment_high_availability,write_restrictable,cloud_restrictable"` // Deprecated: do not use - EnableGossipCompression *bool `access:"environment_high_availability,write_restrictable,cloud_restrictable"` - EnableExperimentalGossipEncryption *bool `access:"environment_high_availability,write_restrictable,cloud_restrictable"` - ReadOnlyConfig *bool `access:"environment_high_availability,write_restrictable,cloud_restrictable"` - GossipPort *int `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none - StreamingPort *int `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none - MaxIdleConns *int `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none - MaxIdleConnsPerHost *int `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none - IdleConnTimeoutMilliseconds *int `access:"environment_high_availability,write_restrictable,cloud_restrictable"` // telemetry: none -} - -func (s *ClusterSettings) SetDefaults() { - if s.Enable == nil { - s.Enable = NewBool(false) - } - - if s.ClusterName == nil { - s.ClusterName = NewString("") - } - - if s.OverrideHostname == nil { - s.OverrideHostname = NewString("") - } - - if s.NetworkInterface == nil { - s.NetworkInterface = NewString("") - } - - if s.BindAddress == nil { - s.BindAddress = NewString("") - } - - if s.AdvertiseAddress == nil { - s.AdvertiseAddress = NewString("") - } - - if s.UseIpAddress == nil { - s.UseIpAddress = NewBool(true) - } - - if s.DEPRECATED_DO_NOT_USE_UseExperimentalGossip == nil { - s.DEPRECATED_DO_NOT_USE_UseExperimentalGossip = NewBool(true) - } - - if s.EnableExperimentalGossipEncryption == nil { - s.EnableExperimentalGossipEncryption = NewBool(false) - } - - if s.EnableGossipCompression == nil { - s.EnableGossipCompression = NewBool(true) - } - - if s.ReadOnlyConfig == nil { - s.ReadOnlyConfig = NewBool(true) - } - - if s.GossipPort == nil { - s.GossipPort = NewInt(8074) - } - - if s.StreamingPort == nil { - s.StreamingPort = NewInt(8075) - } - - if s.MaxIdleConns == nil { - s.MaxIdleConns = NewInt(100) - } - - if s.MaxIdleConnsPerHost == nil { - s.MaxIdleConnsPerHost = NewInt(128) - } - - if s.IdleConnTimeoutMilliseconds == nil { - s.IdleConnTimeoutMilliseconds = NewInt(90000) - } -} - -type MetricsSettings struct { - Enable *bool `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"` - BlockProfileRate *int `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"` - ListenAddress *string `access:"environment_performance_monitoring,write_restrictable,cloud_restrictable"` // telemetry: none -} - -func (s *MetricsSettings) SetDefaults() { - if s.ListenAddress == nil { - s.ListenAddress = NewString(":8067") - } - - if s.Enable == nil { - s.Enable = NewBool(false) - } - - if s.BlockProfileRate == nil { - s.BlockProfileRate = NewInt(0) - } -} - -type ExperimentalSettings struct { - ClientSideCertEnable *bool `access:"experimental_features,cloud_restrictable"` - ClientSideCertCheck *string `access:"experimental_features,cloud_restrictable"` - EnableClickToReply *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` - LinkMetadataTimeoutMilliseconds *int64 `access:"experimental_features,write_restrictable,cloud_restrictable"` - RestrictSystemAdmin *bool `access:"experimental_features,write_restrictable"` - UseNewSAMLLibrary *bool `access:"experimental_features,cloud_restrictable"` - CloudUserLimit *int64 `access:"experimental_features,write_restrictable"` - CloudBilling *bool `access:"experimental_features,write_restrictable"` - EnableSharedChannels *bool `access:"experimental_features"` - EnableRemoteClusterService *bool `access:"experimental_features"` -} - -func (s *ExperimentalSettings) SetDefaults() { - if s.ClientSideCertEnable == nil { - s.ClientSideCertEnable = NewBool(false) - } - - if s.ClientSideCertCheck == nil { - s.ClientSideCertCheck = NewString(CLIENT_SIDE_CERT_CHECK_SECONDARY_AUTH) - } - - if s.EnableClickToReply == nil { - s.EnableClickToReply = NewBool(false) - } - - if s.LinkMetadataTimeoutMilliseconds == nil { - s.LinkMetadataTimeoutMilliseconds = NewInt64(EXPERIMENTAL_SETTINGS_DEFAULT_LINK_METADATA_TIMEOUT_MILLISECONDS) - } - - if s.RestrictSystemAdmin == nil { - s.RestrictSystemAdmin = NewBool(false) - } - - if s.CloudUserLimit == nil { - // User limit 0 is treated as no limit - s.CloudUserLimit = NewInt64(0) - } - - if s.CloudBilling == nil { - s.CloudBilling = NewBool(false) - } - - if s.UseNewSAMLLibrary == nil { - s.UseNewSAMLLibrary = NewBool(false) - } - - if s.EnableSharedChannels == nil { - s.EnableSharedChannels = NewBool(false) - } - - if s.EnableRemoteClusterService == nil { - s.EnableRemoteClusterService = NewBool(false) - } -} - -type AnalyticsSettings struct { - MaxUsersForStatistics *int `access:"write_restrictable,cloud_restrictable"` -} - -func (s *AnalyticsSettings) SetDefaults() { - if s.MaxUsersForStatistics == nil { - s.MaxUsersForStatistics = NewInt(ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS) - } -} - -type SSOSettings struct { - Enable *bool `access:"authentication_openid"` - Secret *string `access:"authentication_openid"` // telemetry: none - Id *string `access:"authentication_openid"` // telemetry: none - Scope *string `access:"authentication_openid"` // telemetry: none - AuthEndpoint *string `access:"authentication_openid"` // telemetry: none - TokenEndpoint *string `access:"authentication_openid"` // telemetry: none - UserApiEndpoint *string `access:"authentication_openid"` // telemetry: none - DiscoveryEndpoint *string `access:"authentication_openid"` // telemetry: none - ButtonText *string `access:"authentication_openid"` // telemetry: none - ButtonColor *string `access:"authentication_openid"` // telemetry: none -} - -func (s *SSOSettings) setDefaults(scope, authEndpoint, tokenEndpoint, userApiEndpoint, buttonColor string) { - if s.Enable == nil { - s.Enable = NewBool(false) - } - - if s.Secret == nil { - s.Secret = NewString("") - } - - if s.Id == nil { - s.Id = NewString("") - } - - if s.Scope == nil { - s.Scope = NewString(scope) - } - - if s.DiscoveryEndpoint == nil { - s.DiscoveryEndpoint = NewString("") - } - - if s.AuthEndpoint == nil { - s.AuthEndpoint = NewString(authEndpoint) - } - - if s.TokenEndpoint == nil { - s.TokenEndpoint = NewString(tokenEndpoint) - } - - if s.UserApiEndpoint == nil { - s.UserApiEndpoint = NewString(userApiEndpoint) - } - - if s.ButtonText == nil { - s.ButtonText = NewString("") - } - - if s.ButtonColor == nil { - s.ButtonColor = NewString(buttonColor) - } -} - -type Office365Settings struct { - Enable *bool `access:"authentication_openid"` - Secret *string `access:"authentication_openid"` // telemetry: none - Id *string `access:"authentication_openid"` // telemetry: none - Scope *string `access:"authentication_openid"` - AuthEndpoint *string `access:"authentication_openid"` // telemetry: none - TokenEndpoint *string `access:"authentication_openid"` // telemetry: none - UserApiEndpoint *string `access:"authentication_openid"` // telemetry: none - DiscoveryEndpoint *string `access:"authentication_openid"` // telemetry: none - DirectoryId *string `access:"authentication_openid"` // telemetry: none -} - -func (s *Office365Settings) setDefaults() { - if s.Enable == nil { - s.Enable = NewBool(false) - } - - if s.Id == nil { - s.Id = NewString("") - } - - if s.Secret == nil { - s.Secret = NewString("") - } - - if s.Scope == nil { - s.Scope = NewString(OFFICE365_SETTINGS_DEFAULT_SCOPE) - } - - if s.DiscoveryEndpoint == nil { - s.DiscoveryEndpoint = NewString("") - } - - if s.AuthEndpoint == nil { - s.AuthEndpoint = NewString(OFFICE365_SETTINGS_DEFAULT_AUTH_ENDPOINT) - } - - if s.TokenEndpoint == nil { - s.TokenEndpoint = NewString(OFFICE365_SETTINGS_DEFAULT_TOKEN_ENDPOINT) - } - - if s.UserApiEndpoint == nil { - s.UserApiEndpoint = NewString(OFFICE365_SETTINGS_DEFAULT_USER_API_ENDPOINT) - } - - if s.DirectoryId == nil { - s.DirectoryId = NewString("") - } -} - -func (s *Office365Settings) SSOSettings() *SSOSettings { - ssoSettings := SSOSettings{} - ssoSettings.Enable = s.Enable - ssoSettings.Secret = s.Secret - ssoSettings.Id = s.Id - ssoSettings.Scope = s.Scope - ssoSettings.DiscoveryEndpoint = s.DiscoveryEndpoint - ssoSettings.AuthEndpoint = s.AuthEndpoint - ssoSettings.TokenEndpoint = s.TokenEndpoint - ssoSettings.UserApiEndpoint = s.UserApiEndpoint - return &ssoSettings -} - -type ReplicaLagSettings struct { - DataSource *string `access:"environment,write_restrictable,cloud_restrictable"` // telemetry: none - QueryAbsoluteLag *string `access:"environment,write_restrictable,cloud_restrictable"` // telemetry: none - QueryTimeLag *string `access:"environment,write_restrictable,cloud_restrictable"` // telemetry: none -} - -type SqlSettings struct { - DriverName *string `access:"environment_database,write_restrictable,cloud_restrictable"` - DataSource *string `access:"environment_database,write_restrictable,cloud_restrictable"` // telemetry: none - DataSourceReplicas []string `access:"environment_database,write_restrictable,cloud_restrictable"` - DataSourceSearchReplicas []string `access:"environment_database,write_restrictable,cloud_restrictable"` - MaxIdleConns *int `access:"environment_database,write_restrictable,cloud_restrictable"` - ConnMaxLifetimeMilliseconds *int `access:"environment_database,write_restrictable,cloud_restrictable"` - ConnMaxIdleTimeMilliseconds *int `access:"environment_database,write_restrictable,cloud_restrictable"` - MaxOpenConns *int `access:"environment_database,write_restrictable,cloud_restrictable"` - Trace *bool `access:"environment_database,write_restrictable,cloud_restrictable"` - AtRestEncryptKey *string `access:"environment_database,write_restrictable,cloud_restrictable"` // telemetry: none - QueryTimeout *int `access:"environment_database,write_restrictable,cloud_restrictable"` - DisableDatabaseSearch *bool `access:"environment_database,write_restrictable,cloud_restrictable"` - ReplicaLagSettings []*ReplicaLagSettings `access:"environment_database,write_restrictable,cloud_restrictable"` // telemetry: none -} - -func (s *SqlSettings) SetDefaults(isUpdate bool) { - if s.DriverName == nil { - s.DriverName = NewString(DATABASE_DRIVER_POSTGRES) - } - - if s.DataSource == nil { - s.DataSource = NewString(SQL_SETTINGS_DEFAULT_DATA_SOURCE) - } - - if s.DataSourceReplicas == nil { - s.DataSourceReplicas = []string{} - } - - if s.DataSourceSearchReplicas == nil { - s.DataSourceSearchReplicas = []string{} - } - - if isUpdate { - // When updating an existing configuration, ensure an encryption key has been specified. - if s.AtRestEncryptKey == nil || *s.AtRestEncryptKey == "" { - s.AtRestEncryptKey = NewString(NewRandomString(32)) - } - } else { - // When generating a blank configuration, leave this key empty to be generated on server start. - s.AtRestEncryptKey = NewString("") - } - - if s.MaxIdleConns == nil { - s.MaxIdleConns = NewInt(20) - } - - if s.MaxOpenConns == nil { - s.MaxOpenConns = NewInt(300) - } - - if s.ConnMaxLifetimeMilliseconds == nil { - s.ConnMaxLifetimeMilliseconds = NewInt(3600000) - } - - if s.ConnMaxIdleTimeMilliseconds == nil { - s.ConnMaxIdleTimeMilliseconds = NewInt(300000) - } - - if s.Trace == nil { - s.Trace = NewBool(false) - } - - if s.QueryTimeout == nil { - s.QueryTimeout = NewInt(30) - } - - if s.DisableDatabaseSearch == nil { - s.DisableDatabaseSearch = NewBool(false) - } - - if s.ReplicaLagSettings == nil { - s.ReplicaLagSettings = []*ReplicaLagSettings{} - } -} - -type LogSettings struct { - EnableConsole *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` - ConsoleLevel *string `access:"environment_logging,write_restrictable,cloud_restrictable"` - ConsoleJson *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` - EnableColor *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` // telemetry: none - EnableFile *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` - FileLevel *string `access:"environment_logging,write_restrictable,cloud_restrictable"` - FileJson *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` - FileLocation *string `access:"environment_logging,write_restrictable,cloud_restrictable"` - EnableWebhookDebugging *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` - EnableDiagnostics *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` // telemetry: none - EnableSentry *bool `access:"environment_logging,write_restrictable,cloud_restrictable"` // telemetry: none - AdvancedLoggingConfig *string `access:"environment_logging,write_restrictable,cloud_restrictable"` -} - -func (s *LogSettings) SetDefaults() { - if s.EnableConsole == nil { - s.EnableConsole = NewBool(true) - } - - if s.ConsoleLevel == nil { - s.ConsoleLevel = NewString("DEBUG") - } - - if s.EnableColor == nil { - s.EnableColor = NewBool(false) - } - - if s.EnableFile == nil { - s.EnableFile = NewBool(true) - } - - if s.FileLevel == nil { - s.FileLevel = NewString("INFO") - } - - if s.FileLocation == nil { - s.FileLocation = NewString("") - } - - if s.EnableWebhookDebugging == nil { - s.EnableWebhookDebugging = NewBool(true) - } - - if s.EnableDiagnostics == nil { - s.EnableDiagnostics = NewBool(true) - } - - if s.EnableSentry == nil { - s.EnableSentry = NewBool(*s.EnableDiagnostics) - } - - if s.ConsoleJson == nil { - s.ConsoleJson = NewBool(true) - } - - if s.FileJson == nil { - s.FileJson = NewBool(true) - } - - if s.AdvancedLoggingConfig == nil { - s.AdvancedLoggingConfig = NewString("") - } -} - -type ExperimentalAuditSettings struct { - FileEnabled *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` - FileName *string `access:"experimental_features,write_restrictable,cloud_restrictable"` // telemetry: none - FileMaxSizeMB *int `access:"experimental_features,write_restrictable,cloud_restrictable"` - FileMaxAgeDays *int `access:"experimental_features,write_restrictable,cloud_restrictable"` - FileMaxBackups *int `access:"experimental_features,write_restrictable,cloud_restrictable"` - FileCompress *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` - FileMaxQueueSize *int `access:"experimental_features,write_restrictable,cloud_restrictable"` - AdvancedLoggingConfig *string `access:"experimental_features,write_restrictable,cloud_restrictable"` -} - -func (s *ExperimentalAuditSettings) SetDefaults() { - if s.FileEnabled == nil { - s.FileEnabled = NewBool(false) - } - - if s.FileName == nil { - s.FileName = NewString("") - } - - if s.FileMaxSizeMB == nil { - s.FileMaxSizeMB = NewInt(100) - } - - if s.FileMaxAgeDays == nil { - s.FileMaxAgeDays = NewInt(0) // no limit on age - } - - if s.FileMaxBackups == nil { // no limit on number of backups - s.FileMaxBackups = NewInt(0) - } - - if s.FileCompress == nil { - s.FileCompress = NewBool(false) - } - - if s.FileMaxQueueSize == nil { - s.FileMaxQueueSize = NewInt(1000) - } - - if s.AdvancedLoggingConfig == nil { - s.AdvancedLoggingConfig = NewString("") - } -} - -type NotificationLogSettings struct { - EnableConsole *bool `access:"write_restrictable,cloud_restrictable"` - ConsoleLevel *string `access:"write_restrictable,cloud_restrictable"` - ConsoleJson *bool `access:"write_restrictable,cloud_restrictable"` - EnableColor *bool `access:"write_restrictable,cloud_restrictable"` // telemetry: none - EnableFile *bool `access:"write_restrictable,cloud_restrictable"` - FileLevel *string `access:"write_restrictable,cloud_restrictable"` - FileJson *bool `access:"write_restrictable,cloud_restrictable"` - FileLocation *string `access:"write_restrictable,cloud_restrictable"` - AdvancedLoggingConfig *string `access:"write_restrictable,cloud_restrictable"` -} - -func (s *NotificationLogSettings) SetDefaults() { - if s.EnableConsole == nil { - s.EnableConsole = NewBool(true) - } - - if s.ConsoleLevel == nil { - s.ConsoleLevel = NewString("DEBUG") - } - - if s.EnableFile == nil { - s.EnableFile = NewBool(true) - } - - if s.FileLevel == nil { - s.FileLevel = NewString("INFO") - } - - if s.FileLocation == nil { - s.FileLocation = NewString("") - } - - if s.ConsoleJson == nil { - s.ConsoleJson = NewBool(true) - } - - if s.EnableColor == nil { - s.EnableColor = NewBool(false) - } - - if s.FileJson == nil { - s.FileJson = NewBool(true) - } - - if s.AdvancedLoggingConfig == nil { - s.AdvancedLoggingConfig = NewString("") - } -} - -type PasswordSettings struct { - MinimumLength *int `access:"authentication_password"` - Lowercase *bool `access:"authentication_password"` - Number *bool `access:"authentication_password"` - Uppercase *bool `access:"authentication_password"` - Symbol *bool `access:"authentication_password"` -} - -func (s *PasswordSettings) SetDefaults() { - if s.MinimumLength == nil { - s.MinimumLength = NewInt(10) - } - - if s.Lowercase == nil { - s.Lowercase = NewBool(true) - } - - if s.Number == nil { - s.Number = NewBool(true) - } - - if s.Uppercase == nil { - s.Uppercase = NewBool(true) - } - - if s.Symbol == nil { - s.Symbol = NewBool(true) - } -} - -type FileSettings struct { - EnableFileAttachments *bool `access:"site_file_sharing_and_downloads,cloud_restrictable"` - EnableMobileUpload *bool `access:"site_file_sharing_and_downloads,cloud_restrictable"` - EnableMobileDownload *bool `access:"site_file_sharing_and_downloads,cloud_restrictable"` - MaxFileSize *int64 `access:"environment_file_storage,cloud_restrictable"` - DriverName *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` - Directory *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` - EnablePublicLink *bool `access:"site_public_links,cloud_restrictable"` - ExtractContent *bool `access:"environment_file_storage,write_restrictable"` - ArchiveRecursion *bool `access:"environment_file_storage,write_restrictable"` - PublicLinkSalt *string `access:"site_public_links,cloud_restrictable"` // telemetry: none - InitialFont *string `access:"environment_file_storage,cloud_restrictable"` // telemetry: none - AmazonS3AccessKeyId *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none - AmazonS3SecretAccessKey *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none - AmazonS3Bucket *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none - AmazonS3PathPrefix *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none - AmazonS3Region *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none - AmazonS3Endpoint *string `access:"environment_file_storage,write_restrictable,cloud_restrictable"` // telemetry: none - AmazonS3SSL *bool `access:"environment_file_storage,write_restrictable,cloud_restrictable"` - AmazonS3SignV2 *bool `access:"environment_file_storage,write_restrictable,cloud_restrictable"` - AmazonS3SSE *bool `access:"environment_file_storage,write_restrictable,cloud_restrictable"` - AmazonS3Trace *bool `access:"environment_file_storage,write_restrictable,cloud_restrictable"` -} - -func (s *FileSettings) SetDefaults(isUpdate bool) { - if s.EnableFileAttachments == nil { - s.EnableFileAttachments = NewBool(true) - } - - if s.EnableMobileUpload == nil { - s.EnableMobileUpload = NewBool(true) - } - - if s.EnableMobileDownload == nil { - s.EnableMobileDownload = NewBool(true) - } - - if s.MaxFileSize == nil { - s.MaxFileSize = NewInt64(MB * 100) - } - - if s.DriverName == nil { - s.DriverName = NewString(IMAGE_DRIVER_LOCAL) - } - - if s.Directory == nil || *s.Directory == "" { - s.Directory = NewString(FILE_SETTINGS_DEFAULT_DIRECTORY) - } - - if s.EnablePublicLink == nil { - s.EnablePublicLink = NewBool(false) - } - - if s.ExtractContent == nil { - s.ExtractContent = NewBool(true) - } - - if s.ArchiveRecursion == nil { - s.ArchiveRecursion = NewBool(false) - } - - if isUpdate { - // When updating an existing configuration, ensure link salt has been specified. - if s.PublicLinkSalt == nil || *s.PublicLinkSalt == "" { - s.PublicLinkSalt = NewString(NewRandomString(32)) - } - } else { - // When generating a blank configuration, leave link salt empty to be generated on server start. - s.PublicLinkSalt = NewString("") - } - - if s.InitialFont == nil { - // Defaults to "nunito-bold.ttf" - s.InitialFont = NewString("nunito-bold.ttf") - } - - if s.AmazonS3AccessKeyId == nil { - s.AmazonS3AccessKeyId = NewString("") - } - - if s.AmazonS3SecretAccessKey == nil { - s.AmazonS3SecretAccessKey = NewString("") - } - - if s.AmazonS3Bucket == nil { - s.AmazonS3Bucket = NewString("") - } - - if s.AmazonS3PathPrefix == nil { - s.AmazonS3PathPrefix = NewString("") - } - - if s.AmazonS3Region == nil { - s.AmazonS3Region = NewString("") - } - - if s.AmazonS3Endpoint == nil || *s.AmazonS3Endpoint == "" { - // Defaults to "s3.amazonaws.com" - s.AmazonS3Endpoint = NewString("s3.amazonaws.com") - } - - if s.AmazonS3SSL == nil { - s.AmazonS3SSL = NewBool(true) // Secure by default. - } - - if s.AmazonS3SignV2 == nil { - s.AmazonS3SignV2 = new(bool) - // Signature v2 is not enabled by default. - } - - if s.AmazonS3SSE == nil { - s.AmazonS3SSE = NewBool(false) // Not Encrypted by default. - } - - if s.AmazonS3Trace == nil { - s.AmazonS3Trace = NewBool(false) - } -} - -func (s *FileSettings) ToFileBackendSettings(enableComplianceFeature bool) filestore.FileBackendSettings { - if *s.DriverName == IMAGE_DRIVER_LOCAL { - return filestore.FileBackendSettings{ - DriverName: *s.DriverName, - Directory: *s.Directory, - } - } - return filestore.FileBackendSettings{ - DriverName: *s.DriverName, - AmazonS3AccessKeyId: *s.AmazonS3AccessKeyId, - AmazonS3SecretAccessKey: *s.AmazonS3SecretAccessKey, - AmazonS3Bucket: *s.AmazonS3Bucket, - AmazonS3PathPrefix: *s.AmazonS3PathPrefix, - AmazonS3Region: *s.AmazonS3Region, - AmazonS3Endpoint: *s.AmazonS3Endpoint, - AmazonS3SSL: s.AmazonS3SSL == nil || *s.AmazonS3SSL, - AmazonS3SignV2: s.AmazonS3SignV2 != nil && *s.AmazonS3SignV2, - AmazonS3SSE: s.AmazonS3SSE != nil && *s.AmazonS3SSE && enableComplianceFeature, - AmazonS3Trace: s.AmazonS3Trace != nil && *s.AmazonS3Trace, - } -} - -type EmailSettings struct { - EnableSignUpWithEmail *bool `access:"authentication_email"` - EnableSignInWithEmail *bool `access:"authentication_email"` - EnableSignInWithUsername *bool `access:"authentication_email"` - SendEmailNotifications *bool `access:"site_notifications"` - UseChannelInEmailNotifications *bool `access:"experimental_features"` - RequireEmailVerification *bool `access:"authentication_email"` - FeedbackName *string `access:"site_notifications"` - FeedbackEmail *string `access:"site_notifications,cloud_restrictable"` - ReplyToAddress *string `access:"site_notifications,cloud_restrictable"` - FeedbackOrganization *string `access:"site_notifications"` - EnableSMTPAuth *bool `access:"environment_smtp,write_restrictable,cloud_restrictable"` - SMTPUsername *string `access:"environment_smtp,write_restrictable,cloud_restrictable"` // telemetry: none - SMTPPassword *string `access:"environment_smtp,write_restrictable,cloud_restrictable"` // telemetry: none - SMTPServer *string `access:"environment_smtp,write_restrictable,cloud_restrictable"` // telemetry: none - SMTPPort *string `access:"environment_smtp,write_restrictable,cloud_restrictable"` // telemetry: none - SMTPServerTimeout *int `access:"cloud_restrictable"` - ConnectionSecurity *string `access:"environment_smtp,write_restrictable,cloud_restrictable"` - SendPushNotifications *bool `access:"environment_push_notification_server"` - PushNotificationServer *string `access:"environment_push_notification_server"` // telemetry: none - PushNotificationContents *string `access:"site_notifications"` - PushNotificationBuffer *int // telemetry: none - EnableEmailBatching *bool `access:"site_notifications"` - EmailBatchingBufferSize *int `access:"experimental_features"` - EmailBatchingInterval *int `access:"experimental_features"` - EnablePreviewModeBanner *bool `access:"site_notifications"` - SkipServerCertificateVerification *bool `access:"environment_smtp,write_restrictable,cloud_restrictable"` - EmailNotificationContentsType *string `access:"site_notifications"` - LoginButtonColor *string `access:"experimental_features"` - LoginButtonBorderColor *string `access:"experimental_features"` - LoginButtonTextColor *string `access:"experimental_features"` -} - -func (s *EmailSettings) SetDefaults(isUpdate bool) { - if s.EnableSignUpWithEmail == nil { - s.EnableSignUpWithEmail = NewBool(true) - } - - if s.EnableSignInWithEmail == nil { - s.EnableSignInWithEmail = NewBool(*s.EnableSignUpWithEmail) - } - - if s.EnableSignInWithUsername == nil { - s.EnableSignInWithUsername = NewBool(true) - } - - if s.SendEmailNotifications == nil { - s.SendEmailNotifications = NewBool(true) - } - - if s.UseChannelInEmailNotifications == nil { - s.UseChannelInEmailNotifications = NewBool(false) - } - - if s.RequireEmailVerification == nil { - s.RequireEmailVerification = NewBool(false) - } - - if s.FeedbackName == nil { - s.FeedbackName = NewString("") - } - - if s.FeedbackEmail == nil { - s.FeedbackEmail = NewString("test@example.com") - } - - if s.ReplyToAddress == nil { - s.ReplyToAddress = NewString("test@example.com") - } - - if s.FeedbackOrganization == nil { - s.FeedbackOrganization = NewString(EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION) - } - - if s.EnableSMTPAuth == nil { - if s.ConnectionSecurity == nil || *s.ConnectionSecurity == CONN_SECURITY_NONE { - s.EnableSMTPAuth = NewBool(false) - } else { - s.EnableSMTPAuth = NewBool(true) - } - } - - if s.SMTPUsername == nil { - s.SMTPUsername = NewString("") - } - - if s.SMTPPassword == nil { - s.SMTPPassword = NewString("") - } - - if s.SMTPServer == nil || *s.SMTPServer == "" { - s.SMTPServer = NewString("localhost") - } - - if s.SMTPPort == nil || *s.SMTPPort == "" { - s.SMTPPort = NewString("10025") - } - - if s.SMTPServerTimeout == nil || *s.SMTPServerTimeout == 0 { - s.SMTPServerTimeout = NewInt(10) - } - - if s.ConnectionSecurity == nil || *s.ConnectionSecurity == CONN_SECURITY_PLAIN { - s.ConnectionSecurity = NewString(CONN_SECURITY_NONE) - } - - if s.SendPushNotifications == nil { - s.SendPushNotifications = NewBool(!isUpdate) - } - - if s.PushNotificationServer == nil { - if isUpdate { - s.PushNotificationServer = NewString("") - } else { - s.PushNotificationServer = NewString(GENERIC_NOTIFICATION_SERVER) - } - } - - if s.PushNotificationContents == nil { - s.PushNotificationContents = NewString(FULL_NOTIFICATION) - } - - if s.PushNotificationBuffer == nil { - s.PushNotificationBuffer = NewInt(1000) - } - - if s.EnableEmailBatching == nil { - s.EnableEmailBatching = NewBool(false) - } - - if s.EmailBatchingBufferSize == nil { - s.EmailBatchingBufferSize = NewInt(EMAIL_BATCHING_BUFFER_SIZE) - } - - if s.EmailBatchingInterval == nil { - s.EmailBatchingInterval = NewInt(EMAIL_BATCHING_INTERVAL) - } - - if s.EnablePreviewModeBanner == nil { - s.EnablePreviewModeBanner = NewBool(true) - } - - if s.EnableSMTPAuth == nil { - if *s.ConnectionSecurity == CONN_SECURITY_NONE { - s.EnableSMTPAuth = NewBool(false) - } else { - s.EnableSMTPAuth = NewBool(true) - } - } - - if *s.ConnectionSecurity == CONN_SECURITY_PLAIN { - *s.ConnectionSecurity = CONN_SECURITY_NONE - } - - if s.SkipServerCertificateVerification == nil { - s.SkipServerCertificateVerification = NewBool(false) - } - - if s.EmailNotificationContentsType == nil { - s.EmailNotificationContentsType = NewString(EMAIL_NOTIFICATION_CONTENTS_FULL) - } - - if s.LoginButtonColor == nil { - s.LoginButtonColor = NewString("#0000") - } - - if s.LoginButtonBorderColor == nil { - s.LoginButtonBorderColor = NewString("#2389D7") - } - - if s.LoginButtonTextColor == nil { - s.LoginButtonTextColor = NewString("#2389D7") - } -} - -type RateLimitSettings struct { - Enable *bool `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` - PerSec *int `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` - MaxBurst *int `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` - MemoryStoreSize *int `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` - VaryByRemoteAddr *bool `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` - VaryByUser *bool `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` - VaryByHeader string `access:"environment_rate_limiting,write_restrictable,cloud_restrictable"` -} - -func (s *RateLimitSettings) SetDefaults() { - if s.Enable == nil { - s.Enable = NewBool(false) - } - - if s.PerSec == nil { - s.PerSec = NewInt(10) - } - - if s.MaxBurst == nil { - s.MaxBurst = NewInt(100) - } - - if s.MemoryStoreSize == nil { - s.MemoryStoreSize = NewInt(10000) - } - - if s.VaryByRemoteAddr == nil { - s.VaryByRemoteAddr = NewBool(true) - } - - if s.VaryByUser == nil { - s.VaryByUser = NewBool(false) - } -} - -type PrivacySettings struct { - ShowEmailAddress *bool `access:"site_users_and_teams"` - ShowFullName *bool `access:"site_users_and_teams"` -} - -func (s *PrivacySettings) setDefaults() { - if s.ShowEmailAddress == nil { - s.ShowEmailAddress = NewBool(true) - } - - if s.ShowFullName == nil { - s.ShowFullName = NewBool(true) - } -} - -type SupportSettings struct { - TermsOfServiceLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` - PrivacyPolicyLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` - AboutLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` - HelpLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` - ReportAProblemLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` - SupportEmail *string `access:"site_customization"` - CustomTermsOfServiceEnabled *bool `access:"compliance_custom_terms_of_service"` - CustomTermsOfServiceReAcceptancePeriod *int `access:"compliance_custom_terms_of_service"` - EnableAskCommunityLink *bool `access:"site_customization"` -} - -func (s *SupportSettings) SetDefaults() { - if !IsSafeLink(s.TermsOfServiceLink) { - *s.TermsOfServiceLink = SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK - } - - if s.TermsOfServiceLink == nil { - s.TermsOfServiceLink = NewString(SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK) - } - - if !IsSafeLink(s.PrivacyPolicyLink) { - *s.PrivacyPolicyLink = "" - } - - if s.PrivacyPolicyLink == nil { - s.PrivacyPolicyLink = NewString(SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK) - } - - if !IsSafeLink(s.AboutLink) { - *s.AboutLink = "" - } - - if s.AboutLink == nil { - s.AboutLink = NewString(SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK) - } - - if !IsSafeLink(s.HelpLink) { - *s.HelpLink = "" - } - - if s.HelpLink == nil { - s.HelpLink = NewString(SUPPORT_SETTINGS_DEFAULT_HELP_LINK) - } - - if !IsSafeLink(s.ReportAProblemLink) { - *s.ReportAProblemLink = "" - } - - if s.ReportAProblemLink == nil { - s.ReportAProblemLink = NewString(SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK) - } - - if s.SupportEmail == nil { - s.SupportEmail = NewString(SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL) - } - - if s.CustomTermsOfServiceEnabled == nil { - s.CustomTermsOfServiceEnabled = NewBool(false) - } - - if s.CustomTermsOfServiceReAcceptancePeriod == nil { - s.CustomTermsOfServiceReAcceptancePeriod = NewInt(SUPPORT_SETTINGS_DEFAULT_RE_ACCEPTANCE_PERIOD) - } - - if s.EnableAskCommunityLink == nil { - s.EnableAskCommunityLink = NewBool(true) - } -} - -type AnnouncementSettings struct { - EnableBanner *bool `access:"site_announcement_banner"` - BannerText *string `access:"site_announcement_banner"` // telemetry: none - BannerColor *string `access:"site_announcement_banner"` - BannerTextColor *string `access:"site_announcement_banner"` - AllowBannerDismissal *bool `access:"site_announcement_banner"` - AdminNoticesEnabled *bool `access:"site_notices"` - UserNoticesEnabled *bool `access:"site_notices"` - NoticesURL *string `access:"site_notices,write_restrictable"` // telemetry: none - NoticesFetchFrequency *int `access:"site_notices,write_restrictable"` // telemetry: none - NoticesSkipCache *bool `access:"site_notices,write_restrictable"` // telemetry: none -} - -func (s *AnnouncementSettings) SetDefaults() { - if s.EnableBanner == nil { - s.EnableBanner = NewBool(false) - } - - if s.BannerText == nil { - s.BannerText = NewString("") - } - - if s.BannerColor == nil { - s.BannerColor = NewString(ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_COLOR) - } - - if s.BannerTextColor == nil { - s.BannerTextColor = NewString(ANNOUNCEMENT_SETTINGS_DEFAULT_BANNER_TEXT_COLOR) - } - - if s.AllowBannerDismissal == nil { - s.AllowBannerDismissal = NewBool(true) - } - - if s.AdminNoticesEnabled == nil { - s.AdminNoticesEnabled = NewBool(true) - } - - if s.UserNoticesEnabled == nil { - s.UserNoticesEnabled = NewBool(true) - } - if s.NoticesURL == nil { - s.NoticesURL = NewString(ANNOUNCEMENT_SETTINGS_DEFAULT_NOTICES_JSON_URL) - } - if s.NoticesSkipCache == nil { - s.NoticesSkipCache = NewBool(false) - } - if s.NoticesFetchFrequency == nil { - s.NoticesFetchFrequency = NewInt(ANNOUNCEMENT_SETTINGS_DEFAULT_NOTICES_FETCH_FREQUENCY_SECONDS) - } - -} - -type ThemeSettings struct { - EnableThemeSelection *bool `access:"experimental_features"` - DefaultTheme *string `access:"experimental_features"` - AllowCustomThemes *bool `access:"experimental_features"` - AllowedThemes []string -} - -func (s *ThemeSettings) SetDefaults() { - if s.EnableThemeSelection == nil { - s.EnableThemeSelection = NewBool(true) - } - - if s.DefaultTheme == nil { - s.DefaultTheme = NewString(TEAM_SETTINGS_DEFAULT_TEAM_TEXT) - } - - if s.AllowCustomThemes == nil { - s.AllowCustomThemes = NewBool(true) - } - - if s.AllowedThemes == nil { - s.AllowedThemes = []string{} - } -} - -type TeamSettings struct { - SiteName *string `access:"site_customization"` - MaxUsersPerTeam *int `access:"site_users_and_teams"` - DEPRECATED_DO_NOT_USE_EnableTeamCreation *bool `json:"EnableTeamCreation" mapstructure:"EnableTeamCreation"` // Deprecated: do not use - EnableUserCreation *bool `access:"authentication_signup"` - EnableOpenServer *bool `access:"authentication_signup"` - EnableUserDeactivation *bool `access:"experimental_features"` - RestrictCreationToDomains *string `access:"authentication_signup"` // telemetry: none - EnableCustomUserStatuses *bool `access:"site_users_and_teams"` - EnableCustomBrand *bool `access:"site_customization"` - CustomBrandText *string `access:"site_customization"` - CustomDescriptionText *string `access:"site_customization"` - RestrictDirectMessage *string `access:"site_users_and_teams"` - DEPRECATED_DO_NOT_USE_RestrictTeamInvite *string `json:"RestrictTeamInvite" mapstructure:"RestrictTeamInvite"` // Deprecated: do not use - DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement *string `json:"RestrictPublicChannelManagement" mapstructure:"RestrictPublicChannelManagement"` // Deprecated: do not use - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement *string `json:"RestrictPrivateChannelManagement" mapstructure:"RestrictPrivateChannelManagement"` // Deprecated: do not use - DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation *string `json:"RestrictPublicChannelCreation" mapstructure:"RestrictPublicChannelCreation"` // Deprecated: do not use - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation *string `json:"RestrictPrivateChannelCreation" mapstructure:"RestrictPrivateChannelCreation"` // Deprecated: do not use - DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion *string `json:"RestrictPublicChannelDeletion" mapstructure:"RestrictPublicChannelDeletion"` // Deprecated: do not use - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion *string `json:"RestrictPrivateChannelDeletion" mapstructure:"RestrictPrivateChannelDeletion"` // Deprecated: do not use - DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers *string `json:"RestrictPrivateChannelManageMembers" mapstructure:"RestrictPrivateChannelManageMembers"` // Deprecated: do not use - EnableXToLeaveChannelsFromLHS *bool `access:"experimental_features"` - UserStatusAwayTimeout *int64 `access:"experimental_features"` - MaxChannelsPerTeam *int64 `access:"site_users_and_teams"` - MaxNotificationsPerChannel *int64 `access:"environment_push_notification_server"` - EnableConfirmNotificationsToChannel *bool `access:"site_notifications"` - TeammateNameDisplay *string `access:"site_users_and_teams"` - ExperimentalViewArchivedChannels *bool `access:"experimental_features,site_users_and_teams"` - ExperimentalEnableAutomaticReplies *bool `access:"experimental_features"` - ExperimentalHideTownSquareinLHS *bool `access:"experimental_features"` - ExperimentalTownSquareIsReadOnly *bool `access:"experimental_features"` - LockTeammateNameDisplay *bool `access:"site_users_and_teams"` - ExperimentalPrimaryTeam *string `access:"experimental_features"` - ExperimentalDefaultChannels []string `access:"experimental_features"` -} - -func (s *TeamSettings) SetDefaults() { - - if s.SiteName == nil || *s.SiteName == "" { - s.SiteName = NewString(TEAM_SETTINGS_DEFAULT_SITE_NAME) - } - - if s.MaxUsersPerTeam == nil { - s.MaxUsersPerTeam = NewInt(TEAM_SETTINGS_DEFAULT_MAX_USERS_PER_TEAM) - } - - if s.DEPRECATED_DO_NOT_USE_EnableTeamCreation == nil { - s.DEPRECATED_DO_NOT_USE_EnableTeamCreation = NewBool(true) - } - - if s.EnableUserCreation == nil { - s.EnableUserCreation = NewBool(true) - } - - if s.EnableOpenServer == nil { - s.EnableOpenServer = NewBool(false) - } - - if s.RestrictCreationToDomains == nil { - s.RestrictCreationToDomains = NewString("") - } - - if s.EnableCustomUserStatuses == nil { - s.EnableCustomUserStatuses = NewBool(true) - } - - if s.EnableCustomBrand == nil { - s.EnableCustomBrand = NewBool(false) - } - - if s.EnableUserDeactivation == nil { - s.EnableUserDeactivation = NewBool(false) - } - - if s.CustomBrandText == nil { - s.CustomBrandText = NewString(TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT) - } - - if s.CustomDescriptionText == nil { - s.CustomDescriptionText = NewString(TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT) - } - - if s.RestrictDirectMessage == nil { - s.RestrictDirectMessage = NewString(DIRECT_MESSAGE_ANY) - } - - if s.DEPRECATED_DO_NOT_USE_RestrictTeamInvite == nil { - s.DEPRECATED_DO_NOT_USE_RestrictTeamInvite = NewString(PERMISSIONS_ALL) - } - - if s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement == nil { - s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement = NewString(PERMISSIONS_ALL) - } - - if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement == nil { - s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement = NewString(PERMISSIONS_ALL) - } - - if s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation == nil { - s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation = new(string) - // If this setting does not exist, assume migration from <3.6, so use management setting as default. - if *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement == PERMISSIONS_CHANNEL_ADMIN { - *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation = PERMISSIONS_TEAM_ADMIN - } else { - *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelCreation = *s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement - } - } - - if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation == nil { - // If this setting does not exist, assume migration from <3.6, so use management setting as default. - if *s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement == PERMISSIONS_CHANNEL_ADMIN { - s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation = NewString(PERMISSIONS_TEAM_ADMIN) - } else { - s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelCreation = NewString(*s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement) - } - } - - if s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion == nil { - // If this setting does not exist, assume migration from <3.6, so use management setting as default. - s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelDeletion = NewString(*s.DEPRECATED_DO_NOT_USE_RestrictPublicChannelManagement) - } - - if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion == nil { - // If this setting does not exist, assume migration from <3.6, so use management setting as default. - s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelDeletion = NewString(*s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManagement) - } - - if s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers == nil { - s.DEPRECATED_DO_NOT_USE_RestrictPrivateChannelManageMembers = NewString(PERMISSIONS_ALL) - } - - if s.EnableXToLeaveChannelsFromLHS == nil { - s.EnableXToLeaveChannelsFromLHS = NewBool(false) - } - - if s.UserStatusAwayTimeout == nil { - s.UserStatusAwayTimeout = NewInt64(TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT) - } - - if s.MaxChannelsPerTeam == nil { - s.MaxChannelsPerTeam = NewInt64(2000) - } - - if s.MaxNotificationsPerChannel == nil { - s.MaxNotificationsPerChannel = NewInt64(1000) - } - - if s.EnableConfirmNotificationsToChannel == nil { - s.EnableConfirmNotificationsToChannel = NewBool(true) - } - - if s.ExperimentalEnableAutomaticReplies == nil { - s.ExperimentalEnableAutomaticReplies = NewBool(false) - } - - if s.ExperimentalHideTownSquareinLHS == nil { - s.ExperimentalHideTownSquareinLHS = NewBool(false) - } - - if s.ExperimentalTownSquareIsReadOnly == nil { - s.ExperimentalTownSquareIsReadOnly = NewBool(false) - } - - if s.ExperimentalPrimaryTeam == nil { - s.ExperimentalPrimaryTeam = NewString("") - } - - if s.ExperimentalDefaultChannels == nil { - s.ExperimentalDefaultChannels = []string{} - } - - if s.DEPRECATED_DO_NOT_USE_EnableTeamCreation == nil { - s.DEPRECATED_DO_NOT_USE_EnableTeamCreation = NewBool(true) - } - - if s.EnableUserCreation == nil { - s.EnableUserCreation = NewBool(true) - } - - if s.ExperimentalViewArchivedChannels == nil { - s.ExperimentalViewArchivedChannels = NewBool(true) - } - - if s.LockTeammateNameDisplay == nil { - s.LockTeammateNameDisplay = NewBool(false) - } -} - -type ClientRequirements struct { - AndroidLatestVersion string `access:"write_restrictable,cloud_restrictable"` - AndroidMinVersion string `access:"write_restrictable,cloud_restrictable"` - DesktopLatestVersion string `access:"write_restrictable,cloud_restrictable"` - DesktopMinVersion string `access:"write_restrictable,cloud_restrictable"` - IosLatestVersion string `access:"write_restrictable,cloud_restrictable"` - IosMinVersion string `access:"write_restrictable,cloud_restrictable"` -} - -type LdapSettings struct { - // Basic - Enable *bool `access:"authentication_ldap"` - EnableSync *bool `access:"authentication_ldap"` - LdapServer *string `access:"authentication_ldap"` // telemetry: none - LdapPort *int `access:"authentication_ldap"` // telemetry: none - ConnectionSecurity *string `access:"authentication_ldap"` - BaseDN *string `access:"authentication_ldap"` // telemetry: none - BindUsername *string `access:"authentication_ldap"` // telemetry: none - BindPassword *string `access:"authentication_ldap"` // telemetry: none - - // Filtering - UserFilter *string `access:"authentication_ldap"` // telemetry: none - GroupFilter *string `access:"authentication_ldap"` - GuestFilter *string `access:"authentication_ldap"` - EnableAdminFilter *bool - AdminFilter *string - - // Group Mapping - GroupDisplayNameAttribute *string `access:"authentication_ldap"` - GroupIdAttribute *string `access:"authentication_ldap"` - - // User Mapping - FirstNameAttribute *string `access:"authentication_ldap"` - LastNameAttribute *string `access:"authentication_ldap"` - EmailAttribute *string `access:"authentication_ldap"` - UsernameAttribute *string `access:"authentication_ldap"` - NicknameAttribute *string `access:"authentication_ldap"` - IdAttribute *string `access:"authentication_ldap"` - PositionAttribute *string `access:"authentication_ldap"` - LoginIdAttribute *string `access:"authentication_ldap"` - PictureAttribute *string `access:"authentication_ldap"` - - // Synchronization - SyncIntervalMinutes *int `access:"authentication_ldap"` - - // Advanced - SkipCertificateVerification *bool `access:"authentication_ldap"` - PublicCertificateFile *string `access:"authentication_ldap"` - PrivateKeyFile *string `access:"authentication_ldap"` - QueryTimeout *int `access:"authentication_ldap"` - MaxPageSize *int `access:"authentication_ldap"` - - // Customization - LoginFieldName *string `access:"authentication_ldap"` - - LoginButtonColor *string `access:"experimental_features"` - LoginButtonBorderColor *string `access:"experimental_features"` - LoginButtonTextColor *string `access:"experimental_features"` - - Trace *bool `access:"authentication_ldap"` // telemetry: none -} - -func (s *LdapSettings) SetDefaults() { - if s.Enable == nil { - s.Enable = NewBool(false) - } - - // When unset should default to LDAP Enabled - if s.EnableSync == nil { - s.EnableSync = NewBool(*s.Enable) - } - - if s.EnableAdminFilter == nil { - s.EnableAdminFilter = NewBool(false) - } - - if s.LdapServer == nil { - s.LdapServer = NewString("") - } - - if s.LdapPort == nil { - s.LdapPort = NewInt(389) - } - - if s.ConnectionSecurity == nil { - s.ConnectionSecurity = NewString("") - } - - if s.PublicCertificateFile == nil { - s.PublicCertificateFile = NewString("") - } - - if s.PrivateKeyFile == nil { - s.PrivateKeyFile = NewString("") - } - - if s.BaseDN == nil { - s.BaseDN = NewString("") - } - - if s.BindUsername == nil { - s.BindUsername = NewString("") - } - - if s.BindPassword == nil { - s.BindPassword = NewString("") - } - - if s.UserFilter == nil { - s.UserFilter = NewString("") - } - - if s.GuestFilter == nil { - s.GuestFilter = NewString("") - } - - if s.AdminFilter == nil { - s.AdminFilter = NewString("") - } - - if s.GroupFilter == nil { - s.GroupFilter = NewString("") - } - - if s.GroupDisplayNameAttribute == nil { - s.GroupDisplayNameAttribute = NewString(LDAP_SETTINGS_DEFAULT_GROUP_DISPLAY_NAME_ATTRIBUTE) - } - - if s.GroupIdAttribute == nil { - s.GroupIdAttribute = NewString(LDAP_SETTINGS_DEFAULT_GROUP_ID_ATTRIBUTE) - } - - if s.FirstNameAttribute == nil { - s.FirstNameAttribute = NewString(LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE) - } - - if s.LastNameAttribute == nil { - s.LastNameAttribute = NewString(LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE) - } - - if s.EmailAttribute == nil { - s.EmailAttribute = NewString(LDAP_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE) - } - - if s.UsernameAttribute == nil { - s.UsernameAttribute = NewString(LDAP_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE) - } - - if s.NicknameAttribute == nil { - s.NicknameAttribute = NewString(LDAP_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE) - } - - if s.IdAttribute == nil { - s.IdAttribute = NewString(LDAP_SETTINGS_DEFAULT_ID_ATTRIBUTE) - } - - if s.PositionAttribute == nil { - s.PositionAttribute = NewString(LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE) - } - - if s.PictureAttribute == nil { - s.PictureAttribute = NewString(LDAP_SETTINGS_DEFAULT_PICTURE_ATTRIBUTE) - } - - // For those upgrading to the version when LoginIdAttribute was added - // they need IdAttribute == LoginIdAttribute not to break - if s.LoginIdAttribute == nil { - s.LoginIdAttribute = s.IdAttribute - } - - if s.SyncIntervalMinutes == nil { - s.SyncIntervalMinutes = NewInt(60) - } - - if s.SkipCertificateVerification == nil { - s.SkipCertificateVerification = NewBool(false) - } - - if s.QueryTimeout == nil { - s.QueryTimeout = NewInt(60) - } - - if s.MaxPageSize == nil { - s.MaxPageSize = NewInt(0) - } - - if s.LoginFieldName == nil { - s.LoginFieldName = NewString(LDAP_SETTINGS_DEFAULT_LOGIN_FIELD_NAME) - } - - if s.LoginButtonColor == nil { - s.LoginButtonColor = NewString("#0000") - } - - if s.LoginButtonBorderColor == nil { - s.LoginButtonBorderColor = NewString("#2389D7") - } - - if s.LoginButtonTextColor == nil { - s.LoginButtonTextColor = NewString("#2389D7") - } - - if s.Trace == nil { - s.Trace = NewBool(false) - } -} - -type ComplianceSettings struct { - Enable *bool `access:"compliance_compliance_monitoring"` - Directory *string `access:"compliance_compliance_monitoring"` // telemetry: none - EnableDaily *bool `access:"compliance_compliance_monitoring"` - BatchSize *int `access:"compliance_compliance_monitoring"` // telemetry: none -} - -func (s *ComplianceSettings) SetDefaults() { - if s.Enable == nil { - s.Enable = NewBool(false) - } - - if s.Directory == nil { - s.Directory = NewString("./data/") - } - - if s.EnableDaily == nil { - s.EnableDaily = NewBool(false) - } - - if s.BatchSize == nil { - s.BatchSize = NewInt(30000) - } -} - -type LocalizationSettings struct { - DefaultServerLocale *string `access:"site_localization"` - DefaultClientLocale *string `access:"site_localization"` - AvailableLocales *string `access:"site_localization"` -} - -func (s *LocalizationSettings) SetDefaults() { - if s.DefaultServerLocale == nil { - s.DefaultServerLocale = NewString(DEFAULT_LOCALE) - } - - if s.DefaultClientLocale == nil { - s.DefaultClientLocale = NewString(DEFAULT_LOCALE) - } - - if s.AvailableLocales == nil { - s.AvailableLocales = NewString("") - } -} - -type SamlSettings struct { - // Basic - Enable *bool `access:"authentication_saml"` - EnableSyncWithLdap *bool `access:"authentication_saml"` - EnableSyncWithLdapIncludeAuth *bool `access:"authentication_saml"` - IgnoreGuestsLdapSync *bool `access:"authentication_saml"` - - Verify *bool `access:"authentication_saml"` - Encrypt *bool `access:"authentication_saml"` - SignRequest *bool `access:"authentication_saml"` - - IdpUrl *string `access:"authentication_saml"` // telemetry: none - IdpDescriptorUrl *string `access:"authentication_saml"` // telemetry: none - IdpMetadataUrl *string `access:"authentication_saml"` // telemetry: none - ServiceProviderIdentifier *string `access:"authentication_saml"` // telemetry: none - AssertionConsumerServiceURL *string `access:"authentication_saml"` // telemetry: none - - SignatureAlgorithm *string `access:"authentication_saml"` - CanonicalAlgorithm *string `access:"authentication_saml"` - - ScopingIDPProviderId *string `access:"authentication_saml"` - ScopingIDPName *string `access:"authentication_saml"` - - IdpCertificateFile *string `access:"authentication_saml"` // telemetry: none - PublicCertificateFile *string `access:"authentication_saml"` // telemetry: none - PrivateKeyFile *string `access:"authentication_saml"` // telemetry: none - - // User Mapping - IdAttribute *string `access:"authentication_saml"` - GuestAttribute *string `access:"authentication_saml"` - EnableAdminAttribute *bool - AdminAttribute *string - FirstNameAttribute *string `access:"authentication_saml"` - LastNameAttribute *string `access:"authentication_saml"` - EmailAttribute *string `access:"authentication_saml"` - UsernameAttribute *string `access:"authentication_saml"` - NicknameAttribute *string `access:"authentication_saml"` - LocaleAttribute *string `access:"authentication_saml"` - PositionAttribute *string `access:"authentication_saml"` - - LoginButtonText *string `access:"authentication_saml"` - - LoginButtonColor *string `access:"experimental_features"` - LoginButtonBorderColor *string `access:"experimental_features"` - LoginButtonTextColor *string `access:"experimental_features"` -} - -func (s *SamlSettings) SetDefaults() { - if s.Enable == nil { - s.Enable = NewBool(false) - } - - if s.EnableSyncWithLdap == nil { - s.EnableSyncWithLdap = NewBool(false) - } - - if s.EnableSyncWithLdapIncludeAuth == nil { - s.EnableSyncWithLdapIncludeAuth = NewBool(false) - } - - if s.IgnoreGuestsLdapSync == nil { - s.IgnoreGuestsLdapSync = NewBool(false) - } - - if s.EnableAdminAttribute == nil { - s.EnableAdminAttribute = NewBool(false) - } - - if s.Verify == nil { - s.Verify = NewBool(true) - } - - if s.Encrypt == nil { - s.Encrypt = NewBool(true) - } - - if s.SignRequest == nil { - s.SignRequest = NewBool(false) - } - - if s.SignatureAlgorithm == nil { - s.SignatureAlgorithm = NewString(SAML_SETTINGS_DEFAULT_SIGNATURE_ALGORITHM) - } - - if s.CanonicalAlgorithm == nil { - s.CanonicalAlgorithm = NewString(SAML_SETTINGS_DEFAULT_CANONICAL_ALGORITHM) - } - - if s.IdpUrl == nil { - s.IdpUrl = NewString("") - } - - if s.IdpDescriptorUrl == nil { - s.IdpDescriptorUrl = NewString("") - } - - if s.ServiceProviderIdentifier == nil { - if s.IdpDescriptorUrl != nil { - s.ServiceProviderIdentifier = NewString(*s.IdpDescriptorUrl) - } else { - s.ServiceProviderIdentifier = NewString("") - } - } - - if s.IdpMetadataUrl == nil { - s.IdpMetadataUrl = NewString("") - } - - if s.IdpCertificateFile == nil { - s.IdpCertificateFile = NewString("") - } - - if s.PublicCertificateFile == nil { - s.PublicCertificateFile = NewString("") - } - - if s.PrivateKeyFile == nil { - s.PrivateKeyFile = NewString("") - } - - if s.AssertionConsumerServiceURL == nil { - s.AssertionConsumerServiceURL = NewString("") - } - - if s.ScopingIDPProviderId == nil { - s.ScopingIDPProviderId = NewString("") - } - - if s.ScopingIDPName == nil { - s.ScopingIDPName = NewString("") - } - - if s.LoginButtonText == nil || *s.LoginButtonText == "" { - s.LoginButtonText = NewString(USER_AUTH_SERVICE_SAML_TEXT) - } - - if s.IdAttribute == nil { - s.IdAttribute = NewString(SAML_SETTINGS_DEFAULT_ID_ATTRIBUTE) - } - - if s.GuestAttribute == nil { - s.GuestAttribute = NewString(SAML_SETTINGS_DEFAULT_GUEST_ATTRIBUTE) - } - if s.AdminAttribute == nil { - s.AdminAttribute = NewString(SAML_SETTINGS_DEFAULT_ADMIN_ATTRIBUTE) - } - if s.FirstNameAttribute == nil { - s.FirstNameAttribute = NewString(SAML_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE) - } - - if s.LastNameAttribute == nil { - s.LastNameAttribute = NewString(SAML_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE) - } - - if s.EmailAttribute == nil { - s.EmailAttribute = NewString(SAML_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE) - } - - if s.UsernameAttribute == nil { - s.UsernameAttribute = NewString(SAML_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE) - } - - if s.NicknameAttribute == nil { - s.NicknameAttribute = NewString(SAML_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE) - } - - if s.PositionAttribute == nil { - s.PositionAttribute = NewString(SAML_SETTINGS_DEFAULT_POSITION_ATTRIBUTE) - } - - if s.LocaleAttribute == nil { - s.LocaleAttribute = NewString(SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE) - } - - if s.LoginButtonColor == nil { - s.LoginButtonColor = NewString("#34a28b") - } - - if s.LoginButtonBorderColor == nil { - s.LoginButtonBorderColor = NewString("#2389D7") - } - - if s.LoginButtonTextColor == nil { - s.LoginButtonTextColor = NewString("#ffffff") - } -} - -type NativeAppSettings struct { - AppCustomURLSchemes []string `access:"site_customization,write_restrictable,cloud_restrictable"` // telemetry: none - AppDownloadLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` - AndroidAppDownloadLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` - IosAppDownloadLink *string `access:"site_customization,write_restrictable,cloud_restrictable"` -} - -func (s *NativeAppSettings) SetDefaults() { - if s.AppDownloadLink == nil { - s.AppDownloadLink = NewString(NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK) - } - - if s.AndroidAppDownloadLink == nil { - s.AndroidAppDownloadLink = NewString(NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK) - } - - if s.IosAppDownloadLink == nil { - s.IosAppDownloadLink = NewString(NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK) - } - - if s.AppCustomURLSchemes == nil { - s.AppCustomURLSchemes = GetDefaultAppCustomURLSchemes() - } -} - -type ElasticsearchSettings struct { - ConnectionUrl *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - Username *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - Password *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - EnableIndexing *bool `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - EnableSearching *bool `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - EnableAutocomplete *bool `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - Sniff *bool `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - PostIndexReplicas *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - PostIndexShards *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - ChannelIndexReplicas *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - ChannelIndexShards *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - UserIndexReplicas *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - UserIndexShards *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - AggregatePostsAfterDays *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` // telemetry: none - PostsAggregatorJobStartTime *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` // telemetry: none - IndexPrefix *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - LiveIndexingBatchSize *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - BulkIndexingTimeWindowSeconds *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - RequestTimeoutSeconds *int `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - SkipTLSVerification *bool `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` - Trace *string `access:"environment_elasticsearch,write_restrictable,cloud_restrictable"` -} - -func (s *ElasticsearchSettings) SetDefaults() { - if s.ConnectionUrl == nil { - s.ConnectionUrl = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_CONNECTION_URL) - } - - if s.Username == nil { - s.Username = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_USERNAME) - } - - if s.Password == nil { - s.Password = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD) - } - - if s.EnableIndexing == nil { - s.EnableIndexing = NewBool(false) - } - - if s.EnableSearching == nil { - s.EnableSearching = NewBool(false) - } - - if s.EnableAutocomplete == nil { - s.EnableAutocomplete = NewBool(false) - } - - if s.Sniff == nil { - s.Sniff = NewBool(true) - } - - if s.PostIndexReplicas == nil { - s.PostIndexReplicas = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_REPLICAS) - } - - if s.PostIndexShards == nil { - s.PostIndexShards = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_POST_INDEX_SHARDS) - } - - if s.ChannelIndexReplicas == nil { - s.ChannelIndexReplicas = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_CHANNEL_INDEX_REPLICAS) - } - - if s.ChannelIndexShards == nil { - s.ChannelIndexShards = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_CHANNEL_INDEX_SHARDS) - } - - if s.UserIndexReplicas == nil { - s.UserIndexReplicas = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_USER_INDEX_REPLICAS) - } - - if s.UserIndexShards == nil { - s.UserIndexShards = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_USER_INDEX_SHARDS) - } - - if s.AggregatePostsAfterDays == nil { - s.AggregatePostsAfterDays = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_AGGREGATE_POSTS_AFTER_DAYS) - } - - if s.PostsAggregatorJobStartTime == nil { - s.PostsAggregatorJobStartTime = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_POSTS_AGGREGATOR_JOB_START_TIME) - } - - if s.IndexPrefix == nil { - s.IndexPrefix = NewString(ELASTICSEARCH_SETTINGS_DEFAULT_INDEX_PREFIX) - } - - if s.LiveIndexingBatchSize == nil { - s.LiveIndexingBatchSize = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_LIVE_INDEXING_BATCH_SIZE) - } - - if s.BulkIndexingTimeWindowSeconds == nil { - s.BulkIndexingTimeWindowSeconds = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS) - } - - if s.RequestTimeoutSeconds == nil { - s.RequestTimeoutSeconds = NewInt(ELASTICSEARCH_SETTINGS_DEFAULT_REQUEST_TIMEOUT_SECONDS) - } - - if s.SkipTLSVerification == nil { - s.SkipTLSVerification = NewBool(false) - } - - if s.Trace == nil { - s.Trace = NewString("") - } -} - -type BleveSettings struct { - IndexDir *string `access:"experimental_bleve"` // telemetry: none - EnableIndexing *bool `access:"experimental_bleve"` - EnableSearching *bool `access:"experimental_bleve"` - EnableAutocomplete *bool `access:"experimental_bleve"` - BulkIndexingTimeWindowSeconds *int `access:"experimental_bleve"` -} - -func (bs *BleveSettings) SetDefaults() { - if bs.IndexDir == nil { - bs.IndexDir = NewString(BLEVE_SETTINGS_DEFAULT_INDEX_DIR) - } - - if bs.EnableIndexing == nil { - bs.EnableIndexing = NewBool(false) - } - - if bs.EnableSearching == nil { - bs.EnableSearching = NewBool(false) - } - - if bs.EnableAutocomplete == nil { - bs.EnableAutocomplete = NewBool(false) - } - - if bs.BulkIndexingTimeWindowSeconds == nil { - bs.BulkIndexingTimeWindowSeconds = NewInt(BLEVE_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS) - } -} - -type DataRetentionSettings struct { - EnableMessageDeletion *bool `access:"compliance_data_retention_policy"` - EnableFileDeletion *bool `access:"compliance_data_retention_policy"` - MessageRetentionDays *int `access:"compliance_data_retention_policy"` - FileRetentionDays *int `access:"compliance_data_retention_policy"` - DeletionJobStartTime *string `access:"compliance_data_retention_policy"` - BatchSize *int `access:"compliance_data_retention_policy"` -} - -func (s *DataRetentionSettings) SetDefaults() { - if s.EnableMessageDeletion == nil { - s.EnableMessageDeletion = NewBool(false) - } - - if s.EnableFileDeletion == nil { - s.EnableFileDeletion = NewBool(false) - } - - if s.MessageRetentionDays == nil { - s.MessageRetentionDays = NewInt(DATA_RETENTION_SETTINGS_DEFAULT_MESSAGE_RETENTION_DAYS) - } - - if s.FileRetentionDays == nil { - s.FileRetentionDays = NewInt(DATA_RETENTION_SETTINGS_DEFAULT_FILE_RETENTION_DAYS) - } - - if s.DeletionJobStartTime == nil { - s.DeletionJobStartTime = NewString(DATA_RETENTION_SETTINGS_DEFAULT_DELETION_JOB_START_TIME) - } - - if s.BatchSize == nil { - s.BatchSize = NewInt(DATA_RETENTION_SETTINGS_DEFAULT_BATCH_SIZE) - } -} - -type JobSettings struct { - RunJobs *bool `access:"write_restrictable,cloud_restrictable"` - RunScheduler *bool `access:"write_restrictable,cloud_restrictable"` -} - -func (s *JobSettings) SetDefaults() { - if s.RunJobs == nil { - s.RunJobs = NewBool(true) - } - - if s.RunScheduler == nil { - s.RunScheduler = NewBool(true) - } -} - -type CloudSettings struct { - CWSUrl *string `access:"write_restrictable"` - CWSAPIUrl *string `access:"write_restrictable"` -} - -func (s *CloudSettings) SetDefaults() { - if s.CWSUrl == nil { - s.CWSUrl = NewString(CLOUD_SETTINGS_DEFAULT_CWS_URL) - } - if s.CWSAPIUrl == nil { - s.CWSAPIUrl = NewString(CLOUD_SETTINGS_DEFAULT_CWS_API_URL) - } -} - -type PluginState struct { - Enable bool -} - -type PluginSettings struct { - Enable *bool `access:"plugins,write_restrictable"` - EnableUploads *bool `access:"plugins,write_restrictable,cloud_restrictable"` - AllowInsecureDownloadUrl *bool `access:"plugins,write_restrictable,cloud_restrictable"` - EnableHealthCheck *bool `access:"plugins,write_restrictable,cloud_restrictable"` - Directory *string `access:"plugins,write_restrictable,cloud_restrictable"` // telemetry: none - ClientDirectory *string `access:"plugins,write_restrictable,cloud_restrictable"` // telemetry: none - Plugins map[string]map[string]interface{} `access:"plugins"` // telemetry: none - PluginStates map[string]*PluginState `access:"plugins"` // telemetry: none - EnableMarketplace *bool `access:"plugins,write_restrictable,cloud_restrictable"` - EnableRemoteMarketplace *bool `access:"plugins,write_restrictable,cloud_restrictable"` - AutomaticPrepackagedPlugins *bool `access:"plugins,write_restrictable,cloud_restrictable"` - RequirePluginSignature *bool `access:"plugins,write_restrictable,cloud_restrictable"` - MarketplaceUrl *string `access:"plugins,write_restrictable,cloud_restrictable"` - SignaturePublicKeyFiles []string `access:"plugins,write_restrictable,cloud_restrictable"` - ChimeraOAuthProxyUrl *string `access:"plugins,write_restrictable,cloud_restrictable"` -} - -func (s *PluginSettings) SetDefaults(ls LogSettings) { - if s.Enable == nil { - s.Enable = NewBool(true) - } - - if s.EnableUploads == nil { - s.EnableUploads = NewBool(false) - } - - if s.AllowInsecureDownloadUrl == nil { - s.AllowInsecureDownloadUrl = NewBool(false) - } - - if s.EnableHealthCheck == nil { - s.EnableHealthCheck = NewBool(true) - } - - if s.Directory == nil || *s.Directory == "" { - s.Directory = NewString(PLUGIN_SETTINGS_DEFAULT_DIRECTORY) - } - - if s.ClientDirectory == nil || *s.ClientDirectory == "" { - s.ClientDirectory = NewString(PLUGIN_SETTINGS_DEFAULT_CLIENT_DIRECTORY) - } - - if s.Plugins == nil { - s.Plugins = make(map[string]map[string]interface{}) - } - - if s.PluginStates == nil { - s.PluginStates = make(map[string]*PluginState) - } - - if s.PluginStates["com.mattermost.nps"] == nil { - // Enable the NPS plugin by default if diagnostics are enabled - s.PluginStates["com.mattermost.nps"] = &PluginState{Enable: ls.EnableDiagnostics == nil || *ls.EnableDiagnostics} - } - - if s.PluginStates["com.mattermost.plugin-incident-management"] == nil && BuildEnterpriseReady == "true" { - // Enable the incident management plugin by default - s.PluginStates["com.mattermost.plugin-incident-management"] = &PluginState{Enable: true} - } - - if s.PluginStates["com.mattermost.plugin-channel-export"] == nil && BuildEnterpriseReady == "true" { - // Enable the channel export plugin by default - s.PluginStates["com.mattermost.plugin-channel-export"] = &PluginState{Enable: true} - } - - if s.EnableMarketplace == nil { - s.EnableMarketplace = NewBool(PLUGIN_SETTINGS_DEFAULT_ENABLE_MARKETPLACE) - } - - if s.EnableRemoteMarketplace == nil { - s.EnableRemoteMarketplace = NewBool(true) - } - - if s.AutomaticPrepackagedPlugins == nil { - s.AutomaticPrepackagedPlugins = NewBool(true) - } - - if s.MarketplaceUrl == nil || *s.MarketplaceUrl == "" || *s.MarketplaceUrl == PLUGIN_SETTINGS_OLD_MARKETPLACE_URL { - s.MarketplaceUrl = NewString(PLUGIN_SETTINGS_DEFAULT_MARKETPLACE_URL) - } - - if s.RequirePluginSignature == nil { - s.RequirePluginSignature = NewBool(false) - } - - if s.SignaturePublicKeyFiles == nil { - s.SignaturePublicKeyFiles = []string{} - } - - if s.ChimeraOAuthProxyUrl == nil { - s.ChimeraOAuthProxyUrl = NewString("") - } -} - -type GlobalRelayMessageExportSettings struct { - CustomerType *string `access:"compliance_compliance_export"` // must be either A9 or A10, dictates SMTP server url - SmtpUsername *string `access:"compliance_compliance_export"` - SmtpPassword *string `access:"compliance_compliance_export"` - EmailAddress *string `access:"compliance_compliance_export"` // the address to send messages to - SMTPServerTimeout *int `access:"compliance_compliance_export"` -} - -func (s *GlobalRelayMessageExportSettings) SetDefaults() { - if s.CustomerType == nil { - s.CustomerType = NewString(GLOBALRELAY_CUSTOMER_TYPE_A9) - } - if s.SmtpUsername == nil { - s.SmtpUsername = NewString("") - } - if s.SmtpPassword == nil { - s.SmtpPassword = NewString("") - } - if s.EmailAddress == nil { - s.EmailAddress = NewString("") - } - if s.SMTPServerTimeout == nil || *s.SMTPServerTimeout == 0 { - s.SMTPServerTimeout = NewInt(1800) - } -} - -type MessageExportSettings struct { - EnableExport *bool `access:"compliance_compliance_export"` - ExportFormat *string `access:"compliance_compliance_export"` - DailyRunTime *string `access:"compliance_compliance_export"` - ExportFromTimestamp *int64 `access:"compliance_compliance_export"` - BatchSize *int `access:"compliance_compliance_export"` - DownloadExportResults *bool `access:"compliance_compliance_export"` - - // formatter-specific settings - these are only expected to be non-nil if ExportFormat is set to the associated format - GlobalRelaySettings *GlobalRelayMessageExportSettings `access:"compliance_compliance_export"` -} - -func (s *MessageExportSettings) SetDefaults() { - if s.EnableExport == nil { - s.EnableExport = NewBool(false) - } - - if s.DownloadExportResults == nil { - s.DownloadExportResults = NewBool(false) - } - - if s.ExportFormat == nil { - s.ExportFormat = NewString(COMPLIANCE_EXPORT_TYPE_ACTIANCE) - } - - if s.DailyRunTime == nil { - s.DailyRunTime = NewString("01:00") - } - - if s.ExportFromTimestamp == nil { - s.ExportFromTimestamp = NewInt64(0) - } - - if s.BatchSize == nil { - s.BatchSize = NewInt(10000) - } - - if s.GlobalRelaySettings == nil { - s.GlobalRelaySettings = &GlobalRelayMessageExportSettings{} - } - s.GlobalRelaySettings.SetDefaults() -} - -type DisplaySettings struct { - CustomUrlSchemes []string `access:"site_customization"` - ExperimentalTimezone *bool `access:"experimental_features"` -} - -func (s *DisplaySettings) SetDefaults() { - if s.CustomUrlSchemes == nil { - customUrlSchemes := []string{} - s.CustomUrlSchemes = customUrlSchemes - } - - if s.ExperimentalTimezone == nil { - s.ExperimentalTimezone = NewBool(true) - } -} - -type GuestAccountsSettings struct { - Enable *bool `access:"authentication_guest_access"` - AllowEmailAccounts *bool `access:"authentication_guest_access"` - EnforceMultifactorAuthentication *bool `access:"authentication_guest_access"` - RestrictCreationToDomains *string `access:"authentication_guest_access"` -} - -func (s *GuestAccountsSettings) SetDefaults() { - if s.Enable == nil { - s.Enable = NewBool(false) - } - - if s.AllowEmailAccounts == nil { - s.AllowEmailAccounts = NewBool(true) - } - - if s.EnforceMultifactorAuthentication == nil { - s.EnforceMultifactorAuthentication = NewBool(false) - } - - if s.RestrictCreationToDomains == nil { - s.RestrictCreationToDomains = NewString("") - } -} - -type ImageProxySettings struct { - Enable *bool `access:"environment_image_proxy"` - ImageProxyType *string `access:"environment_image_proxy"` - RemoteImageProxyURL *string `access:"environment_image_proxy"` - RemoteImageProxyOptions *string `access:"environment_image_proxy"` -} - -func (s *ImageProxySettings) SetDefaults(ss ServiceSettings) { - if s.Enable == nil { - if ss.DEPRECATED_DO_NOT_USE_ImageProxyType == nil || *ss.DEPRECATED_DO_NOT_USE_ImageProxyType == "" { - s.Enable = NewBool(false) - } else { - s.Enable = NewBool(true) - } - } - - if s.ImageProxyType == nil { - if ss.DEPRECATED_DO_NOT_USE_ImageProxyType == nil || *ss.DEPRECATED_DO_NOT_USE_ImageProxyType == "" { - s.ImageProxyType = NewString(IMAGE_PROXY_TYPE_LOCAL) - } else { - s.ImageProxyType = ss.DEPRECATED_DO_NOT_USE_ImageProxyType - } - } - - if s.RemoteImageProxyURL == nil { - if ss.DEPRECATED_DO_NOT_USE_ImageProxyURL == nil { - s.RemoteImageProxyURL = NewString("") - } else { - s.RemoteImageProxyURL = ss.DEPRECATED_DO_NOT_USE_ImageProxyURL - } - } - - if s.RemoteImageProxyOptions == nil { - if ss.DEPRECATED_DO_NOT_USE_ImageProxyOptions == nil { - s.RemoteImageProxyOptions = NewString("") - } else { - s.RemoteImageProxyOptions = ss.DEPRECATED_DO_NOT_USE_ImageProxyOptions - } - } -} - -// ImportSettings defines configuration settings for file imports. -type ImportSettings struct { - // The directory where to store the imported files. - Directory *string - // The number of days to retain the imported files before deleting them. - RetentionDays *int -} - -func (s *ImportSettings) isValid() *AppError { - if *s.Directory == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.import.directory.app_error", nil, "", http.StatusBadRequest) - } - - if *s.RetentionDays <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.import.retention_days_too_low.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -// SetDefaults applies the default settings to the struct. -func (s *ImportSettings) SetDefaults() { - if s.Directory == nil || *s.Directory == "" { - s.Directory = NewString(IMPORT_SETTINGS_DEFAULT_DIRECTORY) - } - - if s.RetentionDays == nil { - s.RetentionDays = NewInt(IMPORT_SETTINGS_DEFAULT_RETENTION_DAYS) - } -} - -// ExportSettings defines configuration settings for file exports. -type ExportSettings struct { - // The directory where to store the exported files. - Directory *string // telemetry: none - // The number of days to retain the exported files before deleting them. - RetentionDays *int -} - -func (s *ExportSettings) isValid() *AppError { - if *s.Directory == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.export.directory.app_error", nil, "", http.StatusBadRequest) - } - - if *s.RetentionDays <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.export.retention_days_too_low.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -// SetDefaults applies the default settings to the struct. -func (s *ExportSettings) SetDefaults() { - if s.Directory == nil || *s.Directory == "" { - s.Directory = NewString(EXPORT_SETTINGS_DEFAULT_DIRECTORY) - } - - if s.RetentionDays == nil { - s.RetentionDays = NewInt(EXPORT_SETTINGS_DEFAULT_RETENTION_DAYS) - } -} - -type ConfigFunc func() *Config - -const ConfigAccessTagType = "access" -const ConfigAccessTagWriteRestrictable = "write_restrictable" -const ConfigAccessTagCloudRestrictable = "cloud_restrictable" - -// Allows read access if any PERMISSION_SYSCONSOLE_READ_* is allowed -const ConfigAccessTagAnySysConsoleRead = "*_read" - -// Config fields support the 'access' tag with the following values corresponding to the suffix of the associated -// PERMISSION_SYSCONSOLE_*_* permission Id: 'about', 'reporting', 'user_management_users', -// 'user_management_groups', 'user_management_teams', 'user_management_channels', -// 'user_management_permissions', 'environment_web_server', 'environment_database', 'environment_elasticsearch', -// 'environment_file_storage', 'environment_image_proxy', 'environment_smtp', 'environment_push_notification_server', -// 'environment_high_availability', 'environment_rate_limiting', 'environment_logging', 'environment_session_lengths', -// 'environment_performance_monitoring', 'environment_developer', 'site', 'authentication', 'plugins', -// 'integrations', 'compliance', 'plugins', and 'experimental'. They grant read and/or write access to the config field -// to roles without PERMISSION_MANAGE_SYSTEM. -// -// The 'access' tag '*_read' checks for any SYSCONSOLE read permission and grants access if any read permission is allowed. -// -// By default config values can be written with PERMISSION_MANAGE_SYSTEM, but if ExperimentalSettings.RestrictSystemAdmin is true -// and the access tag contains the value 'write_restrictable', then even PERMISSION_MANAGE_SYSTEM does not grant write access. -// -// PERMISSION_MANAGE_SYSTEM always grants read access. -// -// Config values with the access tag 'cloud_restrictable' mean that are marked to be filtered when it's used in a cloud licensed -// environment with ExperimentalSettings.RestrictedSystemAdmin set to true. -// -// Example: -// type HairSettings struct { -// // Colour is writeable with either PERMISSION_SYSCONSOLE_WRITE_REPORTING or PERMISSION_SYSCONSOLE_WRITE_USER_MANAGEMENT_GROUPS. -// // It is readable by PERMISSION_SYSCONSOLE_READ_REPORTING and PERMISSION_SYSCONSOLE_READ_USER_MANAGEMENT_GROUPS permissions. -// // PERMISSION_MANAGE_SYSTEM grants read and write access. -// Colour string `access:"reporting,user_management_groups"` -// -// -// // Length is only readable and writable via PERMISSION_MANAGE_SYSTEM. -// Length string -// -// // Product is only writeable by PERMISSION_MANAGE_SYSTEM if ExperimentalSettings.RestrictSystemAdmin is false. -// // PERMISSION_MANAGE_SYSTEM can always read the value. -// Product bool `access:write_restrictable` -// } -type Config struct { - ServiceSettings ServiceSettings - TeamSettings TeamSettings - ClientRequirements ClientRequirements - SqlSettings SqlSettings - LogSettings LogSettings - ExperimentalAuditSettings ExperimentalAuditSettings - NotificationLogSettings NotificationLogSettings - PasswordSettings PasswordSettings - FileSettings FileSettings - EmailSettings EmailSettings - RateLimitSettings RateLimitSettings - PrivacySettings PrivacySettings - SupportSettings SupportSettings - AnnouncementSettings AnnouncementSettings - ThemeSettings ThemeSettings - GitLabSettings SSOSettings - GoogleSettings SSOSettings - Office365Settings Office365Settings - OpenIdSettings SSOSettings - LdapSettings LdapSettings - ComplianceSettings ComplianceSettings - LocalizationSettings LocalizationSettings - SamlSettings SamlSettings - NativeAppSettings NativeAppSettings - ClusterSettings ClusterSettings - MetricsSettings MetricsSettings - ExperimentalSettings ExperimentalSettings - AnalyticsSettings AnalyticsSettings - ElasticsearchSettings ElasticsearchSettings - BleveSettings BleveSettings - DataRetentionSettings DataRetentionSettings - MessageExportSettings MessageExportSettings - JobSettings JobSettings // telemetry: none - PluginSettings PluginSettings - DisplaySettings DisplaySettings - GuestAccountsSettings GuestAccountsSettings - ImageProxySettings ImageProxySettings - CloudSettings CloudSettings // telemetry: none - FeatureFlags *FeatureFlags `access:"*_read" json:",omitempty"` - ImportSettings ImportSettings // telemetry: none - ExportSettings ExportSettings -} - -func (o *Config) Clone() *Config { - var ret Config - if err := json.Unmarshal([]byte(o.ToJson()), &ret); err != nil { - panic(err) - } - return &ret -} - -func (o *Config) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func (o *Config) ToJsonFiltered(tagType, tagValue string) string { - filteredConfigMap := structToMapFilteredByTag(*o, tagType, tagValue) - for key, value := range filteredConfigMap { - v, ok := value.(map[string]interface{}) - if ok && len(v) == 0 { - delete(filteredConfigMap, key) - } - } - b, _ := json.Marshal(filteredConfigMap) - return string(b) -} - -func (o *Config) GetSSOService(service string) *SSOSettings { - switch service { - case SERVICE_GITLAB: - return &o.GitLabSettings - case SERVICE_GOOGLE: - return &o.GoogleSettings - case SERVICE_OFFICE365: - return o.Office365Settings.SSOSettings() - case SERVICE_OPENID: - return &o.OpenIdSettings - } - - return nil -} - -func ConfigFromJson(data io.Reader) *Config { - var o *Config - json.NewDecoder(data).Decode(&o) - return o -} - -// isUpdate detects a pre-existing config based on whether SiteURL has been changed -func (o *Config) isUpdate() bool { - return o.ServiceSettings.SiteURL != nil -} - -func (o *Config) SetDefaults() { - isUpdate := o.isUpdate() - - o.LdapSettings.SetDefaults() - o.SamlSettings.SetDefaults() - - if o.TeamSettings.TeammateNameDisplay == nil { - o.TeamSettings.TeammateNameDisplay = NewString(SHOW_USERNAME) - - if *o.SamlSettings.Enable || *o.LdapSettings.Enable { - *o.TeamSettings.TeammateNameDisplay = SHOW_FULLNAME - } - } - - o.SqlSettings.SetDefaults(isUpdate) - o.FileSettings.SetDefaults(isUpdate) - o.EmailSettings.SetDefaults(isUpdate) - o.PrivacySettings.setDefaults() - o.Office365Settings.setDefaults() - o.Office365Settings.setDefaults() - o.GitLabSettings.setDefaults("", "", "", "", "") - o.GoogleSettings.setDefaults(GOOGLE_SETTINGS_DEFAULT_SCOPE, GOOGLE_SETTINGS_DEFAULT_AUTH_ENDPOINT, GOOGLE_SETTINGS_DEFAULT_TOKEN_ENDPOINT, GOOGLE_SETTINGS_DEFAULT_USER_API_ENDPOINT, "") - o.OpenIdSettings.setDefaults(OPENID_SETTINGS_DEFAULT_SCOPE, "", "", "", "#145DBF") - o.ServiceSettings.SetDefaults(isUpdate) - o.PasswordSettings.SetDefaults() - o.TeamSettings.SetDefaults() - o.MetricsSettings.SetDefaults() - o.ExperimentalSettings.SetDefaults() - o.SupportSettings.SetDefaults() - o.AnnouncementSettings.SetDefaults() - o.ThemeSettings.SetDefaults() - o.ClusterSettings.SetDefaults() - o.PluginSettings.SetDefaults(o.LogSettings) - o.AnalyticsSettings.SetDefaults() - o.ComplianceSettings.SetDefaults() - o.LocalizationSettings.SetDefaults() - o.ElasticsearchSettings.SetDefaults() - o.BleveSettings.SetDefaults() - o.NativeAppSettings.SetDefaults() - o.DataRetentionSettings.SetDefaults() - o.RateLimitSettings.SetDefaults() - o.LogSettings.SetDefaults() - o.ExperimentalAuditSettings.SetDefaults() - o.NotificationLogSettings.SetDefaults() - o.JobSettings.SetDefaults() - o.MessageExportSettings.SetDefaults() - o.DisplaySettings.SetDefaults() - o.GuestAccountsSettings.SetDefaults() - o.ImageProxySettings.SetDefaults(o.ServiceSettings) - o.CloudSettings.SetDefaults() - if o.FeatureFlags == nil { - o.FeatureFlags = &FeatureFlags{} - o.FeatureFlags.SetDefaults() - } - o.ImportSettings.SetDefaults() - o.ExportSettings.SetDefaults() -} - -func (o *Config) IsValid() *AppError { - if *o.ServiceSettings.SiteURL == "" && *o.EmailSettings.EnableEmailBatching { - return NewAppError("Config.IsValid", "model.config.is_valid.site_url_email_batching.app_error", nil, "", http.StatusBadRequest) - } - - if *o.ClusterSettings.Enable && *o.EmailSettings.EnableEmailBatching { - return NewAppError("Config.IsValid", "model.config.is_valid.cluster_email_batching.app_error", nil, "", http.StatusBadRequest) - } - - if *o.ServiceSettings.SiteURL == "" && *o.ServiceSettings.AllowCookiesForSubdomains { - return NewAppError("Config.IsValid", "model.config.is_valid.allow_cookies_for_subdomains.app_error", nil, "", http.StatusBadRequest) - } - - if err := o.TeamSettings.isValid(); err != nil { - return err - } - - if err := o.SqlSettings.isValid(); err != nil { - return err - } - - if err := o.FileSettings.isValid(); err != nil { - return err - } - - if err := o.EmailSettings.isValid(); err != nil { - return err - } - - if err := o.LdapSettings.isValid(); err != nil { - return err - } - - if err := o.SamlSettings.isValid(); err != nil { - return err - } - - if *o.PasswordSettings.MinimumLength < PASSWORD_MINIMUM_LENGTH || *o.PasswordSettings.MinimumLength > PASSWORD_MAXIMUM_LENGTH { - return NewAppError("Config.IsValid", "model.config.is_valid.password_length.app_error", map[string]interface{}{"MinLength": PASSWORD_MINIMUM_LENGTH, "MaxLength": PASSWORD_MAXIMUM_LENGTH}, "", http.StatusBadRequest) - } - - if err := o.RateLimitSettings.isValid(); err != nil { - return err - } - - if err := o.ServiceSettings.isValid(); err != nil { - return err - } - - if err := o.ElasticsearchSettings.isValid(); err != nil { - return err - } - - if err := o.BleveSettings.isValid(); err != nil { - return err - } - - if err := o.DataRetentionSettings.isValid(); err != nil { - return err - } - - if err := o.LocalizationSettings.isValid(); err != nil { - return err - } - - if err := o.MessageExportSettings.isValid(); err != nil { - return err - } - - if err := o.DisplaySettings.isValid(); err != nil { - return err - } - - if err := o.ImageProxySettings.isValid(); err != nil { - return err - } - - if err := o.ImportSettings.isValid(); err != nil { - return err - } - return nil -} - -func (s *TeamSettings) isValid() *AppError { - if *s.MaxUsersPerTeam <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.max_users.app_error", nil, "", http.StatusBadRequest) - } - - if *s.MaxChannelsPerTeam <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.max_channels.app_error", nil, "", http.StatusBadRequest) - } - - if *s.MaxNotificationsPerChannel <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.max_notify_per_channel.app_error", nil, "", http.StatusBadRequest) - } - - if !(*s.RestrictDirectMessage == DIRECT_MESSAGE_ANY || *s.RestrictDirectMessage == DIRECT_MESSAGE_TEAM) { - return NewAppError("Config.IsValid", "model.config.is_valid.restrict_direct_message.app_error", nil, "", http.StatusBadRequest) - } - - if !(*s.TeammateNameDisplay == SHOW_FULLNAME || *s.TeammateNameDisplay == SHOW_NICKNAME_FULLNAME || *s.TeammateNameDisplay == SHOW_USERNAME) { - return NewAppError("Config.IsValid", "model.config.is_valid.teammate_name_display.app_error", nil, "", http.StatusBadRequest) - } - - if len(*s.SiteName) > SITENAME_MAX_LENGTH { - return NewAppError("Config.IsValid", "model.config.is_valid.sitename_length.app_error", map[string]interface{}{"MaxLength": SITENAME_MAX_LENGTH}, "", http.StatusBadRequest) - } - - return nil -} - -func (s *SqlSettings) isValid() *AppError { - if *s.AtRestEncryptKey != "" && len(*s.AtRestEncryptKey) < 32 { - return NewAppError("Config.IsValid", "model.config.is_valid.encrypt_sql.app_error", nil, "", http.StatusBadRequest) - } - - if !(*s.DriverName == DATABASE_DRIVER_MYSQL || *s.DriverName == DATABASE_DRIVER_POSTGRES) { - return NewAppError("Config.IsValid", "model.config.is_valid.sql_driver.app_error", nil, "", http.StatusBadRequest) - } - - if *s.MaxIdleConns <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.sql_idle.app_error", nil, "", http.StatusBadRequest) - } - - if *s.ConnMaxLifetimeMilliseconds < 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.sql_conn_max_lifetime_milliseconds.app_error", nil, "", http.StatusBadRequest) - } - - if *s.ConnMaxIdleTimeMilliseconds < 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.sql_conn_max_idle_time_milliseconds.app_error", nil, "", http.StatusBadRequest) - } - - if *s.QueryTimeout <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.sql_query_timeout.app_error", nil, "", http.StatusBadRequest) - } - - if *s.DataSource == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.sql_data_src.app_error", nil, "", http.StatusBadRequest) - } - - if *s.MaxOpenConns <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.sql_max_conn.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (s *FileSettings) isValid() *AppError { - if *s.MaxFileSize <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.max_file_size.app_error", nil, "", http.StatusBadRequest) - } - - if !(*s.DriverName == IMAGE_DRIVER_LOCAL || *s.DriverName == IMAGE_DRIVER_S3) { - return NewAppError("Config.IsValid", "model.config.is_valid.file_driver.app_error", nil, "", http.StatusBadRequest) - } - - if *s.PublicLinkSalt != "" && len(*s.PublicLinkSalt) < 32 { - return NewAppError("Config.IsValid", "model.config.is_valid.file_salt.app_error", nil, "", http.StatusBadRequest) - } - - if *s.Directory == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.directory.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (s *EmailSettings) isValid() *AppError { - if !(*s.ConnectionSecurity == CONN_SECURITY_NONE || *s.ConnectionSecurity == CONN_SECURITY_TLS || *s.ConnectionSecurity == CONN_SECURITY_STARTTLS || *s.ConnectionSecurity == CONN_SECURITY_PLAIN) { - return NewAppError("Config.IsValid", "model.config.is_valid.email_security.app_error", nil, "", http.StatusBadRequest) - } - - if *s.EmailBatchingBufferSize <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.email_batching_buffer_size.app_error", nil, "", http.StatusBadRequest) - } - - if *s.EmailBatchingInterval < 30 { - return NewAppError("Config.IsValid", "model.config.is_valid.email_batching_interval.app_error", nil, "", http.StatusBadRequest) - } - - if !(*s.EmailNotificationContentsType == EMAIL_NOTIFICATION_CONTENTS_FULL || *s.EmailNotificationContentsType == EMAIL_NOTIFICATION_CONTENTS_GENERIC) { - return NewAppError("Config.IsValid", "model.config.is_valid.email_notification_contents_type.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (s *RateLimitSettings) isValid() *AppError { - if *s.MemoryStoreSize <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.rate_mem.app_error", nil, "", http.StatusBadRequest) - } - - if *s.PerSec <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.rate_sec.app_error", nil, "", http.StatusBadRequest) - } - - if *s.MaxBurst <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.max_burst.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (s *LdapSettings) isValid() *AppError { - if !(*s.ConnectionSecurity == CONN_SECURITY_NONE || *s.ConnectionSecurity == CONN_SECURITY_TLS || *s.ConnectionSecurity == CONN_SECURITY_STARTTLS) { - return NewAppError("Config.IsValid", "model.config.is_valid.ldap_security.app_error", nil, "", http.StatusBadRequest) - } - - if *s.SyncIntervalMinutes <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.ldap_sync_interval.app_error", nil, "", http.StatusBadRequest) - } - - if *s.MaxPageSize < 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.ldap_max_page_size.app_error", nil, "", http.StatusBadRequest) - } - - if *s.Enable { - if *s.LdapServer == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.ldap_server", nil, "", http.StatusBadRequest) - } - - if *s.BaseDN == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.ldap_basedn", nil, "", http.StatusBadRequest) - } - - if *s.EmailAttribute == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.ldap_email", nil, "", http.StatusBadRequest) - } - - if *s.UsernameAttribute == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.ldap_username", nil, "", http.StatusBadRequest) - } - - if *s.IdAttribute == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.ldap_id", nil, "", http.StatusBadRequest) - } - - if *s.LoginIdAttribute == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.ldap_login_id", nil, "", http.StatusBadRequest) - } - - if *s.UserFilter != "" { - if _, err := ldap.CompileFilter(*s.UserFilter); err != nil { - return NewAppError("ValidateFilter", "ent.ldap.validate_filter.app_error", nil, err.Error(), http.StatusBadRequest) - } - } - - if *s.GuestFilter != "" { - if _, err := ldap.CompileFilter(*s.GuestFilter); err != nil { - return NewAppError("LdapSettings.isValid", "ent.ldap.validate_guest_filter.app_error", nil, err.Error(), http.StatusBadRequest) - } - } - - if *s.AdminFilter != "" { - if _, err := ldap.CompileFilter(*s.AdminFilter); err != nil { - return NewAppError("LdapSettings.isValid", "ent.ldap.validate_admin_filter.app_error", nil, err.Error(), http.StatusBadRequest) - } - } - } - - return nil -} - -func (s *SamlSettings) isValid() *AppError { - if *s.Enable { - if *s.IdpUrl == "" || !IsValidHttpUrl(*s.IdpUrl) { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_url.app_error", nil, "", http.StatusBadRequest) - } - - if *s.IdpDescriptorUrl == "" || !IsValidHttpUrl(*s.IdpDescriptorUrl) { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_descriptor_url.app_error", nil, "", http.StatusBadRequest) - } - - if *s.IdpCertificateFile == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_idp_cert.app_error", nil, "", http.StatusBadRequest) - } - - if *s.EmailAttribute == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "", http.StatusBadRequest) - } - - if *s.UsernameAttribute == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_username_attribute.app_error", nil, "", http.StatusBadRequest) - } - - if *s.ServiceProviderIdentifier == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_spidentifier_attribute.app_error", nil, "", http.StatusBadRequest) - } - - if *s.Verify { - if *s.AssertionConsumerServiceURL == "" || !IsValidHttpUrl(*s.AssertionConsumerServiceURL) { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_assertion_consumer_service_url.app_error", nil, "", http.StatusBadRequest) - } - } - - if *s.Encrypt { - if *s.PrivateKeyFile == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_private_key.app_error", nil, "", http.StatusBadRequest) - } - - if *s.PublicCertificateFile == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_public_cert.app_error", nil, "", http.StatusBadRequest) - } - } - - if *s.EmailAttribute == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_email_attribute.app_error", nil, "", http.StatusBadRequest) - } - - if !(*s.SignatureAlgorithm == SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA1 || *s.SignatureAlgorithm == SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA256 || *s.SignatureAlgorithm == SAML_SETTINGS_SIGNATURE_ALGORITHM_SHA512) { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_signature_algorithm.app_error", nil, "", http.StatusBadRequest) - } - if !(*s.CanonicalAlgorithm == SAML_SETTINGS_CANONICAL_ALGORITHM_C14N || *s.CanonicalAlgorithm == SAML_SETTINGS_CANONICAL_ALGORITHM_C14N11) { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_canonical_algorithm.app_error", nil, "", http.StatusBadRequest) - } - - if *s.GuestAttribute != "" { - if !(strings.Contains(*s.GuestAttribute, "=")) { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_guest_attribute.app_error", nil, "", http.StatusBadRequest) - } - if len(strings.Split(*s.GuestAttribute, "=")) != 2 { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_guest_attribute.app_error", nil, "", http.StatusBadRequest) - } - } - - if *s.AdminAttribute != "" { - if !(strings.Contains(*s.AdminAttribute, "=")) { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_admin_attribute.app_error", nil, "", http.StatusBadRequest) - } - if len(strings.Split(*s.AdminAttribute, "=")) != 2 { - return NewAppError("Config.IsValid", "model.config.is_valid.saml_admin_attribute.app_error", nil, "", http.StatusBadRequest) - } - } - } - - return nil -} - -func (s *ServiceSettings) isValid() *AppError { - if !(*s.ConnectionSecurity == CONN_SECURITY_NONE || *s.ConnectionSecurity == CONN_SECURITY_TLS) { - return NewAppError("Config.IsValid", "model.config.is_valid.webserver_security.app_error", nil, "", http.StatusBadRequest) - } - - if *s.ConnectionSecurity == CONN_SECURITY_TLS && !*s.UseLetsEncrypt { - appErr := NewAppError("Config.IsValid", "model.config.is_valid.tls_cert_file_missing.app_error", nil, "", http.StatusBadRequest) - - if *s.TLSCertFile == "" { - return appErr - } else if _, err := os.Stat(*s.TLSCertFile); os.IsNotExist(err) { - return appErr - } - - appErr = NewAppError("Config.IsValid", "model.config.is_valid.tls_key_file_missing.app_error", nil, "", http.StatusBadRequest) - - if *s.TLSKeyFile == "" { - return appErr - } else if _, err := os.Stat(*s.TLSKeyFile); os.IsNotExist(err) { - return appErr - } - } - - if len(s.TLSOverwriteCiphers) > 0 { - for _, cipher := range s.TLSOverwriteCiphers { - if _, ok := ServerTLSSupportedCiphers[cipher]; !ok { - return NewAppError("Config.IsValid", "model.config.is_valid.tls_overwrite_cipher.app_error", map[string]interface{}{"name": cipher}, "", http.StatusBadRequest) - } - } - } - - if *s.ReadTimeout <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.read_timeout.app_error", nil, "", http.StatusBadRequest) - } - - if *s.WriteTimeout <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.write_timeout.app_error", nil, "", http.StatusBadRequest) - } - - if *s.TimeBetweenUserTypingUpdatesMilliseconds < 1000 { - return NewAppError("Config.IsValid", "model.config.is_valid.time_between_user_typing.app_error", nil, "", http.StatusBadRequest) - } - - if *s.MaximumLoginAttempts <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.login_attempts.app_error", nil, "", http.StatusBadRequest) - } - - if *s.SiteURL != "" { - if _, err := url.ParseRequestURI(*s.SiteURL); err != nil { - return NewAppError("Config.IsValid", "model.config.is_valid.site_url.app_error", nil, "", http.StatusBadRequest) - } - } - - if *s.WebsocketURL != "" { - if _, err := url.ParseRequestURI(*s.WebsocketURL); err != nil { - return NewAppError("Config.IsValid", "model.config.is_valid.websocket_url.app_error", nil, "", http.StatusBadRequest) - } - } - - host, port, _ := net.SplitHostPort(*s.ListenAddress) - var isValidHost bool - if host == "" { - isValidHost = true - } else { - isValidHost = (net.ParseIP(host) != nil) || IsDomainName(host) - } - portInt, err := strconv.Atoi(port) - if err != nil || !isValidHost || portInt < 0 || portInt > math.MaxUint16 { - return NewAppError("Config.IsValid", "model.config.is_valid.listen_address.app_error", nil, "", http.StatusBadRequest) - } - - if *s.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DISABLED && - *s.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DEFAULT_ON && - *s.ExperimentalGroupUnreadChannels != GROUP_UNREAD_CHANNELS_DEFAULT_OFF { - return NewAppError("Config.IsValid", "model.config.is_valid.group_unread_channels.app_error", nil, "", http.StatusBadRequest) - } - - if *s.CollapsedThreads != COLLAPSED_THREADS_DISABLED && !*s.ThreadAutoFollow { - return NewAppError("Config.IsValid", "model.config.is_valid.collapsed_threads.autofollow.app_error", nil, "", http.StatusBadRequest) - } - - if *s.CollapsedThreads != COLLAPSED_THREADS_DISABLED && - *s.CollapsedThreads != COLLAPSED_THREADS_DEFAULT_ON && - *s.CollapsedThreads != COLLAPSED_THREADS_DEFAULT_OFF { - return NewAppError("Config.IsValid", "model.config.is_valid.collapsed_threads.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (s *ElasticsearchSettings) isValid() *AppError { - if *s.EnableIndexing { - if *s.ConnectionUrl == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.connection_url.app_error", nil, "", http.StatusBadRequest) - } - } - - if *s.EnableSearching && !*s.EnableIndexing { - return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.enable_searching.app_error", nil, "", http.StatusBadRequest) - } - - if *s.EnableAutocomplete && !*s.EnableIndexing { - return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.enable_autocomplete.app_error", nil, "", http.StatusBadRequest) - } - - if *s.AggregatePostsAfterDays < 1 { - return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.aggregate_posts_after_days.app_error", nil, "", http.StatusBadRequest) - } - - if _, err := time.Parse("15:04", *s.PostsAggregatorJobStartTime); err != nil { - return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.posts_aggregator_job_start_time.app_error", nil, err.Error(), http.StatusBadRequest) - } - - if *s.LiveIndexingBatchSize < 1 { - return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.live_indexing_batch_size.app_error", nil, "", http.StatusBadRequest) - } - - if *s.BulkIndexingTimeWindowSeconds < 1 { - return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.bulk_indexing_time_window_seconds.app_error", nil, "", http.StatusBadRequest) - } - - if *s.RequestTimeoutSeconds < 1 { - return NewAppError("Config.IsValid", "model.config.is_valid.elastic_search.request_timeout_seconds.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (bs *BleveSettings) isValid() *AppError { - if *bs.EnableIndexing { - if *bs.IndexDir == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.filename.app_error", nil, "", http.StatusBadRequest) - } - } else { - if *bs.EnableSearching { - return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.enable_searching.app_error", nil, "", http.StatusBadRequest) - } - if *bs.EnableAutocomplete { - return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.enable_autocomplete.app_error", nil, "", http.StatusBadRequest) - } - } - if *bs.BulkIndexingTimeWindowSeconds < 1 { - return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.bulk_indexing_time_window_seconds.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (s *DataRetentionSettings) isValid() *AppError { - if *s.MessageRetentionDays <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.data_retention.message_retention_days_too_low.app_error", nil, "", http.StatusBadRequest) - } - - if *s.FileRetentionDays <= 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.data_retention.file_retention_days_too_low.app_error", nil, "", http.StatusBadRequest) - } - - if _, err := time.Parse("15:04", *s.DeletionJobStartTime); err != nil { - return NewAppError("Config.IsValid", "model.config.is_valid.data_retention.deletion_job_start_time.app_error", nil, err.Error(), http.StatusBadRequest) - } - - return nil -} - -func (s *LocalizationSettings) isValid() *AppError { - if *s.AvailableLocales != "" { - if !strings.Contains(*s.AvailableLocales, *s.DefaultClientLocale) { - return NewAppError("Config.IsValid", "model.config.is_valid.localization.available_locales.app_error", nil, "", http.StatusBadRequest) - } - } - - return nil -} - -func (s *MessageExportSettings) isValid() *AppError { - if s.EnableExport == nil { - return NewAppError("Config.IsValid", "model.config.is_valid.message_export.enable.app_error", nil, "", http.StatusBadRequest) - } - if *s.EnableExport { - if s.ExportFromTimestamp == nil || *s.ExportFromTimestamp < 0 || *s.ExportFromTimestamp > GetMillis() { - return NewAppError("Config.IsValid", "model.config.is_valid.message_export.export_from.app_error", nil, "", http.StatusBadRequest) - } else if s.DailyRunTime == nil { - return NewAppError("Config.IsValid", "model.config.is_valid.message_export.daily_runtime.app_error", nil, "", http.StatusBadRequest) - } else if _, err := time.Parse("15:04", *s.DailyRunTime); err != nil { - return NewAppError("Config.IsValid", "model.config.is_valid.message_export.daily_runtime.app_error", nil, err.Error(), http.StatusBadRequest) - } else if s.BatchSize == nil || *s.BatchSize < 0 { - return NewAppError("Config.IsValid", "model.config.is_valid.message_export.batch_size.app_error", nil, "", http.StatusBadRequest) - } else if s.ExportFormat == nil || (*s.ExportFormat != COMPLIANCE_EXPORT_TYPE_ACTIANCE && *s.ExportFormat != COMPLIANCE_EXPORT_TYPE_GLOBALRELAY && *s.ExportFormat != COMPLIANCE_EXPORT_TYPE_CSV) { - return NewAppError("Config.IsValid", "model.config.is_valid.message_export.export_type.app_error", nil, "", http.StatusBadRequest) - } - - if *s.ExportFormat == COMPLIANCE_EXPORT_TYPE_GLOBALRELAY { - if s.GlobalRelaySettings == nil { - return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.config_missing.app_error", nil, "", http.StatusBadRequest) - } else if s.GlobalRelaySettings.CustomerType == nil || (*s.GlobalRelaySettings.CustomerType != GLOBALRELAY_CUSTOMER_TYPE_A9 && *s.GlobalRelaySettings.CustomerType != GLOBALRELAY_CUSTOMER_TYPE_A10) { - return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.customer_type.app_error", nil, "", http.StatusBadRequest) - } else if s.GlobalRelaySettings.EmailAddress == nil || !strings.Contains(*s.GlobalRelaySettings.EmailAddress, "@") { - // validating email addresses is hard - just make sure it contains an '@' sign - // see https://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address - return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.email_address.app_error", nil, "", http.StatusBadRequest) - } else if s.GlobalRelaySettings.SmtpUsername == nil || *s.GlobalRelaySettings.SmtpUsername == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.smtp_username.app_error", nil, "", http.StatusBadRequest) - } else if s.GlobalRelaySettings.SmtpPassword == nil || *s.GlobalRelaySettings.SmtpPassword == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.message_export.global_relay.smtp_password.app_error", nil, "", http.StatusBadRequest) - } - } - } - return nil -} - -func (s *DisplaySettings) isValid() *AppError { - if len(s.CustomUrlSchemes) != 0 { - validProtocolPattern := regexp.MustCompile(`(?i)^\s*[A-Za-z][A-Za-z0-9.+-]*\s*$`) - - for _, scheme := range s.CustomUrlSchemes { - if !validProtocolPattern.MatchString(scheme) { - return NewAppError( - "Config.IsValid", - "model.config.is_valid.display.custom_url_schemes.app_error", - map[string]interface{}{"Scheme": scheme}, - "", - http.StatusBadRequest, - ) - } - } - } - - return nil -} - -func (s *ImageProxySettings) isValid() *AppError { - if *s.Enable { - switch *s.ImageProxyType { - case IMAGE_PROXY_TYPE_LOCAL: - // No other settings to validate - case IMAGE_PROXY_TYPE_ATMOS_CAMO: - if *s.RemoteImageProxyURL == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.atmos_camo_image_proxy_url.app_error", nil, "", http.StatusBadRequest) - } - - if *s.RemoteImageProxyOptions == "" { - return NewAppError("Config.IsValid", "model.config.is_valid.atmos_camo_image_proxy_options.app_error", nil, "", http.StatusBadRequest) - } - default: - return NewAppError("Config.IsValid", "model.config.is_valid.image_proxy_type.app_error", nil, "", http.StatusBadRequest) - } - } - - return nil -} - -func (o *Config) GetSanitizeOptions() map[string]bool { - options := map[string]bool{} - options["fullname"] = *o.PrivacySettings.ShowFullName - options["email"] = *o.PrivacySettings.ShowEmailAddress - - return options -} - -func (o *Config) Sanitize() { - if o.LdapSettings.BindPassword != nil && *o.LdapSettings.BindPassword != "" { - *o.LdapSettings.BindPassword = FAKE_SETTING - } - - if o.FileSettings.PublicLinkSalt != nil { - *o.FileSettings.PublicLinkSalt = FAKE_SETTING - } - - if o.FileSettings.AmazonS3SecretAccessKey != nil && *o.FileSettings.AmazonS3SecretAccessKey != "" { - *o.FileSettings.AmazonS3SecretAccessKey = FAKE_SETTING - } - - if o.EmailSettings.SMTPPassword != nil && *o.EmailSettings.SMTPPassword != "" { - *o.EmailSettings.SMTPPassword = FAKE_SETTING - } - - if o.GitLabSettings.Secret != nil && *o.GitLabSettings.Secret != "" { - *o.GitLabSettings.Secret = FAKE_SETTING - } - - if o.GoogleSettings.Secret != nil && *o.GoogleSettings.Secret != "" { - *o.GoogleSettings.Secret = FAKE_SETTING - } - - if o.Office365Settings.Secret != nil && *o.Office365Settings.Secret != "" { - *o.Office365Settings.Secret = FAKE_SETTING - } - - if o.OpenIdSettings.Secret != nil && *o.OpenIdSettings.Secret != "" { - *o.OpenIdSettings.Secret = FAKE_SETTING - } - - if o.SqlSettings.DataSource != nil { - *o.SqlSettings.DataSource = FAKE_SETTING - } - - if o.SqlSettings.AtRestEncryptKey != nil { - *o.SqlSettings.AtRestEncryptKey = FAKE_SETTING - } - - if o.ElasticsearchSettings.Password != nil { - *o.ElasticsearchSettings.Password = FAKE_SETTING - } - - for i := range o.SqlSettings.DataSourceReplicas { - o.SqlSettings.DataSourceReplicas[i] = FAKE_SETTING - } - - for i := range o.SqlSettings.DataSourceSearchReplicas { - o.SqlSettings.DataSourceSearchReplicas[i] = FAKE_SETTING - } - - if o.MessageExportSettings.GlobalRelaySettings != nil && - o.MessageExportSettings.GlobalRelaySettings.SmtpPassword != nil && - *o.MessageExportSettings.GlobalRelaySettings.SmtpPassword != "" { - *o.MessageExportSettings.GlobalRelaySettings.SmtpPassword = FAKE_SETTING - } - - if o.ServiceSettings.GfycatApiSecret != nil && *o.ServiceSettings.GfycatApiSecret != "" { - *o.ServiceSettings.GfycatApiSecret = FAKE_SETTING - } - - if o.ServiceSettings.SplitKey != nil { - *o.ServiceSettings.SplitKey = FAKE_SETTING - } -} - -// structToMapFilteredByTag converts a struct into a map removing those fields that has the tag passed -// as argument -func structToMapFilteredByTag(t interface{}, typeOfTag, filterTag string) map[string]interface{} { - defer func() { - if r := recover(); r != nil { - mlog.Warn("Panicked in structToMapFilteredByTag. This should never happen.", mlog.Any("recover", r)) - } - }() - - val := reflect.ValueOf(t) - elemField := reflect.TypeOf(t) - - if val.Kind() != reflect.Struct { - return nil - } - - out := map[string]interface{}{} - - for i := 0; i < val.NumField(); i++ { - field := val.Field(i) - - structField := elemField.Field(i) - tagPermissions := strings.Split(structField.Tag.Get(typeOfTag), ",") - if isTagPresent(filterTag, tagPermissions) { - continue - } - - var value interface{} - - switch field.Kind() { - case reflect.Struct: - value = structToMapFilteredByTag(field.Interface(), typeOfTag, filterTag) - case reflect.Ptr: - indirectType := field.Elem() - if indirectType.Kind() == reflect.Struct { - value = structToMapFilteredByTag(indirectType.Interface(), typeOfTag, filterTag) - } else if indirectType.Kind() != reflect.Invalid { - value = indirectType.Interface() - } - default: - value = field.Interface() - } - - out[val.Type().Field(i).Name] = value - } - - return out -} - -func isTagPresent(tag string, tags []string) bool { - for _, val := range tags { - tagValue := strings.TrimSpace(val) - if tagValue != "" && tagValue == tag { - return true - } - } - - return false -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/custom_status.go b/vendor/github.com/mattermost/mattermost-server/v5/model/custom_status.go deleted file mode 100644 index 9898ce6c..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/custom_status.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "time" -) - -const ( - UserPropsKeyCustomStatus = "customStatus" - - CustomStatusTextMaxRunes = 100 - MaxRecentCustomStatuses = 5 - DefaultCustomStatusEmoji = "speech_balloon" -) - -var validCustomStatusDuration = map[string]bool{ - "thirty_minutes": true, - "one_hour": true, - "four_hours": true, - "today": true, - "this_week": true, - "date_and_time": true, -} - -type CustomStatus struct { - Emoji string `json:"emoji"` - Text string `json:"text"` - Duration string `json:"duration"` - ExpiresAt time.Time `json:"expires_at"` -} - -func (cs *CustomStatus) PreSave() { - if cs.Emoji == "" { - cs.Emoji = DefaultCustomStatusEmoji - } - - if cs.Duration == "" && !cs.ExpiresAt.Before(time.Now()) { - cs.Duration = "date_and_time" - } - - runes := []rune(cs.Text) - if len(runes) > CustomStatusTextMaxRunes { - cs.Text = string(runes[:CustomStatusTextMaxRunes]) - } -} - -func (cs *CustomStatus) ToJson() string { - csCopy := *cs - b, _ := json.Marshal(csCopy) - return string(b) -} - -func (cs *CustomStatus) AreDurationAndExpirationTimeValid() bool { - if cs.Duration == "" && (cs.ExpiresAt.IsZero() || !cs.ExpiresAt.Before(time.Now())) { - return true - } - - if validCustomStatusDuration[cs.Duration] && !cs.ExpiresAt.Before(time.Now()) { - return true - } - - return false -} - -func CustomStatusFromJson(data io.Reader) *CustomStatus { - var cs *CustomStatus - _ = json.NewDecoder(data).Decode(&cs) - return cs -} - -func RuneToHexadecimalString(r rune) string { - return fmt.Sprintf("%04x", r) -} - -type RecentCustomStatuses []CustomStatus - -func (rcs *RecentCustomStatuses) Contains(cs *CustomStatus) bool { - var csJSON = cs.ToJson() - - // status is empty - if cs == nil || csJSON == "" || (cs.Emoji == "" && cs.Text == "") { - return false - } - - for _, status := range *rcs { - if status.ToJson() == csJSON { - return true - } - } - - return false -} - -func (rcs *RecentCustomStatuses) Add(cs *CustomStatus) *RecentCustomStatuses { - newRCS := (*rcs)[:0] - - // if same `text` exists in existing recent custom statuses, modify existing status - for _, status := range *rcs { - if status.Text != cs.Text { - newRCS = append(newRCS, status) - } - } - newRCS = append(RecentCustomStatuses{*cs}, newRCS...) - if len(newRCS) > MaxRecentCustomStatuses { - newRCS = newRCS[:MaxRecentCustomStatuses] - } - return &newRCS -} - -func (rcs *RecentCustomStatuses) Remove(cs *CustomStatus) *RecentCustomStatuses { - var csJSON = cs.ToJson() - if csJSON == "" || (cs.Emoji == "" && cs.Text == "") { - return rcs - } - - newRCS := (*rcs)[:0] - for _, status := range *rcs { - if status.ToJson() != csJSON { - newRCS = append(newRCS, status) - } - } - - return &newRCS -} - -func (rcs *RecentCustomStatuses) ToJson() string { - rcsCopy := *rcs - b, _ := json.Marshal(rcsCopy) - return string(b) -} - -func RecentCustomStatusesFromJson(data io.Reader) *RecentCustomStatuses { - var rcs *RecentCustomStatuses - _ = json.NewDecoder(data).Decode(&rcs) - return rcs -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/data_retention_policy.go b/vendor/github.com/mattermost/mattermost-server/v5/model/data_retention_policy.go deleted file mode 100644 index 3f984d1b..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/data_retention_policy.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type GlobalRetentionPolicy struct { - MessageDeletionEnabled bool `json:"message_deletion_enabled"` - FileDeletionEnabled bool `json:"file_deletion_enabled"` - MessageRetentionCutoff int64 `json:"message_retention_cutoff"` - FileRetentionCutoff int64 `json:"file_retention_cutoff"` -} - -type RetentionPolicy struct { - ID string `db:"Id" json:"id"` - DisplayName string `json:"display_name"` - PostDuration *int64 `json:"post_duration"` -} - -type RetentionPolicyWithTeamAndChannelIDs struct { - RetentionPolicy - TeamIDs []string `json:"team_ids"` - ChannelIDs []string `json:"channel_ids"` -} - -type RetentionPolicyWithTeamAndChannelCounts struct { - RetentionPolicy - ChannelCount int64 `json:"channel_count"` - TeamCount int64 `json:"team_count"` -} - -type RetentionPolicyChannel struct { - PolicyID string `db:"PolicyId"` - ChannelID string `db:"ChannelId"` -} - -type RetentionPolicyTeam struct { - PolicyID string `db:"PolicyId"` - TeamID string `db:"TeamId"` -} - -type RetentionPolicyWithTeamAndChannelCountsList struct { - Policies []*RetentionPolicyWithTeamAndChannelCounts `json:"policies"` - TotalCount int64 `json:"total_count"` -} - -type RetentionPolicyForTeam struct { - TeamID string `db:"Id" json:"team_id"` - PostDuration int64 `json:"post_duration"` -} - -type RetentionPolicyForTeamList struct { - Policies []*RetentionPolicyForTeam `json:"policies"` - TotalCount int64 `json:"total_count"` -} - -type RetentionPolicyForChannel struct { - ChannelID string `db:"Id" json:"channel_id"` - PostDuration int64 `json:"post_duration"` -} - -type RetentionPolicyForChannelList struct { - Policies []*RetentionPolicyForChannel `json:"policies"` - TotalCount int64 `json:"total_count"` -} - -type RetentionPolicyCursor struct { - ChannelPoliciesDone bool - TeamPoliciesDone bool - GlobalPoliciesDone bool -} - -func (rp *GlobalRetentionPolicy) ToJson() []byte { - b, _ := json.Marshal(rp) - return b -} - -func GlobalRetentionPolicyFromJson(data io.Reader) *GlobalRetentionPolicy { - var grp *GlobalRetentionPolicy - json.NewDecoder(data).Decode(&grp) - return grp -} - -func RetentionPolicyWithTeamAndChannelCountsFromJson(data io.Reader) (*RetentionPolicyWithTeamAndChannelCounts, error) { - var rp RetentionPolicyWithTeamAndChannelCounts - err := json.NewDecoder(data).Decode(&rp) - return &rp, err -} - -func (rp *RetentionPolicyWithTeamAndChannelCounts) ToJson() []byte { - b, _ := json.Marshal(rp) - return b -} - -func RetentionPolicyWithTeamAndChannelCountsListFromJson(data io.Reader) (*RetentionPolicyWithTeamAndChannelCountsList, error) { - var rpList *RetentionPolicyWithTeamAndChannelCountsList - err := json.NewDecoder(data).Decode(&rpList) - if err != nil { - return nil, err - } - return rpList, nil -} - -func (rpList *RetentionPolicyWithTeamAndChannelCountsList) ToJson() []byte { - b, _ := json.Marshal(rpList) - return b -} - -func RetentionPolicyWithTeamAndChannelIdsFromJson(data io.Reader) (*RetentionPolicyWithTeamAndChannelIDs, error) { - var rp *RetentionPolicyWithTeamAndChannelIDs - err := json.NewDecoder(data).Decode(&rp) - return rp, err -} - -func (rp *RetentionPolicyWithTeamAndChannelIDs) ToJson() []byte { - b, _ := json.Marshal(rp) - return b -} - -func (lst *RetentionPolicyForTeamList) ToJson() []byte { - b, _ := json.Marshal(lst) - return b -} - -func (lst *RetentionPolicyForChannelList) ToJson() []byte { - b, _ := json.Marshal(lst) - return b -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/emoji.go b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji.go deleted file mode 100644 index f990c670..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/emoji.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" - "regexp" - "sort" -) - -const ( - EMOJI_NAME_MAX_LENGTH = 64 - EMOJI_SORT_BY_NAME = "name" -) - -var EMOJI_PATTERN = regexp.MustCompile(`:[a-zA-Z0-9_+-]+:`) - -var ReverseSystemEmojisMap = makeReverseEmojiMap() - -type Emoji struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - CreatorId string `json:"creator_id"` - Name string `json:"name"` -} - -func inSystemEmoji(emojiName string) bool { - _, ok := SystemEmojis[emojiName] - return ok -} - -func GetSystemEmojiId(emojiName string) (string, bool) { - id, found := SystemEmojis[emojiName] - return id, found -} - -func makeReverseEmojiMap() map[string][]string { - reverseEmojiMap := make(map[string][]string) - for key, value := range SystemEmojis { - emojiNames := reverseEmojiMap[value] - emojiNames = append(emojiNames, key) - sort.Strings(emojiNames) - reverseEmojiMap[value] = emojiNames - } - - return reverseEmojiMap -} - -func GetEmojiNameFromUnicode(unicode string) (emojiName string, count int) { - if emojiNames, found := ReverseSystemEmojisMap[unicode]; found { - return emojiNames[0], len(emojiNames) - } - - return "", 0 -} - -func (emoji *Emoji) IsValid() *AppError { - if !IsValidId(emoji.Id) { - return NewAppError("Emoji.IsValid", "model.emoji.id.app_error", nil, "", http.StatusBadRequest) - } - - if emoji.CreateAt == 0 { - return NewAppError("Emoji.IsValid", "model.emoji.create_at.app_error", nil, "id="+emoji.Id, http.StatusBadRequest) - } - - if emoji.UpdateAt == 0 { - return NewAppError("Emoji.IsValid", "model.emoji.update_at.app_error", nil, "id="+emoji.Id, http.StatusBadRequest) - } - - if len(emoji.CreatorId) > 26 { - return NewAppError("Emoji.IsValid", "model.emoji.user_id.app_error", nil, "", http.StatusBadRequest) - } - - return IsValidEmojiName(emoji.Name) -} - -func IsValidEmojiName(name string) *AppError { - if name == "" || len(name) > EMOJI_NAME_MAX_LENGTH || !IsValidAlphaNumHyphenUnderscorePlus(name) || inSystemEmoji(name) { - return NewAppError("Emoji.IsValid", "model.emoji.name.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (emoji *Emoji) PreSave() { - if emoji.Id == "" { - emoji.Id = NewId() - } - - emoji.CreateAt = GetMillis() - emoji.UpdateAt = emoji.CreateAt -} - -func (emoji *Emoji) ToJson() string { - b, _ := json.Marshal(emoji) - return string(b) -} - -func EmojiFromJson(data io.Reader) *Emoji { - var emoji *Emoji - json.NewDecoder(data).Decode(&emoji) - return emoji -} - -func EmojiListToJson(emojiList []*Emoji) string { - b, _ := json.Marshal(emojiList) - return string(b) -} - -func EmojiListFromJson(data io.Reader) []*Emoji { - var emojiList []*Emoji - json.NewDecoder(data).Decode(&emojiList) - return emojiList -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_data.go b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_data.go deleted file mode 100644 index 849c2046..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_data.go +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. -// This file is automatically generated via `make emojis`. Do not modify it manually. - -package model - -var SystemEmojis = map[string]string{"grinning": "1f600", "smiley": "1f603", "smile": "1f604", "grin": "1f601", "laughing": "1f606", "satisfied": "1f606", "sweat_smile": "1f605", "rolling_on_the_floor_laughing": "1f923", "rofl": "1f923", "joy": "1f602", "slightly_smiling_face": "1f642", "upside_down_face": "1f643", "wink": "1f609", "blush": "1f60a", "innocent": "1f607", "smiling_face_with_3_hearts": "1f970", "heart_eyes": "1f60d", "star-struck": "1f929", "grinning_face_with_star_eyes": "1f929", "kissing_heart": "1f618", "kissing": "1f617", "relaxed": "263a-fe0f", "kissing_closed_eyes": "1f61a", "kissing_smiling_eyes": "1f619", "smiling_face_with_tear": "1f972", "yum": "1f60b", "stuck_out_tongue": "1f61b", "stuck_out_tongue_winking_eye": "1f61c", "zany_face": "1f92a", "grinning_face_with_one_large_and_one_small_eye": "1f92a", "stuck_out_tongue_closed_eyes": "1f61d", "money_mouth_face": "1f911", "hugging_face": "1f917", "hugs": "1f917", "face_with_hand_over_mouth": "1f92d", "smiling_face_with_smiling_eyes_and_hand_covering_mouth": "1f92d", "shushing_face": "1f92b", "face_with_finger_covering_closed_lips": "1f92b", "thinking_face": "1f914", "thinking": "1f914", "zipper_mouth_face": "1f910", "face_with_raised_eyebrow": "1f928", "face_with_one_eyebrow_raised": "1f928", "neutral_face": "1f610", "expressionless": "1f611", "no_mouth": "1f636", "smirk": "1f60f", "unamused": "1f612", "face_with_rolling_eyes": "1f644", "roll_eyes": "1f644", "grimacing": "1f62c", "lying_face": "1f925", "relieved": "1f60c", "pensive": "1f614", "sleepy": "1f62a", "drooling_face": "1f924", "sleeping": "1f634", "mask": "1f637", "face_with_thermometer": "1f912", "face_with_head_bandage": "1f915", "nauseated_face": "1f922", "face_vomiting": "1f92e", "face_with_open_mouth_vomiting": "1f92e", "sneezing_face": "1f927", "hot_face": "1f975", "cold_face": "1f976", "woozy_face": "1f974", "dizzy_face": "1f635", "exploding_head": "1f92f", "shocked_face_with_exploding_head": "1f92f", "face_with_cowboy_hat": "1f920", "cowboy_hat_face": "1f920", "partying_face": "1f973", "disguised_face": "1f978", "sunglasses": "1f60e", "nerd_face": "1f913", "face_with_monocle": "1f9d0", "confused": "1f615", "worried": "1f61f", "slightly_frowning_face": "1f641", "white_frowning_face": "2639-fe0f", "frowning_face": "2639-fe0f", "open_mouth": "1f62e", "hushed": "1f62f", "astonished": "1f632", "flushed": "1f633", "pleading_face": "1f97a", "frowning": "1f626", "anguished": "1f627", "fearful": "1f628", "cold_sweat": "1f630", "disappointed_relieved": "1f625", "cry": "1f622", "sob": "1f62d", "scream": "1f631", "confounded": "1f616", "persevere": "1f623", "disappointed": "1f61e", "sweat": "1f613", "weary": "1f629", "tired_face": "1f62b", "yawning_face": "1f971", "triumph": "1f624", "rage": "1f621", "pout": "1f621", "angry": "1f620", "face_with_symbols_on_mouth": "1f92c", "serious_face_with_symbols_covering_mouth": "1f92c", "smiling_imp": "1f608", "imp": "1f47f", "skull": "1f480", "skull_and_crossbones": "2620-fe0f", "hankey": "1f4a9", "poop": "1f4a9", "shit": "1f4a9", "clown_face": "1f921", "japanese_ogre": "1f479", "japanese_goblin": "1f47a", "ghost": "1f47b", "alien": "1f47d", "space_invader": "1f47e", "robot_face": "1f916", "robot": "1f916", "smiley_cat": "1f63a", "smile_cat": "1f638", "joy_cat": "1f639", "heart_eyes_cat": "1f63b", "smirk_cat": "1f63c", "kissing_cat": "1f63d", "scream_cat": "1f640", "crying_cat_face": "1f63f", "pouting_cat": "1f63e", "see_no_evil": "1f648", "hear_no_evil": "1f649", "speak_no_evil": "1f64a", "kiss": "1f48b", "love_letter": "1f48c", "cupid": "1f498", "gift_heart": "1f49d", "sparkling_heart": "1f496", "heartpulse": "1f497", "heartbeat": "1f493", "revolving_hearts": "1f49e", "two_hearts": "1f495", "heart_decoration": "1f49f", "heavy_heart_exclamation_mark_ornament": "2763-fe0f", "heavy_heart_exclamation": "2763-fe0f", "broken_heart": "1f494", "heart": "2764-fe0f", "orange_heart": "1f9e1", "yellow_heart": "1f49b", "green_heart": "1f49a", "blue_heart": "1f499", "purple_heart": "1f49c", "brown_heart": "1f90e", "black_heart": "1f5a4", "white_heart": "1f90d", "100": "1f4af", "anger": "1f4a2", "boom": "1f4a5", "collision": "1f4a5", "dizzy": "1f4ab", "sweat_drops": "1f4a6", "dash": "1f4a8", "hole": "1f573-fe0f", "bomb": "1f4a3", "speech_balloon": "1f4ac", "eye-in-speech-bubble": "1f441-fe0f-200d-1f5e8-fe0f", "left_speech_bubble": "1f5e8-fe0f", "right_anger_bubble": "1f5ef-fe0f", "thought_balloon": "1f4ad", "zzz": "1f4a4", "wave": "1f44b", "raised_back_of_hand": "1f91a", "raised_hand_with_fingers_splayed": "1f590-fe0f", "hand": "270b", "raised_hand": "270b", "spock-hand": "1f596", "vulcan_salute": "1f596", "ok_hand": "1f44c", "pinched_fingers": "1f90c", "pinching_hand": "1f90f", "v": "270c-fe0f", "crossed_fingers": "1f91e", "hand_with_index_and_middle_fingers_crossed": "1f91e", "i_love_you_hand_sign": "1f91f", "the_horns": "1f918", "sign_of_the_horns": "1f918", "metal": "1f918", "call_me_hand": "1f919", "point_left": "1f448", "point_right": "1f449", "point_up_2": "1f446", "middle_finger": "1f595", "reversed_hand_with_middle_finger_extended": "1f595", "fu": "1f595", "point_down": "1f447", "point_up": "261d-fe0f", "+1": "1f44d", "thumbsup": "1f44d", "-1": "1f44e", "thumbsdown": "1f44e", "fist": "270a", "fist_raised": "270a", "facepunch": "1f44a", "punch": "1f44a", "fist_oncoming": "1f44a", "left-facing_fist": "1f91b", "fist_left": "1f91b", "right-facing_fist": "1f91c", "fist_right": "1f91c", "clap": "1f44f", "raised_hands": "1f64c", "open_hands": "1f450", "palms_up_together": "1f932", "handshake": "1f91d", "pray": "1f64f", "writing_hand": "270d-fe0f", "nail_care": "1f485", "selfie": "1f933", "muscle": "1f4aa", "mechanical_arm": "1f9be", "mechanical_leg": "1f9bf", "leg": "1f9b5", "foot": "1f9b6", "ear": "1f442", "ear_with_hearing_aid": "1f9bb", "nose": "1f443", "brain": "1f9e0", "anatomical_heart": "1fac0", "lungs": "1fac1", "tooth": "1f9b7", "bone": "1f9b4", "eyes": "1f440", "eye": "1f441-fe0f", "tongue": "1f445", "lips": "1f444", "baby": "1f476", "child": "1f9d2", "boy": "1f466", "girl": "1f467", "adult": "1f9d1", "person_with_blond_hair": "1f471", "man": "1f468", "bearded_person": "1f9d4", "red_haired_man": "1f468-200d-1f9b0", "curly_haired_man": "1f468-200d-1f9b1", "white_haired_man": "1f468-200d-1f9b3", "bald_man": "1f468-200d-1f9b2", "woman": "1f469", "red_haired_woman": "1f469-200d-1f9b0", "red_haired_person": "1f9d1-200d-1f9b0", "curly_haired_woman": "1f469-200d-1f9b1", "curly_haired_person": "1f9d1-200d-1f9b1", "white_haired_woman": "1f469-200d-1f9b3", "white_haired_person": "1f9d1-200d-1f9b3", "bald_woman": "1f469-200d-1f9b2", "bald_person": "1f9d1-200d-1f9b2", "blond-haired-woman": "1f471-200d-2640-fe0f", "blonde_woman": "1f471-200d-2640-fe0f", "blond-haired-man": "1f471-200d-2642-fe0f", "blonde_man": "1f471-200d-2642-fe0f", "older_adult": "1f9d3", "older_man": "1f474", "older_woman": "1f475", "person_frowning": "1f64d", "man-frowning": "1f64d-200d-2642-fe0f", "frowning_man": "1f64d-200d-2642-fe0f", "woman-frowning": "1f64d-200d-2640-fe0f", "frowning_woman": "1f64d-200d-2640-fe0f", "person_with_pouting_face": "1f64e", "man-pouting": "1f64e-200d-2642-fe0f", "pouting_man": "1f64e-200d-2642-fe0f", "woman-pouting": "1f64e-200d-2640-fe0f", "pouting_woman": "1f64e-200d-2640-fe0f", "no_good": "1f645", "man-gesturing-no": "1f645-200d-2642-fe0f", "ng_man": "1f645-200d-2642-fe0f", "no_good_man": "1f645-200d-2642-fe0f", "woman-gesturing-no": "1f645-200d-2640-fe0f", "no_good_woman": "1f645-200d-2640-fe0f", "ng_woman": "1f645-200d-2640-fe0f", "ok_woman": "1f646", "man-gesturing-ok": "1f646-200d-2642-fe0f", "ok_man": "1f646-200d-2642-fe0f", "woman-gesturing-ok": "1f646-200d-2640-fe0f", "information_desk_person": "1f481", "man-tipping-hand": "1f481-200d-2642-fe0f", "tipping_hand_man": "1f481-200d-2642-fe0f", "woman-tipping-hand": "1f481-200d-2640-fe0f", "tipping_hand_woman": "1f481-200d-2640-fe0f", "raising_hand": "1f64b", "man-raising-hand": "1f64b-200d-2642-fe0f", "raising_hand_man": "1f64b-200d-2642-fe0f", "woman-raising-hand": "1f64b-200d-2640-fe0f", "raising_hand_woman": "1f64b-200d-2640-fe0f", "deaf_person": "1f9cf", "deaf_man": "1f9cf-200d-2642-fe0f", "deaf_woman": "1f9cf-200d-2640-fe0f", "bow": "1f647", "man-bowing": "1f647-200d-2642-fe0f", "bowing_man": "1f647-200d-2642-fe0f", "woman-bowing": "1f647-200d-2640-fe0f", "bowing_woman": "1f647-200d-2640-fe0f", "face_palm": "1f926", "man-facepalming": "1f926-200d-2642-fe0f", "man_facepalming": "1f926-200d-2642-fe0f", "woman-facepalming": "1f926-200d-2640-fe0f", "woman_facepalming": "1f926-200d-2640-fe0f", "shrug": "1f937", "man-shrugging": "1f937-200d-2642-fe0f", "man_shrugging": "1f937-200d-2642-fe0f", "woman-shrugging": "1f937-200d-2640-fe0f", "woman_shrugging": "1f937-200d-2640-fe0f", "health_worker": "1f9d1-200d-2695-fe0f", "male-doctor": "1f468-200d-2695-fe0f", "man_health_worker": "1f468-200d-2695-fe0f", "female-doctor": "1f469-200d-2695-fe0f", "woman_health_worker": "1f469-200d-2695-fe0f", "student": "1f9d1-200d-1f393", "male-student": "1f468-200d-1f393", "man_student": "1f468-200d-1f393", "female-student": "1f469-200d-1f393", "woman_student": "1f469-200d-1f393", "teacher": "1f9d1-200d-1f3eb", "male-teacher": "1f468-200d-1f3eb", "man_teacher": "1f468-200d-1f3eb", "female-teacher": "1f469-200d-1f3eb", "woman_teacher": "1f469-200d-1f3eb", "judge": "1f9d1-200d-2696-fe0f", "male-judge": "1f468-200d-2696-fe0f", "man_judge": "1f468-200d-2696-fe0f", "female-judge": "1f469-200d-2696-fe0f", "woman_judge": "1f469-200d-2696-fe0f", "farmer": "1f9d1-200d-1f33e", "male-farmer": "1f468-200d-1f33e", "man_farmer": "1f468-200d-1f33e", "female-farmer": "1f469-200d-1f33e", "woman_farmer": "1f469-200d-1f33e", "cook": "1f9d1-200d-1f373", "male-cook": "1f468-200d-1f373", "man_cook": "1f468-200d-1f373", "female-cook": "1f469-200d-1f373", "woman_cook": "1f469-200d-1f373", "mechanic": "1f9d1-200d-1f527", "male-mechanic": "1f468-200d-1f527", "man_mechanic": "1f468-200d-1f527", "female-mechanic": "1f469-200d-1f527", "woman_mechanic": "1f469-200d-1f527", "factory_worker": "1f9d1-200d-1f3ed", "male-factory-worker": "1f468-200d-1f3ed", "man_factory_worker": "1f468-200d-1f3ed", "female-factory-worker": "1f469-200d-1f3ed", "woman_factory_worker": "1f469-200d-1f3ed", "office_worker": "1f9d1-200d-1f4bc", "male-office-worker": "1f468-200d-1f4bc", "man_office_worker": "1f468-200d-1f4bc", "female-office-worker": "1f469-200d-1f4bc", "woman_office_worker": "1f469-200d-1f4bc", "scientist": "1f9d1-200d-1f52c", "male-scientist": "1f468-200d-1f52c", "man_scientist": "1f468-200d-1f52c", "female-scientist": "1f469-200d-1f52c", "woman_scientist": "1f469-200d-1f52c", "technologist": "1f9d1-200d-1f4bb", "male-technologist": "1f468-200d-1f4bb", "man_technologist": "1f468-200d-1f4bb", "female-technologist": "1f469-200d-1f4bb", "woman_technologist": "1f469-200d-1f4bb", "singer": "1f9d1-200d-1f3a4", "male-singer": "1f468-200d-1f3a4", "man_singer": "1f468-200d-1f3a4", "female-singer": "1f469-200d-1f3a4", "woman_singer": "1f469-200d-1f3a4", "artist": "1f9d1-200d-1f3a8", "male-artist": "1f468-200d-1f3a8", "man_artist": "1f468-200d-1f3a8", "female-artist": "1f469-200d-1f3a8", "woman_artist": "1f469-200d-1f3a8", "pilot": "1f9d1-200d-2708-fe0f", "male-pilot": "1f468-200d-2708-fe0f", "man_pilot": "1f468-200d-2708-fe0f", "female-pilot": "1f469-200d-2708-fe0f", "woman_pilot": "1f469-200d-2708-fe0f", "astronaut": "1f9d1-200d-1f680", "male-astronaut": "1f468-200d-1f680", "man_astronaut": "1f468-200d-1f680", "female-astronaut": "1f469-200d-1f680", "woman_astronaut": "1f469-200d-1f680", "firefighter": "1f9d1-200d-1f692", "male-firefighter": "1f468-200d-1f692", "man_firefighter": "1f468-200d-1f692", "female-firefighter": "1f469-200d-1f692", "woman_firefighter": "1f469-200d-1f692", "cop": "1f46e", "male-police-officer": "1f46e-200d-2642-fe0f", "policeman": "1f46e-200d-2642-fe0f", "female-police-officer": "1f46e-200d-2640-fe0f", "policewoman": "1f46e-200d-2640-fe0f", "sleuth_or_spy": "1f575-fe0f", "detective": "1f575-fe0f", "male-detective": "1f575-fe0f-200d-2642-fe0f", "male_detective": "1f575-fe0f-200d-2642-fe0f", "female-detective": "1f575-fe0f-200d-2640-fe0f", "female_detective": "1f575-fe0f-200d-2640-fe0f", "guardsman": "1f482", "male-guard": "1f482-200d-2642-fe0f", "female-guard": "1f482-200d-2640-fe0f", "guardswoman": "1f482-200d-2640-fe0f", "ninja": "1f977", "construction_worker": "1f477", "male-construction-worker": "1f477-200d-2642-fe0f", "construction_worker_man": "1f477-200d-2642-fe0f", "female-construction-worker": "1f477-200d-2640-fe0f", "construction_worker_woman": "1f477-200d-2640-fe0f", "prince": "1f934", "princess": "1f478", "man_with_turban": "1f473", "man-wearing-turban": "1f473-200d-2642-fe0f", "woman-wearing-turban": "1f473-200d-2640-fe0f", "woman_with_turban": "1f473-200d-2640-fe0f", "man_with_gua_pi_mao": "1f472", "person_with_headscarf": "1f9d5", "person_in_tuxedo": "1f935", "man_in_tuxedo": "1f935-200d-2642-fe0f", "woman_in_tuxedo": "1f935-200d-2640-fe0f", "bride_with_veil": "1f470", "man_with_veil": "1f470-200d-2642-fe0f", "woman_with_veil": "1f470-200d-2640-fe0f", "pregnant_woman": "1f930", "breast-feeding": "1f931", "woman_feeding_baby": "1f469-200d-1f37c", "man_feeding_baby": "1f468-200d-1f37c", "person_feeding_baby": "1f9d1-200d-1f37c", "angel": "1f47c", "santa": "1f385", "mrs_claus": "1f936", "mother_christmas": "1f936", "mx_claus": "1f9d1-200d-1f384", "superhero": "1f9b8", "male_superhero": "1f9b8-200d-2642-fe0f", "female_superhero": "1f9b8-200d-2640-fe0f", "supervillain": "1f9b9", "male_supervillain": "1f9b9-200d-2642-fe0f", "female_supervillain": "1f9b9-200d-2640-fe0f", "mage": "1f9d9", "male_mage": "1f9d9-200d-2642-fe0f", "female_mage": "1f9d9-200d-2640-fe0f", "fairy": "1f9da", "male_fairy": "1f9da-200d-2642-fe0f", "female_fairy": "1f9da-200d-2640-fe0f", "vampire": "1f9db", "male_vampire": "1f9db-200d-2642-fe0f", "female_vampire": "1f9db-200d-2640-fe0f", "merperson": "1f9dc", "merman": "1f9dc-200d-2642-fe0f", "mermaid": "1f9dc-200d-2640-fe0f", "elf": "1f9dd", "male_elf": "1f9dd-200d-2642-fe0f", "female_elf": "1f9dd-200d-2640-fe0f", "genie": "1f9de", "male_genie": "1f9de-200d-2642-fe0f", "female_genie": "1f9de-200d-2640-fe0f", "zombie": "1f9df", "male_zombie": "1f9df-200d-2642-fe0f", "female_zombie": "1f9df-200d-2640-fe0f", "massage": "1f486", "man-getting-massage": "1f486-200d-2642-fe0f", "massage_man": "1f486-200d-2642-fe0f", "woman-getting-massage": "1f486-200d-2640-fe0f", "massage_woman": "1f486-200d-2640-fe0f", "haircut": "1f487", "man-getting-haircut": "1f487-200d-2642-fe0f", "haircut_man": "1f487-200d-2642-fe0f", "woman-getting-haircut": "1f487-200d-2640-fe0f", "haircut_woman": "1f487-200d-2640-fe0f", "walking": "1f6b6", "man-walking": "1f6b6-200d-2642-fe0f", "walking_man": "1f6b6-200d-2642-fe0f", "woman-walking": "1f6b6-200d-2640-fe0f", "walking_woman": "1f6b6-200d-2640-fe0f", "standing_person": "1f9cd", "man_standing": "1f9cd-200d-2642-fe0f", "woman_standing": "1f9cd-200d-2640-fe0f", "kneeling_person": "1f9ce", "man_kneeling": "1f9ce-200d-2642-fe0f", "woman_kneeling": "1f9ce-200d-2640-fe0f", "person_with_probing_cane": "1f9d1-200d-1f9af", "man_with_probing_cane": "1f468-200d-1f9af", "woman_with_probing_cane": "1f469-200d-1f9af", "person_in_motorized_wheelchair": "1f9d1-200d-1f9bc", "man_in_motorized_wheelchair": "1f468-200d-1f9bc", "woman_in_motorized_wheelchair": "1f469-200d-1f9bc", "person_in_manual_wheelchair": "1f9d1-200d-1f9bd", "man_in_manual_wheelchair": "1f468-200d-1f9bd", "woman_in_manual_wheelchair": "1f469-200d-1f9bd", "runner": "1f3c3", "running": "1f3c3", "man-running": "1f3c3-200d-2642-fe0f", "running_man": "1f3c3-200d-2642-fe0f", "woman-running": "1f3c3-200d-2640-fe0f", "running_woman": "1f3c3-200d-2640-fe0f", "dancer": "1f483", "man_dancing": "1f57a", "man_in_business_suit_levitating": "1f574-fe0f", "business_suit_levitating": "1f574-fe0f", "dancers": "1f46f", "man-with-bunny-ears-partying": "1f46f-200d-2642-fe0f", "dancing_men": "1f46f-200d-2642-fe0f", "woman-with-bunny-ears-partying": "1f46f-200d-2640-fe0f", "dancing_women": "1f46f-200d-2640-fe0f", "person_in_steamy_room": "1f9d6", "man_in_steamy_room": "1f9d6-200d-2642-fe0f", "woman_in_steamy_room": "1f9d6-200d-2640-fe0f", "person_climbing": "1f9d7", "man_climbing": "1f9d7-200d-2642-fe0f", "woman_climbing": "1f9d7-200d-2640-fe0f", "fencer": "1f93a", "person_fencing": "1f93a", "horse_racing": "1f3c7", "skier": "26f7-fe0f", "snowboarder": "1f3c2", "golfer": "1f3cc-fe0f", "man-golfing": "1f3cc-fe0f-200d-2642-fe0f", "golfing_man": "1f3cc-fe0f-200d-2642-fe0f", "woman-golfing": "1f3cc-fe0f-200d-2640-fe0f", "golfing_woman": "1f3cc-fe0f-200d-2640-fe0f", "surfer": "1f3c4", "man-surfing": "1f3c4-200d-2642-fe0f", "surfing_man": "1f3c4-200d-2642-fe0f", "woman-surfing": "1f3c4-200d-2640-fe0f", "surfing_woman": "1f3c4-200d-2640-fe0f", "rowboat": "1f6a3", "man-rowing-boat": "1f6a3-200d-2642-fe0f", "rowing_man": "1f6a3-200d-2642-fe0f", "woman-rowing-boat": "1f6a3-200d-2640-fe0f", "rowing_woman": "1f6a3-200d-2640-fe0f", "swimmer": "1f3ca", "man-swimming": "1f3ca-200d-2642-fe0f", "swimming_man": "1f3ca-200d-2642-fe0f", "woman-swimming": "1f3ca-200d-2640-fe0f", "swimming_woman": "1f3ca-200d-2640-fe0f", "person_with_ball": "26f9-fe0f", "man-bouncing-ball": "26f9-fe0f-200d-2642-fe0f", "basketball_man": "26f9-fe0f-200d-2642-fe0f", "woman-bouncing-ball": "26f9-fe0f-200d-2640-fe0f", "basketball_woman": "26f9-fe0f-200d-2640-fe0f", "weight_lifter": "1f3cb-fe0f", "man-lifting-weights": "1f3cb-fe0f-200d-2642-fe0f", "weight_lifting_man": "1f3cb-fe0f-200d-2642-fe0f", "woman-lifting-weights": "1f3cb-fe0f-200d-2640-fe0f", "weight_lifting_woman": "1f3cb-fe0f-200d-2640-fe0f", "bicyclist": "1f6b4", "man-biking": "1f6b4-200d-2642-fe0f", "biking_man": "1f6b4-200d-2642-fe0f", "woman-biking": "1f6b4-200d-2640-fe0f", "biking_woman": "1f6b4-200d-2640-fe0f", "mountain_bicyclist": "1f6b5", "man-mountain-biking": "1f6b5-200d-2642-fe0f", "mountain_biking_man": "1f6b5-200d-2642-fe0f", "woman-mountain-biking": "1f6b5-200d-2640-fe0f", "mountain_biking_woman": "1f6b5-200d-2640-fe0f", "person_doing_cartwheel": "1f938", "man-cartwheeling": "1f938-200d-2642-fe0f", "man_cartwheeling": "1f938-200d-2642-fe0f", "woman-cartwheeling": "1f938-200d-2640-fe0f", "woman_cartwheeling": "1f938-200d-2640-fe0f", "wrestlers": "1f93c", "man-wrestling": "1f93c-200d-2642-fe0f", "men_wrestling": "1f93c-200d-2642-fe0f", "woman-wrestling": "1f93c-200d-2640-fe0f", "women_wrestling": "1f93c-200d-2640-fe0f", "water_polo": "1f93d", "man-playing-water-polo": "1f93d-200d-2642-fe0f", "man_playing_water_polo": "1f93d-200d-2642-fe0f", "woman-playing-water-polo": "1f93d-200d-2640-fe0f", "woman_playing_water_polo": "1f93d-200d-2640-fe0f", "handball": "1f93e", "man-playing-handball": "1f93e-200d-2642-fe0f", "man_playing_handball": "1f93e-200d-2642-fe0f", "woman-playing-handball": "1f93e-200d-2640-fe0f", "woman_playing_handball": "1f93e-200d-2640-fe0f", "juggling": "1f939", "man-juggling": "1f939-200d-2642-fe0f", "man_juggling": "1f939-200d-2642-fe0f", "woman-juggling": "1f939-200d-2640-fe0f", "woman_juggling": "1f939-200d-2640-fe0f", "person_in_lotus_position": "1f9d8", "man_in_lotus_position": "1f9d8-200d-2642-fe0f", "woman_in_lotus_position": "1f9d8-200d-2640-fe0f", "bath": "1f6c0", "sleeping_accommodation": "1f6cc", "sleeping_bed": "1f6cc", "people_holding_hands": "1f9d1-200d-1f91d-200d-1f9d1", "two_women_holding_hands": "1f46d", "women_holding_hands": "1f46d", "man_and_woman_holding_hands": "1f46b", "woman_and_man_holding_hands": "1f46b", "couple": "1f46b", "two_men_holding_hands": "1f46c", "men_holding_hands": "1f46c", "couplekiss": "1f48f", "woman-kiss-man": "1f469-200d-2764-fe0f-200d-1f48b-200d-1f468", "couplekiss_man_woman": "1f469-200d-2764-fe0f-200d-1f48b-200d-1f468", "man-kiss-man": "1f468-200d-2764-fe0f-200d-1f48b-200d-1f468", "couplekiss_man_man": "1f468-200d-2764-fe0f-200d-1f48b-200d-1f468", "woman-kiss-woman": "1f469-200d-2764-fe0f-200d-1f48b-200d-1f469", "couplekiss_woman_woman": "1f469-200d-2764-fe0f-200d-1f48b-200d-1f469", "couple_with_heart": "1f491", "woman-heart-man": "1f469-200d-2764-fe0f-200d-1f468", "couple_with_heart_woman_man": "1f469-200d-2764-fe0f-200d-1f468", "man-heart-man": "1f468-200d-2764-fe0f-200d-1f468", "couple_with_heart_man_man": "1f468-200d-2764-fe0f-200d-1f468", "woman-heart-woman": "1f469-200d-2764-fe0f-200d-1f469", "couple_with_heart_woman_woman": "1f469-200d-2764-fe0f-200d-1f469", "family": "1f46a", "man-woman-boy": "1f468-200d-1f469-200d-1f466", "family_man_woman_boy": "1f468-200d-1f469-200d-1f466", "man-woman-girl": "1f468-200d-1f469-200d-1f467", "family_man_woman_girl": "1f468-200d-1f469-200d-1f467", "man-woman-girl-boy": "1f468-200d-1f469-200d-1f467-200d-1f466", "family_man_woman_girl_boy": "1f468-200d-1f469-200d-1f467-200d-1f466", "man-woman-boy-boy": "1f468-200d-1f469-200d-1f466-200d-1f466", "family_man_woman_boy_boy": "1f468-200d-1f469-200d-1f466-200d-1f466", "man-woman-girl-girl": "1f468-200d-1f469-200d-1f467-200d-1f467", "family_man_woman_girl_girl": "1f468-200d-1f469-200d-1f467-200d-1f467", "man-man-boy": "1f468-200d-1f468-200d-1f466", "family_man_man_boy": "1f468-200d-1f468-200d-1f466", "man-man-girl": "1f468-200d-1f468-200d-1f467", "family_man_man_girl": "1f468-200d-1f468-200d-1f467", "man-man-girl-boy": "1f468-200d-1f468-200d-1f467-200d-1f466", "family_man_man_girl_boy": "1f468-200d-1f468-200d-1f467-200d-1f466", "man-man-boy-boy": "1f468-200d-1f468-200d-1f466-200d-1f466", "family_man_man_boy_boy": "1f468-200d-1f468-200d-1f466-200d-1f466", "man-man-girl-girl": "1f468-200d-1f468-200d-1f467-200d-1f467", "family_man_man_girl_girl": "1f468-200d-1f468-200d-1f467-200d-1f467", "woman-woman-boy": "1f469-200d-1f469-200d-1f466", "family_woman_woman_boy": "1f469-200d-1f469-200d-1f466", "woman-woman-girl": "1f469-200d-1f469-200d-1f467", "family_woman_woman_girl": "1f469-200d-1f469-200d-1f467", "woman-woman-girl-boy": "1f469-200d-1f469-200d-1f467-200d-1f466", "family_woman_woman_girl_boy": "1f469-200d-1f469-200d-1f467-200d-1f466", "woman-woman-boy-boy": "1f469-200d-1f469-200d-1f466-200d-1f466", "family_woman_woman_boy_boy": "1f469-200d-1f469-200d-1f466-200d-1f466", "woman-woman-girl-girl": "1f469-200d-1f469-200d-1f467-200d-1f467", "family_woman_woman_girl_girl": "1f469-200d-1f469-200d-1f467-200d-1f467", "man-boy": "1f468-200d-1f466", "family_man_boy": "1f468-200d-1f466", "man-boy-boy": "1f468-200d-1f466-200d-1f466", "family_man_boy_boy": "1f468-200d-1f466-200d-1f466", "man-girl": "1f468-200d-1f467", "family_man_girl": "1f468-200d-1f467", "man-girl-boy": "1f468-200d-1f467-200d-1f466", "family_man_girl_boy": "1f468-200d-1f467-200d-1f466", "man-girl-girl": "1f468-200d-1f467-200d-1f467", "family_man_girl_girl": "1f468-200d-1f467-200d-1f467", "woman-boy": "1f469-200d-1f466", "family_woman_boy": "1f469-200d-1f466", "woman-boy-boy": "1f469-200d-1f466-200d-1f466", "family_woman_boy_boy": "1f469-200d-1f466-200d-1f466", "woman-girl": "1f469-200d-1f467", "family_woman_girl": "1f469-200d-1f467", "woman-girl-boy": "1f469-200d-1f467-200d-1f466", "family_woman_girl_boy": "1f469-200d-1f467-200d-1f466", "woman-girl-girl": "1f469-200d-1f467-200d-1f467", "family_woman_girl_girl": "1f469-200d-1f467-200d-1f467", "speaking_head_in_silhouette": "1f5e3-fe0f", "speaking_head": "1f5e3-fe0f", "bust_in_silhouette": "1f464", "busts_in_silhouette": "1f465", "people_hugging": "1fac2", "footprints": "1f463", "skin-tone-2": "1f3fb", "skin-tone-3": "1f3fc", "skin-tone-4": "1f3fd", "skin-tone-5": "1f3fe", "skin-tone-6": "1f3ff", "monkey_face": "1f435", "monkey": "1f412", "gorilla": "1f98d", "orangutan": "1f9a7", "dog": "1f436", "dog2": "1f415", "guide_dog": "1f9ae", "service_dog": "1f415-200d-1f9ba", "poodle": "1f429", "wolf": "1f43a", "fox_face": "1f98a", "raccoon": "1f99d", "cat": "1f431", "cat2": "1f408", "black_cat": "1f408-200d-2b1b", "lion_face": "1f981", "lion": "1f981", "tiger": "1f42f", "tiger2": "1f405", "leopard": "1f406", "horse": "1f434", "racehorse": "1f40e", "unicorn_face": "1f984", "unicorn": "1f984", "zebra_face": "1f993", "deer": "1f98c", "bison": "1f9ac", "cow": "1f42e", "ox": "1f402", "water_buffalo": "1f403", "cow2": "1f404", "pig": "1f437", "pig2": "1f416", "boar": "1f417", "pig_nose": "1f43d", "ram": "1f40f", "sheep": "1f411", "goat": "1f410", "dromedary_camel": "1f42a", "camel": "1f42b", "llama": "1f999", "giraffe_face": "1f992", "elephant": "1f418", "mammoth": "1f9a3", "rhinoceros": "1f98f", "hippopotamus": "1f99b", "mouse": "1f42d", "mouse2": "1f401", "rat": "1f400", "hamster": "1f439", "rabbit": "1f430", "rabbit2": "1f407", "chipmunk": "1f43f-fe0f", "beaver": "1f9ab", "hedgehog": "1f994", "bat": "1f987", "bear": "1f43b", "polar_bear": "1f43b-200d-2744-fe0f", "koala": "1f428", "panda_face": "1f43c", "sloth": "1f9a5", "otter": "1f9a6", "skunk": "1f9a8", "kangaroo": "1f998", "badger": "1f9a1", "feet": "1f43e", "paw_prints": "1f43e", "turkey": "1f983", "chicken": "1f414", "rooster": "1f413", "hatching_chick": "1f423", "baby_chick": "1f424", "hatched_chick": "1f425", "bird": "1f426", "penguin": "1f427", "dove_of_peace": "1f54a-fe0f", "dove": "1f54a-fe0f", "eagle": "1f985", "duck": "1f986", "swan": "1f9a2", "owl": "1f989", "dodo": "1f9a4", "feather": "1fab6", "flamingo": "1f9a9", "peacock": "1f99a", "parrot": "1f99c", "frog": "1f438", "crocodile": "1f40a", "turtle": "1f422", "lizard": "1f98e", "snake": "1f40d", "dragon_face": "1f432", "dragon": "1f409", "sauropod": "1f995", "t-rex": "1f996", "whale": "1f433", "whale2": "1f40b", "dolphin": "1f42c", "flipper": "1f42c", "seal": "1f9ad", "fish": "1f41f", "tropical_fish": "1f420", "blowfish": "1f421", "shark": "1f988", "octopus": "1f419", "shell": "1f41a", "snail": "1f40c", "butterfly": "1f98b", "bug": "1f41b", "ant": "1f41c", "bee": "1f41d", "honeybee": "1f41d", "beetle": "1fab2", "ladybug": "1f41e", "lady_beetle": "1f41e", "cricket": "1f997", "cockroach": "1fab3", "spider": "1f577-fe0f", "spider_web": "1f578-fe0f", "scorpion": "1f982", "mosquito": "1f99f", "fly": "1fab0", "worm": "1fab1", "microbe": "1f9a0", "bouquet": "1f490", "cherry_blossom": "1f338", "white_flower": "1f4ae", "rosette": "1f3f5-fe0f", "rose": "1f339", "wilted_flower": "1f940", "hibiscus": "1f33a", "sunflower": "1f33b", "blossom": "1f33c", "tulip": "1f337", "seedling": "1f331", "potted_plant": "1fab4", "evergreen_tree": "1f332", "deciduous_tree": "1f333", "palm_tree": "1f334", "cactus": "1f335", "ear_of_rice": "1f33e", "herb": "1f33f", "shamrock": "2618-fe0f", "four_leaf_clover": "1f340", "maple_leaf": "1f341", "fallen_leaf": "1f342", "leaves": "1f343", "grapes": "1f347", "melon": "1f348", "watermelon": "1f349", "tangerine": "1f34a", "mandarin": "1f34a", "orange": "1f34a", "lemon": "1f34b", "banana": "1f34c", "pineapple": "1f34d", "mango": "1f96d", "apple": "1f34e", "green_apple": "1f34f", "pear": "1f350", "peach": "1f351", "cherries": "1f352", "strawberry": "1f353", "blueberries": "1fad0", "kiwifruit": "1f95d", "kiwi_fruit": "1f95d", "tomato": "1f345", "olive": "1fad2", "coconut": "1f965", "avocado": "1f951", "eggplant": "1f346", "potato": "1f954", "carrot": "1f955", "corn": "1f33d", "hot_pepper": "1f336-fe0f", "bell_pepper": "1fad1", "cucumber": "1f952", "leafy_green": "1f96c", "broccoli": "1f966", "garlic": "1f9c4", "onion": "1f9c5", "mushroom": "1f344", "peanuts": "1f95c", "chestnut": "1f330", "bread": "1f35e", "croissant": "1f950", "baguette_bread": "1f956", "flatbread": "1fad3", "pretzel": "1f968", "bagel": "1f96f", "pancakes": "1f95e", "waffle": "1f9c7", "cheese_wedge": "1f9c0", "cheese": "1f9c0", "meat_on_bone": "1f356", "poultry_leg": "1f357", "cut_of_meat": "1f969", "bacon": "1f953", "hamburger": "1f354", "fries": "1f35f", "pizza": "1f355", "hotdog": "1f32d", "sandwich": "1f96a", "taco": "1f32e", "burrito": "1f32f", "tamale": "1fad4", "stuffed_flatbread": "1f959", "falafel": "1f9c6", "egg": "1f95a", "fried_egg": "1f373", "cooking": "1f373", "shallow_pan_of_food": "1f958", "stew": "1f372", "fondue": "1fad5", "bowl_with_spoon": "1f963", "green_salad": "1f957", "popcorn": "1f37f", "butter": "1f9c8", "salt": "1f9c2", "canned_food": "1f96b", "bento": "1f371", "rice_cracker": "1f358", "rice_ball": "1f359", "rice": "1f35a", "curry": "1f35b", "ramen": "1f35c", "spaghetti": "1f35d", "sweet_potato": "1f360", "oden": "1f362", "sushi": "1f363", "fried_shrimp": "1f364", "fish_cake": "1f365", "moon_cake": "1f96e", "dango": "1f361", "dumpling": "1f95f", "fortune_cookie": "1f960", "takeout_box": "1f961", "crab": "1f980", "lobster": "1f99e", "shrimp": "1f990", "squid": "1f991", "oyster": "1f9aa", "icecream": "1f366", "shaved_ice": "1f367", "ice_cream": "1f368", "doughnut": "1f369", "cookie": "1f36a", "birthday": "1f382", "cake": "1f370", "cupcake": "1f9c1", "pie": "1f967", "chocolate_bar": "1f36b", "candy": "1f36c", "lollipop": "1f36d", "custard": "1f36e", "honey_pot": "1f36f", "baby_bottle": "1f37c", "glass_of_milk": "1f95b", "milk_glass": "1f95b", "coffee": "2615", "teapot": "1fad6", "tea": "1f375", "sake": "1f376", "champagne": "1f37e", "wine_glass": "1f377", "cocktail": "1f378", "tropical_drink": "1f379", "beer": "1f37a", "beers": "1f37b", "clinking_glasses": "1f942", "tumbler_glass": "1f943", "cup_with_straw": "1f964", "bubble_tea": "1f9cb", "beverage_box": "1f9c3", "mate_drink": "1f9c9", "ice_cube": "1f9ca", "chopsticks": "1f962", "knife_fork_plate": "1f37d-fe0f", "plate_with_cutlery": "1f37d-fe0f", "fork_and_knife": "1f374", "spoon": "1f944", "hocho": "1f52a", "knife": "1f52a", "amphora": "1f3fa", "earth_africa": "1f30d", "earth_americas": "1f30e", "earth_asia": "1f30f", "globe_with_meridians": "1f310", "world_map": "1f5fa-fe0f", "japan": "1f5fe", "compass": "1f9ed", "snow_capped_mountain": "1f3d4-fe0f", "mountain_snow": "1f3d4-fe0f", "mountain": "26f0-fe0f", "volcano": "1f30b", "mount_fuji": "1f5fb", "camping": "1f3d5-fe0f", "beach_with_umbrella": "1f3d6-fe0f", "beach_umbrella": "1f3d6-fe0f", "desert": "1f3dc-fe0f", "desert_island": "1f3dd-fe0f", "national_park": "1f3de-fe0f", "stadium": "1f3df-fe0f", "classical_building": "1f3db-fe0f", "building_construction": "1f3d7-fe0f", "bricks": "1f9f1", "rock": "1faa8", "wood": "1fab5", "hut": "1f6d6", "house_buildings": "1f3d8-fe0f", "houses": "1f3d8-fe0f", "derelict_house_building": "1f3da-fe0f", "derelict_house": "1f3da-fe0f", "house": "1f3e0", "house_with_garden": "1f3e1", "office": "1f3e2", "post_office": "1f3e3", "european_post_office": "1f3e4", "hospital": "1f3e5", "bank": "1f3e6", "hotel": "1f3e8", "love_hotel": "1f3e9", "convenience_store": "1f3ea", "school": "1f3eb", "department_store": "1f3ec", "factory": "1f3ed", "japanese_castle": "1f3ef", "european_castle": "1f3f0", "wedding": "1f492", "tokyo_tower": "1f5fc", "statue_of_liberty": "1f5fd", "church": "26ea", "mosque": "1f54c", "hindu_temple": "1f6d5", "synagogue": "1f54d", "shinto_shrine": "26e9-fe0f", "kaaba": "1f54b", "fountain": "26f2", "tent": "26fa", "foggy": "1f301", "night_with_stars": "1f303", "cityscape": "1f3d9-fe0f", "sunrise_over_mountains": "1f304", "sunrise": "1f305", "city_sunset": "1f306", "city_sunrise": "1f307", "bridge_at_night": "1f309", "hotsprings": "2668-fe0f", "carousel_horse": "1f3a0", "ferris_wheel": "1f3a1", "roller_coaster": "1f3a2", "barber": "1f488", "circus_tent": "1f3aa", "steam_locomotive": "1f682", "railway_car": "1f683", "bullettrain_side": "1f684", "bullettrain_front": "1f685", "train2": "1f686", "metro": "1f687", "light_rail": "1f688", "station": "1f689", "tram": "1f68a", "monorail": "1f69d", "mountain_railway": "1f69e", "train": "1f68b", "bus": "1f68c", "oncoming_bus": "1f68d", "trolleybus": "1f68e", "minibus": "1f690", "ambulance": "1f691", "fire_engine": "1f692", "police_car": "1f693", "oncoming_police_car": "1f694", "taxi": "1f695", "oncoming_taxi": "1f696", "car": "1f697", "red_car": "1f697", "oncoming_automobile": "1f698", "blue_car": "1f699", "pickup_truck": "1f6fb", "truck": "1f69a", "articulated_lorry": "1f69b", "tractor": "1f69c", "racing_car": "1f3ce-fe0f", "racing_motorcycle": "1f3cd-fe0f", "motorcycle": "1f3cd-fe0f", "motor_scooter": "1f6f5", "manual_wheelchair": "1f9bd", "motorized_wheelchair": "1f9bc", "auto_rickshaw": "1f6fa", "bike": "1f6b2", "scooter": "1f6f4", "kick_scooter": "1f6f4", "skateboard": "1f6f9", "roller_skate": "1f6fc", "busstop": "1f68f", "motorway": "1f6e3-fe0f", "railway_track": "1f6e4-fe0f", "oil_drum": "1f6e2-fe0f", "fuelpump": "26fd", "rotating_light": "1f6a8", "traffic_light": "1f6a5", "vertical_traffic_light": "1f6a6", "octagonal_sign": "1f6d1", "stop_sign": "1f6d1", "construction": "1f6a7", "anchor": "2693", "boat": "26f5", "sailboat": "26f5", "canoe": "1f6f6", "speedboat": "1f6a4", "passenger_ship": "1f6f3-fe0f", "ferry": "26f4-fe0f", "motor_boat": "1f6e5-fe0f", "ship": "1f6a2", "airplane": "2708-fe0f", "small_airplane": "1f6e9-fe0f", "airplane_departure": "1f6eb", "flight_departure": "1f6eb", "airplane_arriving": "1f6ec", "flight_arrival": "1f6ec", "parachute": "1fa82", "seat": "1f4ba", "helicopter": "1f681", "suspension_railway": "1f69f", "mountain_cableway": "1f6a0", "aerial_tramway": "1f6a1", "satellite": "1f6f0-fe0f", "artificial_satellite": "1f6f0-fe0f", "rocket": "1f680", "flying_saucer": "1f6f8", "bellhop_bell": "1f6ce-fe0f", "luggage": "1f9f3", "hourglass": "231b", "hourglass_flowing_sand": "23f3", "watch": "231a", "alarm_clock": "23f0", "stopwatch": "23f1-fe0f", "timer_clock": "23f2-fe0f", "mantelpiece_clock": "1f570-fe0f", "clock12": "1f55b", "clock1230": "1f567", "clock1": "1f550", "clock130": "1f55c", "clock2": "1f551", "clock230": "1f55d", "clock3": "1f552", "clock330": "1f55e", "clock4": "1f553", "clock430": "1f55f", "clock5": "1f554", "clock530": "1f560", "clock6": "1f555", "clock630": "1f561", "clock7": "1f556", "clock730": "1f562", "clock8": "1f557", "clock830": "1f563", "clock9": "1f558", "clock930": "1f564", "clock10": "1f559", "clock1030": "1f565", "clock11": "1f55a", "clock1130": "1f566", "new_moon": "1f311", "waxing_crescent_moon": "1f312", "first_quarter_moon": "1f313", "moon": "1f314", "waxing_gibbous_moon": "1f314", "full_moon": "1f315", "waning_gibbous_moon": "1f316", "last_quarter_moon": "1f317", "waning_crescent_moon": "1f318", "crescent_moon": "1f319", "new_moon_with_face": "1f31a", "first_quarter_moon_with_face": "1f31b", "last_quarter_moon_with_face": "1f31c", "thermometer": "1f321-fe0f", "sunny": "2600-fe0f", "full_moon_with_face": "1f31d", "sun_with_face": "1f31e", "ringed_planet": "1fa90", "star": "2b50", "star2": "1f31f", "stars": "1f320", "milky_way": "1f30c", "cloud": "2601-fe0f", "partly_sunny": "26c5", "thunder_cloud_and_rain": "26c8-fe0f", "cloud_with_lightning_and_rain": "26c8-fe0f", "mostly_sunny": "1f324-fe0f", "sun_small_cloud": "1f324-fe0f", "sun_behind_small_cloud": "1f324-fe0f", "barely_sunny": "1f325-fe0f", "sun_behind_cloud": "1f325-fe0f", "sun_behind_large_cloud": "1f325-fe0f", "partly_sunny_rain": "1f326-fe0f", "sun_behind_rain_cloud": "1f326-fe0f", "rain_cloud": "1f327-fe0f", "cloud_with_rain": "1f327-fe0f", "snow_cloud": "1f328-fe0f", "cloud_with_snow": "1f328-fe0f", "lightning": "1f329-fe0f", "lightning_cloud": "1f329-fe0f", "cloud_with_lightning": "1f329-fe0f", "tornado": "1f32a-fe0f", "tornado_cloud": "1f32a-fe0f", "fog": "1f32b-fe0f", "wind_blowing_face": "1f32c-fe0f", "wind_face": "1f32c-fe0f", "cyclone": "1f300", "rainbow": "1f308", "closed_umbrella": "1f302", "umbrella": "2602-fe0f", "open_umbrella": "2602-fe0f", "umbrella_with_rain_drops": "2614", "umbrella_on_ground": "26f1-fe0f", "parasol_on_ground": "26f1-fe0f", "zap": "26a1", "snowflake": "2744-fe0f", "snowman": "2603-fe0f", "snowman_with_snow": "2603-fe0f", "snowman_without_snow": "26c4", "comet": "2604-fe0f", "fire": "1f525", "droplet": "1f4a7", "ocean": "1f30a", "jack_o_lantern": "1f383", "christmas_tree": "1f384", "fireworks": "1f386", "sparkler": "1f387", "firecracker": "1f9e8", "sparkles": "2728", "balloon": "1f388", "tada": "1f389", "confetti_ball": "1f38a", "tanabata_tree": "1f38b", "bamboo": "1f38d", "dolls": "1f38e", "flags": "1f38f", "wind_chime": "1f390", "rice_scene": "1f391", "red_envelope": "1f9e7", "ribbon": "1f380", "gift": "1f381", "reminder_ribbon": "1f397-fe0f", "admission_tickets": "1f39f-fe0f", "tickets": "1f39f-fe0f", "ticket": "1f3ab", "medal": "1f396-fe0f", "medal_military": "1f396-fe0f", "trophy": "1f3c6", "sports_medal": "1f3c5", "medal_sports": "1f3c5", "first_place_medal": "1f947", "1st_place_medal": "1f947", "second_place_medal": "1f948", "2nd_place_medal": "1f948", "third_place_medal": "1f949", "3rd_place_medal": "1f949", "soccer": "26bd", "baseball": "26be", "softball": "1f94e", "basketball": "1f3c0", "volleyball": "1f3d0", "football": "1f3c8", "rugby_football": "1f3c9", "tennis": "1f3be", "flying_disc": "1f94f", "bowling": "1f3b3", "cricket_bat_and_ball": "1f3cf", "field_hockey_stick_and_ball": "1f3d1", "field_hockey": "1f3d1", "ice_hockey_stick_and_puck": "1f3d2", "ice_hockey": "1f3d2", "lacrosse": "1f94d", "table_tennis_paddle_and_ball": "1f3d3", "ping_pong": "1f3d3", "badminton_racquet_and_shuttlecock": "1f3f8", "badminton": "1f3f8", "boxing_glove": "1f94a", "martial_arts_uniform": "1f94b", "goal_net": "1f945", "golf": "26f3", "ice_skate": "26f8-fe0f", "fishing_pole_and_fish": "1f3a3", "diving_mask": "1f93f", "running_shirt_with_sash": "1f3bd", "ski": "1f3bf", "sled": "1f6f7", "curling_stone": "1f94c", "dart": "1f3af", "yo-yo": "1fa80", "kite": "1fa81", "8ball": "1f3b1", "crystal_ball": "1f52e", "magic_wand": "1fa84", "nazar_amulet": "1f9ff", "video_game": "1f3ae", "joystick": "1f579-fe0f", "slot_machine": "1f3b0", "game_die": "1f3b2", "jigsaw": "1f9e9", "teddy_bear": "1f9f8", "pinata": "1fa85", "nesting_dolls": "1fa86", "spades": "2660-fe0f", "hearts": "2665-fe0f", "diamonds": "2666-fe0f", "clubs": "2663-fe0f", "chess_pawn": "265f-fe0f", "black_joker": "1f0cf", "mahjong": "1f004", "flower_playing_cards": "1f3b4", "performing_arts": "1f3ad", "frame_with_picture": "1f5bc-fe0f", "framed_picture": "1f5bc-fe0f", "art": "1f3a8", "thread": "1f9f5", "sewing_needle": "1faa1", "yarn": "1f9f6", "knot": "1faa2", "eyeglasses": "1f453", "dark_sunglasses": "1f576-fe0f", "goggles": "1f97d", "lab_coat": "1f97c", "safety_vest": "1f9ba", "necktie": "1f454", "shirt": "1f455", "tshirt": "1f455", "jeans": "1f456", "scarf": "1f9e3", "gloves": "1f9e4", "coat": "1f9e5", "socks": "1f9e6", "dress": "1f457", "kimono": "1f458", "sari": "1f97b", "one-piece_swimsuit": "1fa71", "briefs": "1fa72", "shorts": "1fa73", "bikini": "1f459", "womans_clothes": "1f45a", "purse": "1f45b", "handbag": "1f45c", "pouch": "1f45d", "shopping_bags": "1f6cd-fe0f", "shopping": "1f6cd-fe0f", "school_satchel": "1f392", "thong_sandal": "1fa74", "mans_shoe": "1f45e", "shoe": "1f45e", "athletic_shoe": "1f45f", "hiking_boot": "1f97e", "womans_flat_shoe": "1f97f", "high_heel": "1f460", "sandal": "1f461", "ballet_shoes": "1fa70", "boot": "1f462", "crown": "1f451", "womans_hat": "1f452", "tophat": "1f3a9", "mortar_board": "1f393", "billed_cap": "1f9e2", "military_helmet": "1fa96", "helmet_with_white_cross": "26d1-fe0f", "rescue_worker_helmet": "26d1-fe0f", "prayer_beads": "1f4ff", "lipstick": "1f484", "ring": "1f48d", "gem": "1f48e", "mute": "1f507", "speaker": "1f508", "sound": "1f509", "loud_sound": "1f50a", "loudspeaker": "1f4e2", "mega": "1f4e3", "postal_horn": "1f4ef", "bell": "1f514", "no_bell": "1f515", "musical_score": "1f3bc", "musical_note": "1f3b5", "notes": "1f3b6", "studio_microphone": "1f399-fe0f", "level_slider": "1f39a-fe0f", "control_knobs": "1f39b-fe0f", "microphone": "1f3a4", "headphones": "1f3a7", "radio": "1f4fb", "saxophone": "1f3b7", "accordion": "1fa97", "guitar": "1f3b8", "musical_keyboard": "1f3b9", "trumpet": "1f3ba", "violin": "1f3bb", "banjo": "1fa95", "drum_with_drumsticks": "1f941", "drum": "1f941", "long_drum": "1fa98", "iphone": "1f4f1", "calling": "1f4f2", "phone": "260e-fe0f", "telephone": "260e-fe0f", "telephone_receiver": "1f4de", "pager": "1f4df", "fax": "1f4e0", "battery": "1f50b", "electric_plug": "1f50c", "computer": "1f4bb", "desktop_computer": "1f5a5-fe0f", "printer": "1f5a8-fe0f", "keyboard": "2328-fe0f", "three_button_mouse": "1f5b1-fe0f", "computer_mouse": "1f5b1-fe0f", "trackball": "1f5b2-fe0f", "minidisc": "1f4bd", "floppy_disk": "1f4be", "cd": "1f4bf", "dvd": "1f4c0", "abacus": "1f9ee", "movie_camera": "1f3a5", "film_frames": "1f39e-fe0f", "film_strip": "1f39e-fe0f", "film_projector": "1f4fd-fe0f", "clapper": "1f3ac", "tv": "1f4fa", "camera": "1f4f7", "camera_with_flash": "1f4f8", "camera_flash": "1f4f8", "video_camera": "1f4f9", "vhs": "1f4fc", "mag": "1f50d", "mag_right": "1f50e", "candle": "1f56f-fe0f", "bulb": "1f4a1", "flashlight": "1f526", "izakaya_lantern": "1f3ee", "lantern": "1f3ee", "diya_lamp": "1fa94", "notebook_with_decorative_cover": "1f4d4", "closed_book": "1f4d5", "book": "1f4d6", "open_book": "1f4d6", "green_book": "1f4d7", "blue_book": "1f4d8", "orange_book": "1f4d9", "books": "1f4da", "notebook": "1f4d3", "ledger": "1f4d2", "page_with_curl": "1f4c3", "scroll": "1f4dc", "page_facing_up": "1f4c4", "newspaper": "1f4f0", "rolled_up_newspaper": "1f5de-fe0f", "newspaper_roll": "1f5de-fe0f", "bookmark_tabs": "1f4d1", "bookmark": "1f516", "label": "1f3f7-fe0f", "moneybag": "1f4b0", "coin": "1fa99", "yen": "1f4b4", "dollar": "1f4b5", "euro": "1f4b6", "pound": "1f4b7", "money_with_wings": "1f4b8", "credit_card": "1f4b3", "receipt": "1f9fe", "chart": "1f4b9", "email": "2709-fe0f", "envelope": "2709-fe0f", "e-mail": "1f4e7", "incoming_envelope": "1f4e8", "envelope_with_arrow": "1f4e9", "outbox_tray": "1f4e4", "inbox_tray": "1f4e5", "package": "1f4e6", "mailbox": "1f4eb", "mailbox_closed": "1f4ea", "mailbox_with_mail": "1f4ec", "mailbox_with_no_mail": "1f4ed", "postbox": "1f4ee", "ballot_box_with_ballot": "1f5f3-fe0f", "ballot_box": "1f5f3-fe0f", "pencil2": "270f-fe0f", "black_nib": "2712-fe0f", "lower_left_fountain_pen": "1f58b-fe0f", "fountain_pen": "1f58b-fe0f", "lower_left_ballpoint_pen": "1f58a-fe0f", "pen": "1f58a-fe0f", "lower_left_paintbrush": "1f58c-fe0f", "paintbrush": "1f58c-fe0f", "lower_left_crayon": "1f58d-fe0f", "crayon": "1f58d-fe0f", "memo": "1f4dd", "pencil": "1f4dd", "briefcase": "1f4bc", "file_folder": "1f4c1", "open_file_folder": "1f4c2", "card_index_dividers": "1f5c2-fe0f", "date": "1f4c5", "calendar": "1f4c6", "spiral_note_pad": "1f5d2-fe0f", "spiral_notepad": "1f5d2-fe0f", "spiral_calendar_pad": "1f5d3-fe0f", "spiral_calendar": "1f5d3-fe0f", "card_index": "1f4c7", "chart_with_upwards_trend": "1f4c8", "chart_with_downwards_trend": "1f4c9", "bar_chart": "1f4ca", "clipboard": "1f4cb", "pushpin": "1f4cc", "round_pushpin": "1f4cd", "paperclip": "1f4ce", "linked_paperclips": "1f587-fe0f", "paperclips": "1f587-fe0f", "straight_ruler": "1f4cf", "triangular_ruler": "1f4d0", "scissors": "2702-fe0f", "card_file_box": "1f5c3-fe0f", "file_cabinet": "1f5c4-fe0f", "wastebasket": "1f5d1-fe0f", "lock": "1f512", "unlock": "1f513", "lock_with_ink_pen": "1f50f", "closed_lock_with_key": "1f510", "key": "1f511", "old_key": "1f5dd-fe0f", "hammer": "1f528", "axe": "1fa93", "pick": "26cf-fe0f", "hammer_and_pick": "2692-fe0f", "hammer_and_wrench": "1f6e0-fe0f", "dagger_knife": "1f5e1-fe0f", "dagger": "1f5e1-fe0f", "crossed_swords": "2694-fe0f", "gun": "1f52b", "boomerang": "1fa83", "bow_and_arrow": "1f3f9", "shield": "1f6e1-fe0f", "carpentry_saw": "1fa9a", "wrench": "1f527", "screwdriver": "1fa9b", "nut_and_bolt": "1f529", "gear": "2699-fe0f", "compression": "1f5dc-fe0f", "clamp": "1f5dc-fe0f", "scales": "2696-fe0f", "balance_scale": "2696-fe0f", "probing_cane": "1f9af", "link": "1f517", "chains": "26d3-fe0f", "hook": "1fa9d", "toolbox": "1f9f0", "magnet": "1f9f2", "ladder": "1fa9c", "alembic": "2697-fe0f", "test_tube": "1f9ea", "petri_dish": "1f9eb", "dna": "1f9ec", "microscope": "1f52c", "telescope": "1f52d", "satellite_antenna": "1f4e1", "syringe": "1f489", "drop_of_blood": "1fa78", "pill": "1f48a", "adhesive_bandage": "1fa79", "stethoscope": "1fa7a", "door": "1f6aa", "elevator": "1f6d7", "mirror": "1fa9e", "window": "1fa9f", "bed": "1f6cf-fe0f", "couch_and_lamp": "1f6cb-fe0f", "chair": "1fa91", "toilet": "1f6bd", "plunger": "1faa0", "shower": "1f6bf", "bathtub": "1f6c1", "mouse_trap": "1faa4", "razor": "1fa92", "lotion_bottle": "1f9f4", "safety_pin": "1f9f7", "broom": "1f9f9", "basket": "1f9fa", "roll_of_paper": "1f9fb", "bucket": "1faa3", "soap": "1f9fc", "toothbrush": "1faa5", "sponge": "1f9fd", "fire_extinguisher": "1f9ef", "shopping_trolley": "1f6d2", "shopping_cart": "1f6d2", "smoking": "1f6ac", "coffin": "26b0-fe0f", "headstone": "1faa6", "funeral_urn": "26b1-fe0f", "moyai": "1f5ff", "placard": "1faa7", "atm": "1f3e7", "put_litter_in_its_place": "1f6ae", "potable_water": "1f6b0", "wheelchair": "267f", "mens": "1f6b9", "womens": "1f6ba", "restroom": "1f6bb", "baby_symbol": "1f6bc", "wc": "1f6be", "passport_control": "1f6c2", "customs": "1f6c3", "baggage_claim": "1f6c4", "left_luggage": "1f6c5", "warning": "26a0-fe0f", "children_crossing": "1f6b8", "no_entry": "26d4", "no_entry_sign": "1f6ab", "no_bicycles": "1f6b3", "no_smoking": "1f6ad", "do_not_litter": "1f6af", "non-potable_water": "1f6b1", "no_pedestrians": "1f6b7", "no_mobile_phones": "1f4f5", "underage": "1f51e", "radioactive_sign": "2622-fe0f", "radioactive": "2622-fe0f", "biohazard_sign": "2623-fe0f", "biohazard": "2623-fe0f", "arrow_up": "2b06-fe0f", "arrow_upper_right": "2197-fe0f", "arrow_right": "27a1-fe0f", "arrow_lower_right": "2198-fe0f", "arrow_down": "2b07-fe0f", "arrow_lower_left": "2199-fe0f", "arrow_left": "2b05-fe0f", "arrow_upper_left": "2196-fe0f", "arrow_up_down": "2195-fe0f", "left_right_arrow": "2194-fe0f", "leftwards_arrow_with_hook": "21a9-fe0f", "arrow_right_hook": "21aa-fe0f", "arrow_heading_up": "2934-fe0f", "arrow_heading_down": "2935-fe0f", "arrows_clockwise": "1f503", "arrows_counterclockwise": "1f504", "back": "1f519", "end": "1f51a", "on": "1f51b", "soon": "1f51c", "top": "1f51d", "place_of_worship": "1f6d0", "atom_symbol": "269b-fe0f", "om_symbol": "1f549-fe0f", "om": "1f549-fe0f", "star_of_david": "2721-fe0f", "wheel_of_dharma": "2638-fe0f", "yin_yang": "262f-fe0f", "latin_cross": "271d-fe0f", "orthodox_cross": "2626-fe0f", "star_and_crescent": "262a-fe0f", "peace_symbol": "262e-fe0f", "menorah_with_nine_branches": "1f54e", "menorah": "1f54e", "six_pointed_star": "1f52f", "aries": "2648", "taurus": "2649", "gemini": "264a", "cancer": "264b", "leo": "264c", "virgo": "264d", "libra": "264e", "scorpius": "264f", "sagittarius": "2650", "capricorn": "2651", "aquarius": "2652", "pisces": "2653", "ophiuchus": "26ce", "twisted_rightwards_arrows": "1f500", "repeat": "1f501", "repeat_one": "1f502", "arrow_forward": "25b6-fe0f", "fast_forward": "23e9", "black_right_pointing_double_triangle_with_vertical_bar": "23ed-fe0f", "next_track_button": "23ed-fe0f", "black_right_pointing_triangle_with_double_vertical_bar": "23ef-fe0f", "play_or_pause_button": "23ef-fe0f", "arrow_backward": "25c0-fe0f", "rewind": "23ea", "black_left_pointing_double_triangle_with_vertical_bar": "23ee-fe0f", "previous_track_button": "23ee-fe0f", "arrow_up_small": "1f53c", "arrow_double_up": "23eb", "arrow_down_small": "1f53d", "arrow_double_down": "23ec", "double_vertical_bar": "23f8-fe0f", "pause_button": "23f8-fe0f", "black_square_for_stop": "23f9-fe0f", "stop_button": "23f9-fe0f", "black_circle_for_record": "23fa-fe0f", "record_button": "23fa-fe0f", "eject": "23cf-fe0f", "cinema": "1f3a6", "low_brightness": "1f505", "high_brightness": "1f506", "signal_strength": "1f4f6", "vibration_mode": "1f4f3", "mobile_phone_off": "1f4f4", "female_sign": "2640-fe0f", "male_sign": "2642-fe0f", "transgender_symbol": "26a7-fe0f", "heavy_multiplication_x": "2716-fe0f", "heavy_plus_sign": "2795", "heavy_minus_sign": "2796", "heavy_division_sign": "2797", "infinity": "267e-fe0f", "bangbang": "203c-fe0f", "interrobang": "2049-fe0f", "question": "2753", "grey_question": "2754", "grey_exclamation": "2755", "exclamation": "2757", "heavy_exclamation_mark": "2757", "wavy_dash": "3030-fe0f", "currency_exchange": "1f4b1", "heavy_dollar_sign": "1f4b2", "medical_symbol": "2695-fe0f", "staff_of_aesculapius": "2695-fe0f", "recycle": "267b-fe0f", "fleur_de_lis": "269c-fe0f", "trident": "1f531", "name_badge": "1f4db", "beginner": "1f530", "o": "2b55", "white_check_mark": "2705", "ballot_box_with_check": "2611-fe0f", "heavy_check_mark": "2714-fe0f", "x": "274c", "negative_squared_cross_mark": "274e", "curly_loop": "27b0", "loop": "27bf", "part_alternation_mark": "303d-fe0f", "eight_spoked_asterisk": "2733-fe0f", "eight_pointed_black_star": "2734-fe0f", "sparkle": "2747-fe0f", "copyright": "00a9-fe0f", "registered": "00ae-fe0f", "tm": "2122-fe0f", "hash": "0023-fe0f-20e3", "keycap_star": "002a-fe0f-20e3", "asterisk": "002a-fe0f-20e3", "zero": "0030-fe0f-20e3", "one": "0031-fe0f-20e3", "two": "0032-fe0f-20e3", "three": "0033-fe0f-20e3", "four": "0034-fe0f-20e3", "five": "0035-fe0f-20e3", "six": "0036-fe0f-20e3", "seven": "0037-fe0f-20e3", "eight": "0038-fe0f-20e3", "nine": "0039-fe0f-20e3", "keycap_ten": "1f51f", "capital_abcd": "1f520", "abcd": "1f521", "1234": "1f522", "symbols": "1f523", "abc": "1f524", "a": "1f170-fe0f", "ab": "1f18e", "b": "1f171-fe0f", "cl": "1f191", "cool": "1f192", "free": "1f193", "information_source": "2139-fe0f", "id": "1f194", "m": "24c2-fe0f", "new": "1f195", "ng": "1f196", "o2": "1f17e-fe0f", "ok": "1f197", "parking": "1f17f-fe0f", "sos": "1f198", "up": "1f199", "vs": "1f19a", "koko": "1f201", "sa": "1f202-fe0f", "u6708": "1f237-fe0f", "u6709": "1f236", "u6307": "1f22f", "ideograph_advantage": "1f250", "u5272": "1f239", "u7121": "1f21a", "u7981": "1f232", "accept": "1f251", "u7533": "1f238", "u5408": "1f234", "u7a7a": "1f233", "congratulations": "3297-fe0f", "secret": "3299-fe0f", "u55b6": "1f23a", "u6e80": "1f235", "red_circle": "1f534", "large_orange_circle": "1f7e0", "large_yellow_circle": "1f7e1", "large_green_circle": "1f7e2", "large_blue_circle": "1f535", "large_purple_circle": "1f7e3", "large_brown_circle": "1f7e4", "black_circle": "26ab", "white_circle": "26aa", "large_red_square": "1f7e5", "large_orange_square": "1f7e7", "large_yellow_square": "1f7e8", "large_green_square": "1f7e9", "large_blue_square": "1f7e6", "large_purple_square": "1f7ea", "large_brown_square": "1f7eb", "black_large_square": "2b1b", "white_large_square": "2b1c", "black_medium_square": "25fc-fe0f", "white_medium_square": "25fb-fe0f", "black_medium_small_square": "25fe", "white_medium_small_square": "25fd", "black_small_square": "25aa-fe0f", "white_small_square": "25ab-fe0f", "large_orange_diamond": "1f536", "large_blue_diamond": "1f537", "small_orange_diamond": "1f538", "small_blue_diamond": "1f539", "small_red_triangle": "1f53a", "small_red_triangle_down": "1f53b", "diamond_shape_with_a_dot_inside": "1f4a0", "radio_button": "1f518", "white_square_button": "1f533", "black_square_button": "1f532", "checkered_flag": "1f3c1", "triangular_flag_on_post": "1f6a9", "crossed_flags": "1f38c", "waving_black_flag": "1f3f4", "black_flag": "1f3f4", "waving_white_flag": "1f3f3-fe0f", "white_flag": "1f3f3-fe0f", "rainbow-flag": "1f3f3-fe0f-200d-1f308", "rainbow_flag": "1f3f3-fe0f-200d-1f308", "transgender_flag": "1f3f3-fe0f-200d-26a7-fe0f", "pirate_flag": "1f3f4-200d-2620-fe0f", "flag-ac": "1f1e6-1f1e8", "flag-ad": "1f1e6-1f1e9", "andorra": "1f1e6-1f1e9", "flag-ae": "1f1e6-1f1ea", "united_arab_emirates": "1f1e6-1f1ea", "flag-af": "1f1e6-1f1eb", "afghanistan": "1f1e6-1f1eb", "flag-ag": "1f1e6-1f1ec", "antigua_barbuda": "1f1e6-1f1ec", "flag-ai": "1f1e6-1f1ee", "anguilla": "1f1e6-1f1ee", "flag-al": "1f1e6-1f1f1", "albania": "1f1e6-1f1f1", "flag-am": "1f1e6-1f1f2", "armenia": "1f1e6-1f1f2", "flag-ao": "1f1e6-1f1f4", "angola": "1f1e6-1f1f4", "flag-aq": "1f1e6-1f1f6", "antarctica": "1f1e6-1f1f6", "flag-ar": "1f1e6-1f1f7", "argentina": "1f1e6-1f1f7", "flag-as": "1f1e6-1f1f8", "american_samoa": "1f1e6-1f1f8", "flag-at": "1f1e6-1f1f9", "austria": "1f1e6-1f1f9", "flag-au": "1f1e6-1f1fa", "australia": "1f1e6-1f1fa", "flag-aw": "1f1e6-1f1fc", "aruba": "1f1e6-1f1fc", "flag-ax": "1f1e6-1f1fd", "aland_islands": "1f1e6-1f1fd", "flag-az": "1f1e6-1f1ff", "azerbaijan": "1f1e6-1f1ff", "flag-ba": "1f1e7-1f1e6", "bosnia_herzegovina": "1f1e7-1f1e6", "flag-bb": "1f1e7-1f1e7", "barbados": "1f1e7-1f1e7", "flag-bd": "1f1e7-1f1e9", "bangladesh": "1f1e7-1f1e9", "flag-be": "1f1e7-1f1ea", "belgium": "1f1e7-1f1ea", "flag-bf": "1f1e7-1f1eb", "burkina_faso": "1f1e7-1f1eb", "flag-bg": "1f1e7-1f1ec", "bulgaria": "1f1e7-1f1ec", "flag-bh": "1f1e7-1f1ed", "bahrain": "1f1e7-1f1ed", "flag-bi": "1f1e7-1f1ee", "burundi": "1f1e7-1f1ee", "flag-bj": "1f1e7-1f1ef", "benin": "1f1e7-1f1ef", "flag-bl": "1f1e7-1f1f1", "st_barthelemy": "1f1e7-1f1f1", "flag-bm": "1f1e7-1f1f2", "bermuda": "1f1e7-1f1f2", "flag-bn": "1f1e7-1f1f3", "brunei": "1f1e7-1f1f3", "flag-bo": "1f1e7-1f1f4", "bolivia": "1f1e7-1f1f4", "flag-bq": "1f1e7-1f1f6", "caribbean_netherlands": "1f1e7-1f1f6", "flag-br": "1f1e7-1f1f7", "brazil": "1f1e7-1f1f7", "flag-bs": "1f1e7-1f1f8", "bahamas": "1f1e7-1f1f8", "flag-bt": "1f1e7-1f1f9", "bhutan": "1f1e7-1f1f9", "flag-bv": "1f1e7-1f1fb", "flag-bw": "1f1e7-1f1fc", "botswana": "1f1e7-1f1fc", "flag-by": "1f1e7-1f1fe", "belarus": "1f1e7-1f1fe", "flag-bz": "1f1e7-1f1ff", "belize": "1f1e7-1f1ff", "flag-ca": "1f1e8-1f1e6", "ca": "1f1e8-1f1e6", "canada": "1f1e8-1f1e6", "flag-cc": "1f1e8-1f1e8", "cocos_islands": "1f1e8-1f1e8", "flag-cd": "1f1e8-1f1e9", "congo_kinshasa": "1f1e8-1f1e9", "flag-cf": "1f1e8-1f1eb", "central_african_republic": "1f1e8-1f1eb", "flag-cg": "1f1e8-1f1ec", "congo_brazzaville": "1f1e8-1f1ec", "flag-ch": "1f1e8-1f1ed", "switzerland": "1f1e8-1f1ed", "flag-ci": "1f1e8-1f1ee", "cote_divoire": "1f1e8-1f1ee", "flag-ck": "1f1e8-1f1f0", "cook_islands": "1f1e8-1f1f0", "flag-cl": "1f1e8-1f1f1", "chile": "1f1e8-1f1f1", "flag-cm": "1f1e8-1f1f2", "cameroon": "1f1e8-1f1f2", "cn": "1f1e8-1f1f3", "flag-cn": "1f1e8-1f1f3", "flag-co": "1f1e8-1f1f4", "colombia": "1f1e8-1f1f4", "flag-cp": "1f1e8-1f1f5", "flag-cr": "1f1e8-1f1f7", "costa_rica": "1f1e8-1f1f7", "flag-cu": "1f1e8-1f1fa", "cuba": "1f1e8-1f1fa", "flag-cv": "1f1e8-1f1fb", "cape_verde": "1f1e8-1f1fb", "flag-cw": "1f1e8-1f1fc", "curacao": "1f1e8-1f1fc", "flag-cx": "1f1e8-1f1fd", "christmas_island": "1f1e8-1f1fd", "flag-cy": "1f1e8-1f1fe", "cyprus": "1f1e8-1f1fe", "flag-cz": "1f1e8-1f1ff", "czech_republic": "1f1e8-1f1ff", "de": "1f1e9-1f1ea", "flag-de": "1f1e9-1f1ea", "flag-dg": "1f1e9-1f1ec", "flag-dj": "1f1e9-1f1ef", "djibouti": "1f1e9-1f1ef", "flag-dk": "1f1e9-1f1f0", "denmark": "1f1e9-1f1f0", "flag-dm": "1f1e9-1f1f2", "dominica": "1f1e9-1f1f2", "flag-do": "1f1e9-1f1f4", "dominican_republic": "1f1e9-1f1f4", "flag-dz": "1f1e9-1f1ff", "algeria": "1f1e9-1f1ff", "flag-ea": "1f1ea-1f1e6", "flag-ec": "1f1ea-1f1e8", "ecuador": "1f1ea-1f1e8", "flag-ee": "1f1ea-1f1ea", "estonia": "1f1ea-1f1ea", "flag-eg": "1f1ea-1f1ec", "egypt": "1f1ea-1f1ec", "flag-eh": "1f1ea-1f1ed", "western_sahara": "1f1ea-1f1ed", "flag-er": "1f1ea-1f1f7", "eritrea": "1f1ea-1f1f7", "es": "1f1ea-1f1f8", "flag-es": "1f1ea-1f1f8", "flag-et": "1f1ea-1f1f9", "ethiopia": "1f1ea-1f1f9", "flag-eu": "1f1ea-1f1fa", "eu": "1f1ea-1f1fa", "european_union": "1f1ea-1f1fa", "flag-fi": "1f1eb-1f1ee", "finland": "1f1eb-1f1ee", "flag-fj": "1f1eb-1f1ef", "fiji": "1f1eb-1f1ef", "flag-fk": "1f1eb-1f1f0", "falkland_islands": "1f1eb-1f1f0", "flag-fm": "1f1eb-1f1f2", "micronesia": "1f1eb-1f1f2", "flag-fo": "1f1eb-1f1f4", "faroe_islands": "1f1eb-1f1f4", "fr": "1f1eb-1f1f7", "flag-fr": "1f1eb-1f1f7", "flag-ga": "1f1ec-1f1e6", "gabon": "1f1ec-1f1e6", "gb": "1f1ec-1f1e7", "uk": "1f1ec-1f1e7", "flag-gb": "1f1ec-1f1e7", "flag-gd": "1f1ec-1f1e9", "grenada": "1f1ec-1f1e9", "flag-ge": "1f1ec-1f1ea", "georgia": "1f1ec-1f1ea", "flag-gf": "1f1ec-1f1eb", "french_guiana": "1f1ec-1f1eb", "flag-gg": "1f1ec-1f1ec", "guernsey": "1f1ec-1f1ec", "flag-gh": "1f1ec-1f1ed", "ghana": "1f1ec-1f1ed", "flag-gi": "1f1ec-1f1ee", "gibraltar": "1f1ec-1f1ee", "flag-gl": "1f1ec-1f1f1", "greenland": "1f1ec-1f1f1", "flag-gm": "1f1ec-1f1f2", "gambia": "1f1ec-1f1f2", "flag-gn": "1f1ec-1f1f3", "guinea": "1f1ec-1f1f3", "flag-gp": "1f1ec-1f1f5", "guadeloupe": "1f1ec-1f1f5", "flag-gq": "1f1ec-1f1f6", "equatorial_guinea": "1f1ec-1f1f6", "flag-gr": "1f1ec-1f1f7", "greece": "1f1ec-1f1f7", "flag-gs": "1f1ec-1f1f8", "south_georgia_south_sandwich_islands": "1f1ec-1f1f8", "flag-gt": "1f1ec-1f1f9", "guatemala": "1f1ec-1f1f9", "flag-gu": "1f1ec-1f1fa", "guam": "1f1ec-1f1fa", "flag-gw": "1f1ec-1f1fc", "guinea_bissau": "1f1ec-1f1fc", "flag-gy": "1f1ec-1f1fe", "guyana": "1f1ec-1f1fe", "flag-hk": "1f1ed-1f1f0", "hong_kong": "1f1ed-1f1f0", "flag-hm": "1f1ed-1f1f2", "flag-hn": "1f1ed-1f1f3", "honduras": "1f1ed-1f1f3", "flag-hr": "1f1ed-1f1f7", "croatia": "1f1ed-1f1f7", "flag-ht": "1f1ed-1f1f9", "haiti": "1f1ed-1f1f9", "flag-hu": "1f1ed-1f1fa", "hungary": "1f1ed-1f1fa", "flag-ic": "1f1ee-1f1e8", "canary_islands": "1f1ee-1f1e8", "flag-id": "1f1ee-1f1e9", "indonesia": "1f1ee-1f1e9", "flag-ie": "1f1ee-1f1ea", "ireland": "1f1ee-1f1ea", "flag-il": "1f1ee-1f1f1", "israel": "1f1ee-1f1f1", "flag-im": "1f1ee-1f1f2", "isle_of_man": "1f1ee-1f1f2", "flag-in": "1f1ee-1f1f3", "india": "1f1ee-1f1f3", "flag-io": "1f1ee-1f1f4", "british_indian_ocean_territory": "1f1ee-1f1f4", "flag-iq": "1f1ee-1f1f6", "iraq": "1f1ee-1f1f6", "flag-ir": "1f1ee-1f1f7", "iran": "1f1ee-1f1f7", "flag-is": "1f1ee-1f1f8", "iceland": "1f1ee-1f1f8", "it": "1f1ee-1f1f9", "flag-it": "1f1ee-1f1f9", "flag-je": "1f1ef-1f1ea", "jersey": "1f1ef-1f1ea", "flag-jm": "1f1ef-1f1f2", "jamaica": "1f1ef-1f1f2", "flag-jo": "1f1ef-1f1f4", "jordan": "1f1ef-1f1f4", "jp": "1f1ef-1f1f5", "flag-jp": "1f1ef-1f1f5", "flag-ke": "1f1f0-1f1ea", "kenya": "1f1f0-1f1ea", "flag-kg": "1f1f0-1f1ec", "kyrgyzstan": "1f1f0-1f1ec", "flag-kh": "1f1f0-1f1ed", "cambodia": "1f1f0-1f1ed", "flag-ki": "1f1f0-1f1ee", "kiribati": "1f1f0-1f1ee", "flag-km": "1f1f0-1f1f2", "comoros": "1f1f0-1f1f2", "flag-kn": "1f1f0-1f1f3", "st_kitts_nevis": "1f1f0-1f1f3", "flag-kp": "1f1f0-1f1f5", "north_korea": "1f1f0-1f1f5", "kr": "1f1f0-1f1f7", "flag-kr": "1f1f0-1f1f7", "flag-kw": "1f1f0-1f1fc", "kuwait": "1f1f0-1f1fc", "flag-ky": "1f1f0-1f1fe", "cayman_islands": "1f1f0-1f1fe", "flag-kz": "1f1f0-1f1ff", "kazakhstan": "1f1f0-1f1ff", "flag-la": "1f1f1-1f1e6", "laos": "1f1f1-1f1e6", "flag-lb": "1f1f1-1f1e7", "lebanon": "1f1f1-1f1e7", "flag-lc": "1f1f1-1f1e8", "st_lucia": "1f1f1-1f1e8", "flag-li": "1f1f1-1f1ee", "liechtenstein": "1f1f1-1f1ee", "flag-lk": "1f1f1-1f1f0", "sri_lanka": "1f1f1-1f1f0", "flag-lr": "1f1f1-1f1f7", "liberia": "1f1f1-1f1f7", "flag-ls": "1f1f1-1f1f8", "lesotho": "1f1f1-1f1f8", "flag-lt": "1f1f1-1f1f9", "lithuania": "1f1f1-1f1f9", "flag-lu": "1f1f1-1f1fa", "luxembourg": "1f1f1-1f1fa", "flag-lv": "1f1f1-1f1fb", "latvia": "1f1f1-1f1fb", "flag-ly": "1f1f1-1f1fe", "libya": "1f1f1-1f1fe", "flag-ma": "1f1f2-1f1e6", "morocco": "1f1f2-1f1e6", "flag-mc": "1f1f2-1f1e8", "monaco": "1f1f2-1f1e8", "flag-md": "1f1f2-1f1e9", "moldova": "1f1f2-1f1e9", "flag-me": "1f1f2-1f1ea", "montenegro": "1f1f2-1f1ea", "flag-mf": "1f1f2-1f1eb", "flag-mg": "1f1f2-1f1ec", "madagascar": "1f1f2-1f1ec", "flag-mh": "1f1f2-1f1ed", "marshall_islands": "1f1f2-1f1ed", "flag-mk": "1f1f2-1f1f0", "macedonia": "1f1f2-1f1f0", "flag-ml": "1f1f2-1f1f1", "mali": "1f1f2-1f1f1", "flag-mm": "1f1f2-1f1f2", "myanmar": "1f1f2-1f1f2", "flag-mn": "1f1f2-1f1f3", "mongolia": "1f1f2-1f1f3", "flag-mo": "1f1f2-1f1f4", "macau": "1f1f2-1f1f4", "flag-mp": "1f1f2-1f1f5", "northern_mariana_islands": "1f1f2-1f1f5", "flag-mq": "1f1f2-1f1f6", "martinique": "1f1f2-1f1f6", "flag-mr": "1f1f2-1f1f7", "mauritania": "1f1f2-1f1f7", "flag-ms": "1f1f2-1f1f8", "montserrat": "1f1f2-1f1f8", "flag-mt": "1f1f2-1f1f9", "malta": "1f1f2-1f1f9", "flag-mu": "1f1f2-1f1fa", "mauritius": "1f1f2-1f1fa", "flag-mv": "1f1f2-1f1fb", "maldives": "1f1f2-1f1fb", "flag-mw": "1f1f2-1f1fc", "malawi": "1f1f2-1f1fc", "flag-mx": "1f1f2-1f1fd", "mexico": "1f1f2-1f1fd", "flag-my": "1f1f2-1f1fe", "malaysia": "1f1f2-1f1fe", "flag-mz": "1f1f2-1f1ff", "mozambique": "1f1f2-1f1ff", "flag-na": "1f1f3-1f1e6", "namibia": "1f1f3-1f1e6", "flag-nc": "1f1f3-1f1e8", "new_caledonia": "1f1f3-1f1e8", "flag-ne": "1f1f3-1f1ea", "niger": "1f1f3-1f1ea", "flag-nf": "1f1f3-1f1eb", "norfolk_island": "1f1f3-1f1eb", "flag-ng": "1f1f3-1f1ec", "nigeria": "1f1f3-1f1ec", "flag-ni": "1f1f3-1f1ee", "nicaragua": "1f1f3-1f1ee", "flag-nl": "1f1f3-1f1f1", "netherlands": "1f1f3-1f1f1", "flag-no": "1f1f3-1f1f4", "norway": "1f1f3-1f1f4", "flag-np": "1f1f3-1f1f5", "nepal": "1f1f3-1f1f5", "flag-nr": "1f1f3-1f1f7", "nauru": "1f1f3-1f1f7", "flag-nu": "1f1f3-1f1fa", "niue": "1f1f3-1f1fa", "flag-nz": "1f1f3-1f1ff", "new_zealand": "1f1f3-1f1ff", "flag-om": "1f1f4-1f1f2", "oman": "1f1f4-1f1f2", "flag-pa": "1f1f5-1f1e6", "panama": "1f1f5-1f1e6", "flag-pe": "1f1f5-1f1ea", "peru": "1f1f5-1f1ea", "flag-pf": "1f1f5-1f1eb", "french_polynesia": "1f1f5-1f1eb", "flag-pg": "1f1f5-1f1ec", "papua_new_guinea": "1f1f5-1f1ec", "flag-ph": "1f1f5-1f1ed", "philippines": "1f1f5-1f1ed", "flag-pk": "1f1f5-1f1f0", "pakistan": "1f1f5-1f1f0", "pk": "1f1f5-1f1f0", "flag-pl": "1f1f5-1f1f1", "poland": "1f1f5-1f1f1", "flag-pm": "1f1f5-1f1f2", "st_pierre_miquelon": "1f1f5-1f1f2", "flag-pn": "1f1f5-1f1f3", "pitcairn_islands": "1f1f5-1f1f3", "flag-pr": "1f1f5-1f1f7", "puerto_rico": "1f1f5-1f1f7", "flag-ps": "1f1f5-1f1f8", "palestinian_territories": "1f1f5-1f1f8", "flag-pt": "1f1f5-1f1f9", "portugal": "1f1f5-1f1f9", "flag-pw": "1f1f5-1f1fc", "palau": "1f1f5-1f1fc", "flag-py": "1f1f5-1f1fe", "paraguay": "1f1f5-1f1fe", "flag-qa": "1f1f6-1f1e6", "qatar": "1f1f6-1f1e6", "flag-re": "1f1f7-1f1ea", "reunion": "1f1f7-1f1ea", "flag-ro": "1f1f7-1f1f4", "romania": "1f1f7-1f1f4", "flag-rs": "1f1f7-1f1f8", "serbia": "1f1f7-1f1f8", "ru": "1f1f7-1f1fa", "flag-ru": "1f1f7-1f1fa", "flag-rw": "1f1f7-1f1fc", "rwanda": "1f1f7-1f1fc", "flag-sa": "1f1f8-1f1e6", "saudi_arabia": "1f1f8-1f1e6", "flag-sb": "1f1f8-1f1e7", "solomon_islands": "1f1f8-1f1e7", "flag-sc": "1f1f8-1f1e8", "seychelles": "1f1f8-1f1e8", "flag-sd": "1f1f8-1f1e9", "sudan": "1f1f8-1f1e9", "flag-se": "1f1f8-1f1ea", "sweden": "1f1f8-1f1ea", "flag-sg": "1f1f8-1f1ec", "singapore": "1f1f8-1f1ec", "flag-sh": "1f1f8-1f1ed", "st_helena": "1f1f8-1f1ed", "flag-si": "1f1f8-1f1ee", "slovenia": "1f1f8-1f1ee", "flag-sj": "1f1f8-1f1ef", "flag-sk": "1f1f8-1f1f0", "slovakia": "1f1f8-1f1f0", "flag-sl": "1f1f8-1f1f1", "sierra_leone": "1f1f8-1f1f1", "flag-sm": "1f1f8-1f1f2", "san_marino": "1f1f8-1f1f2", "flag-sn": "1f1f8-1f1f3", "senegal": "1f1f8-1f1f3", "flag-so": "1f1f8-1f1f4", "somalia": "1f1f8-1f1f4", "flag-sr": "1f1f8-1f1f7", "suriname": "1f1f8-1f1f7", "flag-ss": "1f1f8-1f1f8", "south_sudan": "1f1f8-1f1f8", "flag-st": "1f1f8-1f1f9", "sao_tome_principe": "1f1f8-1f1f9", "flag-sv": "1f1f8-1f1fb", "el_salvador": "1f1f8-1f1fb", "flag-sx": "1f1f8-1f1fd", "sint_maarten": "1f1f8-1f1fd", "flag-sy": "1f1f8-1f1fe", "syria": "1f1f8-1f1fe", "flag-sz": "1f1f8-1f1ff", "swaziland": "1f1f8-1f1ff", "flag-ta": "1f1f9-1f1e6", "flag-tc": "1f1f9-1f1e8", "turks_caicos_islands": "1f1f9-1f1e8", "flag-td": "1f1f9-1f1e9", "chad": "1f1f9-1f1e9", "flag-tf": "1f1f9-1f1eb", "french_southern_territories": "1f1f9-1f1eb", "flag-tg": "1f1f9-1f1ec", "togo": "1f1f9-1f1ec", "flag-th": "1f1f9-1f1ed", "thailand": "1f1f9-1f1ed", "flag-tj": "1f1f9-1f1ef", "tajikistan": "1f1f9-1f1ef", "flag-tk": "1f1f9-1f1f0", "tokelau": "1f1f9-1f1f0", "flag-tl": "1f1f9-1f1f1", "timor_leste": "1f1f9-1f1f1", "flag-tm": "1f1f9-1f1f2", "turkmenistan": "1f1f9-1f1f2", "flag-tn": "1f1f9-1f1f3", "tunisia": "1f1f9-1f1f3", "flag-to": "1f1f9-1f1f4", "tonga": "1f1f9-1f1f4", "flag-tr": "1f1f9-1f1f7", "tr": "1f1f9-1f1f7", "flag-tt": "1f1f9-1f1f9", "trinidad_tobago": "1f1f9-1f1f9", "flag-tv": "1f1f9-1f1fb", "tuvalu": "1f1f9-1f1fb", "flag-tw": "1f1f9-1f1fc", "taiwan": "1f1f9-1f1fc", "flag-tz": "1f1f9-1f1ff", "tanzania": "1f1f9-1f1ff", "flag-ua": "1f1fa-1f1e6", "ukraine": "1f1fa-1f1e6", "flag-ug": "1f1fa-1f1ec", "uganda": "1f1fa-1f1ec", "flag-um": "1f1fa-1f1f2", "flag-un": "1f1fa-1f1f3", "us": "1f1fa-1f1f8", "flag-us": "1f1fa-1f1f8", "flag-uy": "1f1fa-1f1fe", "uruguay": "1f1fa-1f1fe", "flag-uz": "1f1fa-1f1ff", "uzbekistan": "1f1fa-1f1ff", "flag-va": "1f1fb-1f1e6", "vatican_city": "1f1fb-1f1e6", "flag-vc": "1f1fb-1f1e8", "st_vincent_grenadines": "1f1fb-1f1e8", "flag-ve": "1f1fb-1f1ea", "venezuela": "1f1fb-1f1ea", "flag-vg": "1f1fb-1f1ec", "british_virgin_islands": "1f1fb-1f1ec", "flag-vi": "1f1fb-1f1ee", "us_virgin_islands": "1f1fb-1f1ee", "flag-vn": "1f1fb-1f1f3", "vietnam": "1f1fb-1f1f3", "flag-vu": "1f1fb-1f1fa", "vanuatu": "1f1fb-1f1fa", "flag-wf": "1f1fc-1f1eb", "wallis_futuna": "1f1fc-1f1eb", "flag-ws": "1f1fc-1f1f8", "samoa": "1f1fc-1f1f8", "flag-xk": "1f1fd-1f1f0", "kosovo": "1f1fd-1f1f0", "flag-ye": "1f1fe-1f1ea", "yemen": "1f1fe-1f1ea", "flag-yt": "1f1fe-1f1f9", "mayotte": "1f1fe-1f1f9", "flag-za": "1f1ff-1f1e6", "south_africa": "1f1ff-1f1e6", "za": "1f1ff-1f1e6", "flag-zm": "1f1ff-1f1f2", "zambia": "1f1ff-1f1f2", "flag-zw": "1f1ff-1f1fc", "zimbabwe": "1f1ff-1f1fc", "flag-england": "1f3f4-e0067-e0062-e0065-e006e-e0067-e007f", "flag-scotland": "1f3f4-e0067-e0062-e0073-e0063-e0074-e007f", "flag-wales": "1f3f4-e0067-e0062-e0077-e006c-e0073-e007f", "santa_light_skin_tone": "1f385-1f3fb", "santa_medium_light_skin_tone": "1f385-1f3fc", "santa_medium_skin_tone": "1f385-1f3fd", "santa_medium_dark_skin_tone": "1f385-1f3fe", "santa_dark_skin_tone": "1f385-1f3ff", "snowboarder_light_skin_tone": "1f3c2-1f3fb", "snowboarder_medium_light_skin_tone": "1f3c2-1f3fc", "snowboarder_medium_skin_tone": "1f3c2-1f3fd", "snowboarder_medium_dark_skin_tone": "1f3c2-1f3fe", "snowboarder_dark_skin_tone": "1f3c2-1f3ff", "woman-running_light_skin_tone": "1f3c3-1f3fb-200d-2640-fe0f", "running_woman_light_skin_tone": "1f3c3-1f3fb-200d-2640-fe0f", "woman-running_medium_light_skin_tone": "1f3c3-1f3fc-200d-2640-fe0f", "running_woman_medium_light_skin_tone": "1f3c3-1f3fc-200d-2640-fe0f", "woman-running_medium_skin_tone": "1f3c3-1f3fd-200d-2640-fe0f", "running_woman_medium_skin_tone": "1f3c3-1f3fd-200d-2640-fe0f", "woman-running_medium_dark_skin_tone": "1f3c3-1f3fe-200d-2640-fe0f", "running_woman_medium_dark_skin_tone": "1f3c3-1f3fe-200d-2640-fe0f", "woman-running_dark_skin_tone": "1f3c3-1f3ff-200d-2640-fe0f", "running_woman_dark_skin_tone": "1f3c3-1f3ff-200d-2640-fe0f", "man-running_light_skin_tone": "1f3c3-1f3fb-200d-2642-fe0f", "running_man_light_skin_tone": "1f3c3-1f3fb-200d-2642-fe0f", "man-running_medium_light_skin_tone": "1f3c3-1f3fc-200d-2642-fe0f", "running_man_medium_light_skin_tone": "1f3c3-1f3fc-200d-2642-fe0f", "man-running_medium_skin_tone": "1f3c3-1f3fd-200d-2642-fe0f", "running_man_medium_skin_tone": "1f3c3-1f3fd-200d-2642-fe0f", "man-running_medium_dark_skin_tone": "1f3c3-1f3fe-200d-2642-fe0f", "running_man_medium_dark_skin_tone": "1f3c3-1f3fe-200d-2642-fe0f", "man-running_dark_skin_tone": "1f3c3-1f3ff-200d-2642-fe0f", "running_man_dark_skin_tone": "1f3c3-1f3ff-200d-2642-fe0f", "runner_light_skin_tone": "1f3c3-1f3fb", "running_light_skin_tone": "1f3c3-1f3fb", "runner_medium_light_skin_tone": "1f3c3-1f3fc", "running_medium_light_skin_tone": "1f3c3-1f3fc", "runner_medium_skin_tone": "1f3c3-1f3fd", "running_medium_skin_tone": "1f3c3-1f3fd", "runner_medium_dark_skin_tone": "1f3c3-1f3fe", "running_medium_dark_skin_tone": "1f3c3-1f3fe", "runner_dark_skin_tone": "1f3c3-1f3ff", "running_dark_skin_tone": "1f3c3-1f3ff", "woman-surfing_light_skin_tone": "1f3c4-1f3fb-200d-2640-fe0f", "surfing_woman_light_skin_tone": "1f3c4-1f3fb-200d-2640-fe0f", "woman-surfing_medium_light_skin_tone": "1f3c4-1f3fc-200d-2640-fe0f", "surfing_woman_medium_light_skin_tone": "1f3c4-1f3fc-200d-2640-fe0f", "woman-surfing_medium_skin_tone": "1f3c4-1f3fd-200d-2640-fe0f", "surfing_woman_medium_skin_tone": "1f3c4-1f3fd-200d-2640-fe0f", "woman-surfing_medium_dark_skin_tone": "1f3c4-1f3fe-200d-2640-fe0f", "surfing_woman_medium_dark_skin_tone": "1f3c4-1f3fe-200d-2640-fe0f", "woman-surfing_dark_skin_tone": "1f3c4-1f3ff-200d-2640-fe0f", "surfing_woman_dark_skin_tone": "1f3c4-1f3ff-200d-2640-fe0f", "man-surfing_light_skin_tone": "1f3c4-1f3fb-200d-2642-fe0f", "surfing_man_light_skin_tone": "1f3c4-1f3fb-200d-2642-fe0f", "man-surfing_medium_light_skin_tone": "1f3c4-1f3fc-200d-2642-fe0f", "surfing_man_medium_light_skin_tone": "1f3c4-1f3fc-200d-2642-fe0f", "man-surfing_medium_skin_tone": "1f3c4-1f3fd-200d-2642-fe0f", "surfing_man_medium_skin_tone": "1f3c4-1f3fd-200d-2642-fe0f", "man-surfing_medium_dark_skin_tone": "1f3c4-1f3fe-200d-2642-fe0f", "surfing_man_medium_dark_skin_tone": "1f3c4-1f3fe-200d-2642-fe0f", "man-surfing_dark_skin_tone": "1f3c4-1f3ff-200d-2642-fe0f", "surfing_man_dark_skin_tone": "1f3c4-1f3ff-200d-2642-fe0f", "surfer_light_skin_tone": "1f3c4-1f3fb", "surfer_medium_light_skin_tone": "1f3c4-1f3fc", "surfer_medium_skin_tone": "1f3c4-1f3fd", "surfer_medium_dark_skin_tone": "1f3c4-1f3fe", "surfer_dark_skin_tone": "1f3c4-1f3ff", "horse_racing_light_skin_tone": "1f3c7-1f3fb", "horse_racing_medium_light_skin_tone": "1f3c7-1f3fc", "horse_racing_medium_skin_tone": "1f3c7-1f3fd", "horse_racing_medium_dark_skin_tone": "1f3c7-1f3fe", "horse_racing_dark_skin_tone": "1f3c7-1f3ff", "woman-swimming_light_skin_tone": "1f3ca-1f3fb-200d-2640-fe0f", "swimming_woman_light_skin_tone": "1f3ca-1f3fb-200d-2640-fe0f", "woman-swimming_medium_light_skin_tone": "1f3ca-1f3fc-200d-2640-fe0f", "swimming_woman_medium_light_skin_tone": "1f3ca-1f3fc-200d-2640-fe0f", "woman-swimming_medium_skin_tone": "1f3ca-1f3fd-200d-2640-fe0f", "swimming_woman_medium_skin_tone": "1f3ca-1f3fd-200d-2640-fe0f", "woman-swimming_medium_dark_skin_tone": "1f3ca-1f3fe-200d-2640-fe0f", "swimming_woman_medium_dark_skin_tone": "1f3ca-1f3fe-200d-2640-fe0f", "woman-swimming_dark_skin_tone": "1f3ca-1f3ff-200d-2640-fe0f", "swimming_woman_dark_skin_tone": "1f3ca-1f3ff-200d-2640-fe0f", "man-swimming_light_skin_tone": "1f3ca-1f3fb-200d-2642-fe0f", "swimming_man_light_skin_tone": "1f3ca-1f3fb-200d-2642-fe0f", "man-swimming_medium_light_skin_tone": "1f3ca-1f3fc-200d-2642-fe0f", "swimming_man_medium_light_skin_tone": "1f3ca-1f3fc-200d-2642-fe0f", "man-swimming_medium_skin_tone": "1f3ca-1f3fd-200d-2642-fe0f", "swimming_man_medium_skin_tone": "1f3ca-1f3fd-200d-2642-fe0f", "man-swimming_medium_dark_skin_tone": "1f3ca-1f3fe-200d-2642-fe0f", "swimming_man_medium_dark_skin_tone": "1f3ca-1f3fe-200d-2642-fe0f", "man-swimming_dark_skin_tone": "1f3ca-1f3ff-200d-2642-fe0f", "swimming_man_dark_skin_tone": "1f3ca-1f3ff-200d-2642-fe0f", "swimmer_light_skin_tone": "1f3ca-1f3fb", "swimmer_medium_light_skin_tone": "1f3ca-1f3fc", "swimmer_medium_skin_tone": "1f3ca-1f3fd", "swimmer_medium_dark_skin_tone": "1f3ca-1f3fe", "swimmer_dark_skin_tone": "1f3ca-1f3ff", "woman-lifting-weights_light_skin_tone": "1f3cb-1f3fb-200d-2640-fe0f", "weight_lifting_woman_light_skin_tone": "1f3cb-1f3fb-200d-2640-fe0f", "woman-lifting-weights_medium_light_skin_tone": "1f3cb-1f3fc-200d-2640-fe0f", "weight_lifting_woman_medium_light_skin_tone": "1f3cb-1f3fc-200d-2640-fe0f", "woman-lifting-weights_medium_skin_tone": "1f3cb-1f3fd-200d-2640-fe0f", "weight_lifting_woman_medium_skin_tone": "1f3cb-1f3fd-200d-2640-fe0f", "woman-lifting-weights_medium_dark_skin_tone": "1f3cb-1f3fe-200d-2640-fe0f", "weight_lifting_woman_medium_dark_skin_tone": "1f3cb-1f3fe-200d-2640-fe0f", "woman-lifting-weights_dark_skin_tone": "1f3cb-1f3ff-200d-2640-fe0f", "weight_lifting_woman_dark_skin_tone": "1f3cb-1f3ff-200d-2640-fe0f", "man-lifting-weights_light_skin_tone": "1f3cb-1f3fb-200d-2642-fe0f", "weight_lifting_man_light_skin_tone": "1f3cb-1f3fb-200d-2642-fe0f", "man-lifting-weights_medium_light_skin_tone": "1f3cb-1f3fc-200d-2642-fe0f", "weight_lifting_man_medium_light_skin_tone": "1f3cb-1f3fc-200d-2642-fe0f", "man-lifting-weights_medium_skin_tone": "1f3cb-1f3fd-200d-2642-fe0f", "weight_lifting_man_medium_skin_tone": "1f3cb-1f3fd-200d-2642-fe0f", "man-lifting-weights_medium_dark_skin_tone": "1f3cb-1f3fe-200d-2642-fe0f", "weight_lifting_man_medium_dark_skin_tone": "1f3cb-1f3fe-200d-2642-fe0f", "man-lifting-weights_dark_skin_tone": "1f3cb-1f3ff-200d-2642-fe0f", "weight_lifting_man_dark_skin_tone": "1f3cb-1f3ff-200d-2642-fe0f", "weight_lifter_light_skin_tone": "1f3cb-1f3fb", "weight_lifter_medium_light_skin_tone": "1f3cb-1f3fc", "weight_lifter_medium_skin_tone": "1f3cb-1f3fd", "weight_lifter_medium_dark_skin_tone": "1f3cb-1f3fe", "weight_lifter_dark_skin_tone": "1f3cb-1f3ff", "woman-golfing_light_skin_tone": "1f3cc-1f3fb-200d-2640-fe0f", "golfing_woman_light_skin_tone": "1f3cc-1f3fb-200d-2640-fe0f", "woman-golfing_medium_light_skin_tone": "1f3cc-1f3fc-200d-2640-fe0f", "golfing_woman_medium_light_skin_tone": "1f3cc-1f3fc-200d-2640-fe0f", "woman-golfing_medium_skin_tone": "1f3cc-1f3fd-200d-2640-fe0f", "golfing_woman_medium_skin_tone": "1f3cc-1f3fd-200d-2640-fe0f", "woman-golfing_medium_dark_skin_tone": "1f3cc-1f3fe-200d-2640-fe0f", "golfing_woman_medium_dark_skin_tone": "1f3cc-1f3fe-200d-2640-fe0f", "woman-golfing_dark_skin_tone": "1f3cc-1f3ff-200d-2640-fe0f", "golfing_woman_dark_skin_tone": "1f3cc-1f3ff-200d-2640-fe0f", "man-golfing_light_skin_tone": "1f3cc-1f3fb-200d-2642-fe0f", "golfing_man_light_skin_tone": "1f3cc-1f3fb-200d-2642-fe0f", "man-golfing_medium_light_skin_tone": "1f3cc-1f3fc-200d-2642-fe0f", "golfing_man_medium_light_skin_tone": "1f3cc-1f3fc-200d-2642-fe0f", "man-golfing_medium_skin_tone": "1f3cc-1f3fd-200d-2642-fe0f", "golfing_man_medium_skin_tone": "1f3cc-1f3fd-200d-2642-fe0f", "man-golfing_medium_dark_skin_tone": "1f3cc-1f3fe-200d-2642-fe0f", "golfing_man_medium_dark_skin_tone": "1f3cc-1f3fe-200d-2642-fe0f", "man-golfing_dark_skin_tone": "1f3cc-1f3ff-200d-2642-fe0f", "golfing_man_dark_skin_tone": "1f3cc-1f3ff-200d-2642-fe0f", "golfer_light_skin_tone": "1f3cc-1f3fb", "golfer_medium_light_skin_tone": "1f3cc-1f3fc", "golfer_medium_skin_tone": "1f3cc-1f3fd", "golfer_medium_dark_skin_tone": "1f3cc-1f3fe", "golfer_dark_skin_tone": "1f3cc-1f3ff", "ear_light_skin_tone": "1f442-1f3fb", "ear_medium_light_skin_tone": "1f442-1f3fc", "ear_medium_skin_tone": "1f442-1f3fd", "ear_medium_dark_skin_tone": "1f442-1f3fe", "ear_dark_skin_tone": "1f442-1f3ff", "nose_light_skin_tone": "1f443-1f3fb", "nose_medium_light_skin_tone": "1f443-1f3fc", "nose_medium_skin_tone": "1f443-1f3fd", "nose_medium_dark_skin_tone": "1f443-1f3fe", "nose_dark_skin_tone": "1f443-1f3ff", "point_up_2_light_skin_tone": "1f446-1f3fb", "point_up_2_medium_light_skin_tone": "1f446-1f3fc", "point_up_2_medium_skin_tone": "1f446-1f3fd", "point_up_2_medium_dark_skin_tone": "1f446-1f3fe", "point_up_2_dark_skin_tone": "1f446-1f3ff", "point_down_light_skin_tone": "1f447-1f3fb", "point_down_medium_light_skin_tone": "1f447-1f3fc", "point_down_medium_skin_tone": "1f447-1f3fd", "point_down_medium_dark_skin_tone": "1f447-1f3fe", "point_down_dark_skin_tone": "1f447-1f3ff", "point_left_light_skin_tone": "1f448-1f3fb", "point_left_medium_light_skin_tone": "1f448-1f3fc", "point_left_medium_skin_tone": "1f448-1f3fd", "point_left_medium_dark_skin_tone": "1f448-1f3fe", "point_left_dark_skin_tone": "1f448-1f3ff", "point_right_light_skin_tone": "1f449-1f3fb", "point_right_medium_light_skin_tone": "1f449-1f3fc", "point_right_medium_skin_tone": "1f449-1f3fd", "point_right_medium_dark_skin_tone": "1f449-1f3fe", "point_right_dark_skin_tone": "1f449-1f3ff", "facepunch_light_skin_tone": "1f44a-1f3fb", "punch_light_skin_tone": "1f44a-1f3fb", "fist_oncoming_light_skin_tone": "1f44a-1f3fb", "facepunch_medium_light_skin_tone": "1f44a-1f3fc", "punch_medium_light_skin_tone": "1f44a-1f3fc", "fist_oncoming_medium_light_skin_tone": "1f44a-1f3fc", "facepunch_medium_skin_tone": "1f44a-1f3fd", "punch_medium_skin_tone": "1f44a-1f3fd", "fist_oncoming_medium_skin_tone": "1f44a-1f3fd", "facepunch_medium_dark_skin_tone": "1f44a-1f3fe", "punch_medium_dark_skin_tone": "1f44a-1f3fe", "fist_oncoming_medium_dark_skin_tone": "1f44a-1f3fe", "facepunch_dark_skin_tone": "1f44a-1f3ff", "punch_dark_skin_tone": "1f44a-1f3ff", "fist_oncoming_dark_skin_tone": "1f44a-1f3ff", "wave_light_skin_tone": "1f44b-1f3fb", "wave_medium_light_skin_tone": "1f44b-1f3fc", "wave_medium_skin_tone": "1f44b-1f3fd", "wave_medium_dark_skin_tone": "1f44b-1f3fe", "wave_dark_skin_tone": "1f44b-1f3ff", "ok_hand_light_skin_tone": "1f44c-1f3fb", "ok_hand_medium_light_skin_tone": "1f44c-1f3fc", "ok_hand_medium_skin_tone": "1f44c-1f3fd", "ok_hand_medium_dark_skin_tone": "1f44c-1f3fe", "ok_hand_dark_skin_tone": "1f44c-1f3ff", "+1_light_skin_tone": "1f44d-1f3fb", "thumbsup_light_skin_tone": "1f44d-1f3fb", "+1_medium_light_skin_tone": "1f44d-1f3fc", "thumbsup_medium_light_skin_tone": "1f44d-1f3fc", "+1_medium_skin_tone": "1f44d-1f3fd", "thumbsup_medium_skin_tone": "1f44d-1f3fd", "+1_medium_dark_skin_tone": "1f44d-1f3fe", "thumbsup_medium_dark_skin_tone": "1f44d-1f3fe", "+1_dark_skin_tone": "1f44d-1f3ff", "thumbsup_dark_skin_tone": "1f44d-1f3ff", "-1_light_skin_tone": "1f44e-1f3fb", "thumbsdown_light_skin_tone": "1f44e-1f3fb", "-1_medium_light_skin_tone": "1f44e-1f3fc", "thumbsdown_medium_light_skin_tone": "1f44e-1f3fc", "-1_medium_skin_tone": "1f44e-1f3fd", "thumbsdown_medium_skin_tone": "1f44e-1f3fd", "-1_medium_dark_skin_tone": "1f44e-1f3fe", "thumbsdown_medium_dark_skin_tone": "1f44e-1f3fe", "-1_dark_skin_tone": "1f44e-1f3ff", "thumbsdown_dark_skin_tone": "1f44e-1f3ff", "clap_light_skin_tone": "1f44f-1f3fb", "clap_medium_light_skin_tone": "1f44f-1f3fc", "clap_medium_skin_tone": "1f44f-1f3fd", "clap_medium_dark_skin_tone": "1f44f-1f3fe", "clap_dark_skin_tone": "1f44f-1f3ff", "open_hands_light_skin_tone": "1f450-1f3fb", "open_hands_medium_light_skin_tone": "1f450-1f3fc", "open_hands_medium_skin_tone": "1f450-1f3fd", "open_hands_medium_dark_skin_tone": "1f450-1f3fe", "open_hands_dark_skin_tone": "1f450-1f3ff", "boy_light_skin_tone": "1f466-1f3fb", "boy_medium_light_skin_tone": "1f466-1f3fc", "boy_medium_skin_tone": "1f466-1f3fd", "boy_medium_dark_skin_tone": "1f466-1f3fe", "boy_dark_skin_tone": "1f466-1f3ff", "girl_light_skin_tone": "1f467-1f3fb", "girl_medium_light_skin_tone": "1f467-1f3fc", "girl_medium_skin_tone": "1f467-1f3fd", "girl_medium_dark_skin_tone": "1f467-1f3fe", "girl_dark_skin_tone": "1f467-1f3ff", "male-farmer_light_skin_tone": "1f468-1f3fb-200d-1f33e", "man_farmer_light_skin_tone": "1f468-1f3fb-200d-1f33e", "male-farmer_medium_light_skin_tone": "1f468-1f3fc-200d-1f33e", "man_farmer_medium_light_skin_tone": "1f468-1f3fc-200d-1f33e", "male-farmer_medium_skin_tone": "1f468-1f3fd-200d-1f33e", "man_farmer_medium_skin_tone": "1f468-1f3fd-200d-1f33e", "male-farmer_medium_dark_skin_tone": "1f468-1f3fe-200d-1f33e", "man_farmer_medium_dark_skin_tone": "1f468-1f3fe-200d-1f33e", "male-farmer_dark_skin_tone": "1f468-1f3ff-200d-1f33e", "man_farmer_dark_skin_tone": "1f468-1f3ff-200d-1f33e", "male-cook_light_skin_tone": "1f468-1f3fb-200d-1f373", "man_cook_light_skin_tone": "1f468-1f3fb-200d-1f373", "male-cook_medium_light_skin_tone": "1f468-1f3fc-200d-1f373", "man_cook_medium_light_skin_tone": "1f468-1f3fc-200d-1f373", "male-cook_medium_skin_tone": "1f468-1f3fd-200d-1f373", "man_cook_medium_skin_tone": "1f468-1f3fd-200d-1f373", "male-cook_medium_dark_skin_tone": "1f468-1f3fe-200d-1f373", "man_cook_medium_dark_skin_tone": "1f468-1f3fe-200d-1f373", "male-cook_dark_skin_tone": "1f468-1f3ff-200d-1f373", "man_cook_dark_skin_tone": "1f468-1f3ff-200d-1f373", "man_feeding_baby_light_skin_tone": "1f468-1f3fb-200d-1f37c", "man_feeding_baby_medium_light_skin_tone": "1f468-1f3fc-200d-1f37c", "man_feeding_baby_medium_skin_tone": "1f468-1f3fd-200d-1f37c", "man_feeding_baby_medium_dark_skin_tone": "1f468-1f3fe-200d-1f37c", "man_feeding_baby_dark_skin_tone": "1f468-1f3ff-200d-1f37c", "male-student_light_skin_tone": "1f468-1f3fb-200d-1f393", "man_student_light_skin_tone": "1f468-1f3fb-200d-1f393", "male-student_medium_light_skin_tone": "1f468-1f3fc-200d-1f393", "man_student_medium_light_skin_tone": "1f468-1f3fc-200d-1f393", "male-student_medium_skin_tone": "1f468-1f3fd-200d-1f393", "man_student_medium_skin_tone": "1f468-1f3fd-200d-1f393", "male-student_medium_dark_skin_tone": "1f468-1f3fe-200d-1f393", "man_student_medium_dark_skin_tone": "1f468-1f3fe-200d-1f393", "male-student_dark_skin_tone": "1f468-1f3ff-200d-1f393", "man_student_dark_skin_tone": "1f468-1f3ff-200d-1f393", "male-singer_light_skin_tone": "1f468-1f3fb-200d-1f3a4", "man_singer_light_skin_tone": "1f468-1f3fb-200d-1f3a4", "male-singer_medium_light_skin_tone": "1f468-1f3fc-200d-1f3a4", "man_singer_medium_light_skin_tone": "1f468-1f3fc-200d-1f3a4", "male-singer_medium_skin_tone": "1f468-1f3fd-200d-1f3a4", "man_singer_medium_skin_tone": "1f468-1f3fd-200d-1f3a4", "male-singer_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3a4", "man_singer_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3a4", "male-singer_dark_skin_tone": "1f468-1f3ff-200d-1f3a4", "man_singer_dark_skin_tone": "1f468-1f3ff-200d-1f3a4", "male-artist_light_skin_tone": "1f468-1f3fb-200d-1f3a8", "man_artist_light_skin_tone": "1f468-1f3fb-200d-1f3a8", "male-artist_medium_light_skin_tone": "1f468-1f3fc-200d-1f3a8", "man_artist_medium_light_skin_tone": "1f468-1f3fc-200d-1f3a8", "male-artist_medium_skin_tone": "1f468-1f3fd-200d-1f3a8", "man_artist_medium_skin_tone": "1f468-1f3fd-200d-1f3a8", "male-artist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3a8", "man_artist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3a8", "male-artist_dark_skin_tone": "1f468-1f3ff-200d-1f3a8", "man_artist_dark_skin_tone": "1f468-1f3ff-200d-1f3a8", "male-teacher_light_skin_tone": "1f468-1f3fb-200d-1f3eb", "man_teacher_light_skin_tone": "1f468-1f3fb-200d-1f3eb", "male-teacher_medium_light_skin_tone": "1f468-1f3fc-200d-1f3eb", "man_teacher_medium_light_skin_tone": "1f468-1f3fc-200d-1f3eb", "male-teacher_medium_skin_tone": "1f468-1f3fd-200d-1f3eb", "man_teacher_medium_skin_tone": "1f468-1f3fd-200d-1f3eb", "male-teacher_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3eb", "man_teacher_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3eb", "male-teacher_dark_skin_tone": "1f468-1f3ff-200d-1f3eb", "man_teacher_dark_skin_tone": "1f468-1f3ff-200d-1f3eb", "male-factory-worker_light_skin_tone": "1f468-1f3fb-200d-1f3ed", "man_factory_worker_light_skin_tone": "1f468-1f3fb-200d-1f3ed", "male-factory-worker_medium_light_skin_tone": "1f468-1f3fc-200d-1f3ed", "man_factory_worker_medium_light_skin_tone": "1f468-1f3fc-200d-1f3ed", "male-factory-worker_medium_skin_tone": "1f468-1f3fd-200d-1f3ed", "man_factory_worker_medium_skin_tone": "1f468-1f3fd-200d-1f3ed", "male-factory-worker_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3ed", "man_factory_worker_medium_dark_skin_tone": "1f468-1f3fe-200d-1f3ed", "male-factory-worker_dark_skin_tone": "1f468-1f3ff-200d-1f3ed", "man_factory_worker_dark_skin_tone": "1f468-1f3ff-200d-1f3ed", "male-technologist_light_skin_tone": "1f468-1f3fb-200d-1f4bb", "man_technologist_light_skin_tone": "1f468-1f3fb-200d-1f4bb", "male-technologist_medium_light_skin_tone": "1f468-1f3fc-200d-1f4bb", "man_technologist_medium_light_skin_tone": "1f468-1f3fc-200d-1f4bb", "male-technologist_medium_skin_tone": "1f468-1f3fd-200d-1f4bb", "man_technologist_medium_skin_tone": "1f468-1f3fd-200d-1f4bb", "male-technologist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f4bb", "man_technologist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f4bb", "male-technologist_dark_skin_tone": "1f468-1f3ff-200d-1f4bb", "man_technologist_dark_skin_tone": "1f468-1f3ff-200d-1f4bb", "male-office-worker_light_skin_tone": "1f468-1f3fb-200d-1f4bc", "man_office_worker_light_skin_tone": "1f468-1f3fb-200d-1f4bc", "male-office-worker_medium_light_skin_tone": "1f468-1f3fc-200d-1f4bc", "man_office_worker_medium_light_skin_tone": "1f468-1f3fc-200d-1f4bc", "male-office-worker_medium_skin_tone": "1f468-1f3fd-200d-1f4bc", "man_office_worker_medium_skin_tone": "1f468-1f3fd-200d-1f4bc", "male-office-worker_medium_dark_skin_tone": "1f468-1f3fe-200d-1f4bc", "man_office_worker_medium_dark_skin_tone": "1f468-1f3fe-200d-1f4bc", "male-office-worker_dark_skin_tone": "1f468-1f3ff-200d-1f4bc", "man_office_worker_dark_skin_tone": "1f468-1f3ff-200d-1f4bc", "male-mechanic_light_skin_tone": "1f468-1f3fb-200d-1f527", "man_mechanic_light_skin_tone": "1f468-1f3fb-200d-1f527", "male-mechanic_medium_light_skin_tone": "1f468-1f3fc-200d-1f527", "man_mechanic_medium_light_skin_tone": "1f468-1f3fc-200d-1f527", "male-mechanic_medium_skin_tone": "1f468-1f3fd-200d-1f527", "man_mechanic_medium_skin_tone": "1f468-1f3fd-200d-1f527", "male-mechanic_medium_dark_skin_tone": "1f468-1f3fe-200d-1f527", "man_mechanic_medium_dark_skin_tone": "1f468-1f3fe-200d-1f527", "male-mechanic_dark_skin_tone": "1f468-1f3ff-200d-1f527", "man_mechanic_dark_skin_tone": "1f468-1f3ff-200d-1f527", "male-scientist_light_skin_tone": "1f468-1f3fb-200d-1f52c", "man_scientist_light_skin_tone": "1f468-1f3fb-200d-1f52c", "male-scientist_medium_light_skin_tone": "1f468-1f3fc-200d-1f52c", "man_scientist_medium_light_skin_tone": "1f468-1f3fc-200d-1f52c", "male-scientist_medium_skin_tone": "1f468-1f3fd-200d-1f52c", "man_scientist_medium_skin_tone": "1f468-1f3fd-200d-1f52c", "male-scientist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f52c", "man_scientist_medium_dark_skin_tone": "1f468-1f3fe-200d-1f52c", "male-scientist_dark_skin_tone": "1f468-1f3ff-200d-1f52c", "man_scientist_dark_skin_tone": "1f468-1f3ff-200d-1f52c", "male-astronaut_light_skin_tone": "1f468-1f3fb-200d-1f680", "man_astronaut_light_skin_tone": "1f468-1f3fb-200d-1f680", "male-astronaut_medium_light_skin_tone": "1f468-1f3fc-200d-1f680", "man_astronaut_medium_light_skin_tone": "1f468-1f3fc-200d-1f680", "male-astronaut_medium_skin_tone": "1f468-1f3fd-200d-1f680", "man_astronaut_medium_skin_tone": "1f468-1f3fd-200d-1f680", "male-astronaut_medium_dark_skin_tone": "1f468-1f3fe-200d-1f680", "man_astronaut_medium_dark_skin_tone": "1f468-1f3fe-200d-1f680", "male-astronaut_dark_skin_tone": "1f468-1f3ff-200d-1f680", "man_astronaut_dark_skin_tone": "1f468-1f3ff-200d-1f680", "male-firefighter_light_skin_tone": "1f468-1f3fb-200d-1f692", "man_firefighter_light_skin_tone": "1f468-1f3fb-200d-1f692", "male-firefighter_medium_light_skin_tone": "1f468-1f3fc-200d-1f692", "man_firefighter_medium_light_skin_tone": "1f468-1f3fc-200d-1f692", "male-firefighter_medium_skin_tone": "1f468-1f3fd-200d-1f692", "man_firefighter_medium_skin_tone": "1f468-1f3fd-200d-1f692", "male-firefighter_medium_dark_skin_tone": "1f468-1f3fe-200d-1f692", "man_firefighter_medium_dark_skin_tone": "1f468-1f3fe-200d-1f692", "male-firefighter_dark_skin_tone": "1f468-1f3ff-200d-1f692", "man_firefighter_dark_skin_tone": "1f468-1f3ff-200d-1f692", "man_with_probing_cane_light_skin_tone": "1f468-1f3fb-200d-1f9af", "man_with_probing_cane_medium_light_skin_tone": "1f468-1f3fc-200d-1f9af", "man_with_probing_cane_medium_skin_tone": "1f468-1f3fd-200d-1f9af", "man_with_probing_cane_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9af", "man_with_probing_cane_dark_skin_tone": "1f468-1f3ff-200d-1f9af", "red_haired_man_light_skin_tone": "1f468-1f3fb-200d-1f9b0", "red_haired_man_medium_light_skin_tone": "1f468-1f3fc-200d-1f9b0", "red_haired_man_medium_skin_tone": "1f468-1f3fd-200d-1f9b0", "red_haired_man_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9b0", "red_haired_man_dark_skin_tone": "1f468-1f3ff-200d-1f9b0", "curly_haired_man_light_skin_tone": "1f468-1f3fb-200d-1f9b1", "curly_haired_man_medium_light_skin_tone": "1f468-1f3fc-200d-1f9b1", "curly_haired_man_medium_skin_tone": "1f468-1f3fd-200d-1f9b1", "curly_haired_man_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9b1", "curly_haired_man_dark_skin_tone": "1f468-1f3ff-200d-1f9b1", "bald_man_light_skin_tone": "1f468-1f3fb-200d-1f9b2", "bald_man_medium_light_skin_tone": "1f468-1f3fc-200d-1f9b2", "bald_man_medium_skin_tone": "1f468-1f3fd-200d-1f9b2", "bald_man_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9b2", "bald_man_dark_skin_tone": "1f468-1f3ff-200d-1f9b2", "white_haired_man_light_skin_tone": "1f468-1f3fb-200d-1f9b3", "white_haired_man_medium_light_skin_tone": "1f468-1f3fc-200d-1f9b3", "white_haired_man_medium_skin_tone": "1f468-1f3fd-200d-1f9b3", "white_haired_man_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9b3", "white_haired_man_dark_skin_tone": "1f468-1f3ff-200d-1f9b3", "man_in_motorized_wheelchair_light_skin_tone": "1f468-1f3fb-200d-1f9bc", "man_in_motorized_wheelchair_medium_light_skin_tone": "1f468-1f3fc-200d-1f9bc", "man_in_motorized_wheelchair_medium_skin_tone": "1f468-1f3fd-200d-1f9bc", "man_in_motorized_wheelchair_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9bc", "man_in_motorized_wheelchair_dark_skin_tone": "1f468-1f3ff-200d-1f9bc", "man_in_manual_wheelchair_light_skin_tone": "1f468-1f3fb-200d-1f9bd", "man_in_manual_wheelchair_medium_light_skin_tone": "1f468-1f3fc-200d-1f9bd", "man_in_manual_wheelchair_medium_skin_tone": "1f468-1f3fd-200d-1f9bd", "man_in_manual_wheelchair_medium_dark_skin_tone": "1f468-1f3fe-200d-1f9bd", "man_in_manual_wheelchair_dark_skin_tone": "1f468-1f3ff-200d-1f9bd", "male-doctor_light_skin_tone": "1f468-1f3fb-200d-2695-fe0f", "man_health_worker_light_skin_tone": "1f468-1f3fb-200d-2695-fe0f", "male-doctor_medium_light_skin_tone": "1f468-1f3fc-200d-2695-fe0f", "man_health_worker_medium_light_skin_tone": "1f468-1f3fc-200d-2695-fe0f", "male-doctor_medium_skin_tone": "1f468-1f3fd-200d-2695-fe0f", "man_health_worker_medium_skin_tone": "1f468-1f3fd-200d-2695-fe0f", "male-doctor_medium_dark_skin_tone": "1f468-1f3fe-200d-2695-fe0f", "man_health_worker_medium_dark_skin_tone": "1f468-1f3fe-200d-2695-fe0f", "male-doctor_dark_skin_tone": "1f468-1f3ff-200d-2695-fe0f", "man_health_worker_dark_skin_tone": "1f468-1f3ff-200d-2695-fe0f", "male-judge_light_skin_tone": "1f468-1f3fb-200d-2696-fe0f", "man_judge_light_skin_tone": "1f468-1f3fb-200d-2696-fe0f", "male-judge_medium_light_skin_tone": "1f468-1f3fc-200d-2696-fe0f", "man_judge_medium_light_skin_tone": "1f468-1f3fc-200d-2696-fe0f", "male-judge_medium_skin_tone": "1f468-1f3fd-200d-2696-fe0f", "man_judge_medium_skin_tone": "1f468-1f3fd-200d-2696-fe0f", "male-judge_medium_dark_skin_tone": "1f468-1f3fe-200d-2696-fe0f", "man_judge_medium_dark_skin_tone": "1f468-1f3fe-200d-2696-fe0f", "male-judge_dark_skin_tone": "1f468-1f3ff-200d-2696-fe0f", "man_judge_dark_skin_tone": "1f468-1f3ff-200d-2696-fe0f", "male-pilot_light_skin_tone": "1f468-1f3fb-200d-2708-fe0f", "man_pilot_light_skin_tone": "1f468-1f3fb-200d-2708-fe0f", "male-pilot_medium_light_skin_tone": "1f468-1f3fc-200d-2708-fe0f", "man_pilot_medium_light_skin_tone": "1f468-1f3fc-200d-2708-fe0f", "male-pilot_medium_skin_tone": "1f468-1f3fd-200d-2708-fe0f", "man_pilot_medium_skin_tone": "1f468-1f3fd-200d-2708-fe0f", "male-pilot_medium_dark_skin_tone": "1f468-1f3fe-200d-2708-fe0f", "man_pilot_medium_dark_skin_tone": "1f468-1f3fe-200d-2708-fe0f", "male-pilot_dark_skin_tone": "1f468-1f3ff-200d-2708-fe0f", "man_pilot_dark_skin_tone": "1f468-1f3ff-200d-2708-fe0f", "man_light_skin_tone": "1f468-1f3fb", "man_medium_light_skin_tone": "1f468-1f3fc", "man_medium_skin_tone": "1f468-1f3fd", "man_medium_dark_skin_tone": "1f468-1f3fe", "man_dark_skin_tone": "1f468-1f3ff", "female-farmer_light_skin_tone": "1f469-1f3fb-200d-1f33e", "woman_farmer_light_skin_tone": "1f469-1f3fb-200d-1f33e", "female-farmer_medium_light_skin_tone": "1f469-1f3fc-200d-1f33e", "woman_farmer_medium_light_skin_tone": "1f469-1f3fc-200d-1f33e", "female-farmer_medium_skin_tone": "1f469-1f3fd-200d-1f33e", "woman_farmer_medium_skin_tone": "1f469-1f3fd-200d-1f33e", "female-farmer_medium_dark_skin_tone": "1f469-1f3fe-200d-1f33e", "woman_farmer_medium_dark_skin_tone": "1f469-1f3fe-200d-1f33e", "female-farmer_dark_skin_tone": "1f469-1f3ff-200d-1f33e", "woman_farmer_dark_skin_tone": "1f469-1f3ff-200d-1f33e", "female-cook_light_skin_tone": "1f469-1f3fb-200d-1f373", "woman_cook_light_skin_tone": "1f469-1f3fb-200d-1f373", "female-cook_medium_light_skin_tone": "1f469-1f3fc-200d-1f373", "woman_cook_medium_light_skin_tone": "1f469-1f3fc-200d-1f373", "female-cook_medium_skin_tone": "1f469-1f3fd-200d-1f373", "woman_cook_medium_skin_tone": "1f469-1f3fd-200d-1f373", "female-cook_medium_dark_skin_tone": "1f469-1f3fe-200d-1f373", "woman_cook_medium_dark_skin_tone": "1f469-1f3fe-200d-1f373", "female-cook_dark_skin_tone": "1f469-1f3ff-200d-1f373", "woman_cook_dark_skin_tone": "1f469-1f3ff-200d-1f373", "woman_feeding_baby_light_skin_tone": "1f469-1f3fb-200d-1f37c", "woman_feeding_baby_medium_light_skin_tone": "1f469-1f3fc-200d-1f37c", "woman_feeding_baby_medium_skin_tone": "1f469-1f3fd-200d-1f37c", "woman_feeding_baby_medium_dark_skin_tone": "1f469-1f3fe-200d-1f37c", "woman_feeding_baby_dark_skin_tone": "1f469-1f3ff-200d-1f37c", "female-student_light_skin_tone": "1f469-1f3fb-200d-1f393", "woman_student_light_skin_tone": "1f469-1f3fb-200d-1f393", "female-student_medium_light_skin_tone": "1f469-1f3fc-200d-1f393", "woman_student_medium_light_skin_tone": "1f469-1f3fc-200d-1f393", "female-student_medium_skin_tone": "1f469-1f3fd-200d-1f393", "woman_student_medium_skin_tone": "1f469-1f3fd-200d-1f393", "female-student_medium_dark_skin_tone": "1f469-1f3fe-200d-1f393", "woman_student_medium_dark_skin_tone": "1f469-1f3fe-200d-1f393", "female-student_dark_skin_tone": "1f469-1f3ff-200d-1f393", "woman_student_dark_skin_tone": "1f469-1f3ff-200d-1f393", "female-singer_light_skin_tone": "1f469-1f3fb-200d-1f3a4", "woman_singer_light_skin_tone": "1f469-1f3fb-200d-1f3a4", "female-singer_medium_light_skin_tone": "1f469-1f3fc-200d-1f3a4", "woman_singer_medium_light_skin_tone": "1f469-1f3fc-200d-1f3a4", "female-singer_medium_skin_tone": "1f469-1f3fd-200d-1f3a4", "woman_singer_medium_skin_tone": "1f469-1f3fd-200d-1f3a4", "female-singer_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3a4", "woman_singer_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3a4", "female-singer_dark_skin_tone": "1f469-1f3ff-200d-1f3a4", "woman_singer_dark_skin_tone": "1f469-1f3ff-200d-1f3a4", "female-artist_light_skin_tone": "1f469-1f3fb-200d-1f3a8", "woman_artist_light_skin_tone": "1f469-1f3fb-200d-1f3a8", "female-artist_medium_light_skin_tone": "1f469-1f3fc-200d-1f3a8", "woman_artist_medium_light_skin_tone": "1f469-1f3fc-200d-1f3a8", "female-artist_medium_skin_tone": "1f469-1f3fd-200d-1f3a8", "woman_artist_medium_skin_tone": "1f469-1f3fd-200d-1f3a8", "female-artist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3a8", "woman_artist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3a8", "female-artist_dark_skin_tone": "1f469-1f3ff-200d-1f3a8", "woman_artist_dark_skin_tone": "1f469-1f3ff-200d-1f3a8", "female-teacher_light_skin_tone": "1f469-1f3fb-200d-1f3eb", "woman_teacher_light_skin_tone": "1f469-1f3fb-200d-1f3eb", "female-teacher_medium_light_skin_tone": "1f469-1f3fc-200d-1f3eb", "woman_teacher_medium_light_skin_tone": "1f469-1f3fc-200d-1f3eb", "female-teacher_medium_skin_tone": "1f469-1f3fd-200d-1f3eb", "woman_teacher_medium_skin_tone": "1f469-1f3fd-200d-1f3eb", "female-teacher_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3eb", "woman_teacher_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3eb", "female-teacher_dark_skin_tone": "1f469-1f3ff-200d-1f3eb", "woman_teacher_dark_skin_tone": "1f469-1f3ff-200d-1f3eb", "female-factory-worker_light_skin_tone": "1f469-1f3fb-200d-1f3ed", "woman_factory_worker_light_skin_tone": "1f469-1f3fb-200d-1f3ed", "female-factory-worker_medium_light_skin_tone": "1f469-1f3fc-200d-1f3ed", "woman_factory_worker_medium_light_skin_tone": "1f469-1f3fc-200d-1f3ed", "female-factory-worker_medium_skin_tone": "1f469-1f3fd-200d-1f3ed", "woman_factory_worker_medium_skin_tone": "1f469-1f3fd-200d-1f3ed", "female-factory-worker_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3ed", "woman_factory_worker_medium_dark_skin_tone": "1f469-1f3fe-200d-1f3ed", "female-factory-worker_dark_skin_tone": "1f469-1f3ff-200d-1f3ed", "woman_factory_worker_dark_skin_tone": "1f469-1f3ff-200d-1f3ed", "female-technologist_light_skin_tone": "1f469-1f3fb-200d-1f4bb", "woman_technologist_light_skin_tone": "1f469-1f3fb-200d-1f4bb", "female-technologist_medium_light_skin_tone": "1f469-1f3fc-200d-1f4bb", "woman_technologist_medium_light_skin_tone": "1f469-1f3fc-200d-1f4bb", "female-technologist_medium_skin_tone": "1f469-1f3fd-200d-1f4bb", "woman_technologist_medium_skin_tone": "1f469-1f3fd-200d-1f4bb", "female-technologist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f4bb", "woman_technologist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f4bb", "female-technologist_dark_skin_tone": "1f469-1f3ff-200d-1f4bb", "woman_technologist_dark_skin_tone": "1f469-1f3ff-200d-1f4bb", "female-office-worker_light_skin_tone": "1f469-1f3fb-200d-1f4bc", "woman_office_worker_light_skin_tone": "1f469-1f3fb-200d-1f4bc", "female-office-worker_medium_light_skin_tone": "1f469-1f3fc-200d-1f4bc", "woman_office_worker_medium_light_skin_tone": "1f469-1f3fc-200d-1f4bc", "female-office-worker_medium_skin_tone": "1f469-1f3fd-200d-1f4bc", "woman_office_worker_medium_skin_tone": "1f469-1f3fd-200d-1f4bc", "female-office-worker_medium_dark_skin_tone": "1f469-1f3fe-200d-1f4bc", "woman_office_worker_medium_dark_skin_tone": "1f469-1f3fe-200d-1f4bc", "female-office-worker_dark_skin_tone": "1f469-1f3ff-200d-1f4bc", "woman_office_worker_dark_skin_tone": "1f469-1f3ff-200d-1f4bc", "female-mechanic_light_skin_tone": "1f469-1f3fb-200d-1f527", "woman_mechanic_light_skin_tone": "1f469-1f3fb-200d-1f527", "female-mechanic_medium_light_skin_tone": "1f469-1f3fc-200d-1f527", "woman_mechanic_medium_light_skin_tone": "1f469-1f3fc-200d-1f527", "female-mechanic_medium_skin_tone": "1f469-1f3fd-200d-1f527", "woman_mechanic_medium_skin_tone": "1f469-1f3fd-200d-1f527", "female-mechanic_medium_dark_skin_tone": "1f469-1f3fe-200d-1f527", "woman_mechanic_medium_dark_skin_tone": "1f469-1f3fe-200d-1f527", "female-mechanic_dark_skin_tone": "1f469-1f3ff-200d-1f527", "woman_mechanic_dark_skin_tone": "1f469-1f3ff-200d-1f527", "female-scientist_light_skin_tone": "1f469-1f3fb-200d-1f52c", "woman_scientist_light_skin_tone": "1f469-1f3fb-200d-1f52c", "female-scientist_medium_light_skin_tone": "1f469-1f3fc-200d-1f52c", "woman_scientist_medium_light_skin_tone": "1f469-1f3fc-200d-1f52c", "female-scientist_medium_skin_tone": "1f469-1f3fd-200d-1f52c", "woman_scientist_medium_skin_tone": "1f469-1f3fd-200d-1f52c", "female-scientist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f52c", "woman_scientist_medium_dark_skin_tone": "1f469-1f3fe-200d-1f52c", "female-scientist_dark_skin_tone": "1f469-1f3ff-200d-1f52c", "woman_scientist_dark_skin_tone": "1f469-1f3ff-200d-1f52c", "female-astronaut_light_skin_tone": "1f469-1f3fb-200d-1f680", "woman_astronaut_light_skin_tone": "1f469-1f3fb-200d-1f680", "female-astronaut_medium_light_skin_tone": "1f469-1f3fc-200d-1f680", "woman_astronaut_medium_light_skin_tone": "1f469-1f3fc-200d-1f680", "female-astronaut_medium_skin_tone": "1f469-1f3fd-200d-1f680", "woman_astronaut_medium_skin_tone": "1f469-1f3fd-200d-1f680", "female-astronaut_medium_dark_skin_tone": "1f469-1f3fe-200d-1f680", "woman_astronaut_medium_dark_skin_tone": "1f469-1f3fe-200d-1f680", "female-astronaut_dark_skin_tone": "1f469-1f3ff-200d-1f680", "woman_astronaut_dark_skin_tone": "1f469-1f3ff-200d-1f680", "female-firefighter_light_skin_tone": "1f469-1f3fb-200d-1f692", "woman_firefighter_light_skin_tone": "1f469-1f3fb-200d-1f692", "female-firefighter_medium_light_skin_tone": "1f469-1f3fc-200d-1f692", "woman_firefighter_medium_light_skin_tone": "1f469-1f3fc-200d-1f692", "female-firefighter_medium_skin_tone": "1f469-1f3fd-200d-1f692", "woman_firefighter_medium_skin_tone": "1f469-1f3fd-200d-1f692", "female-firefighter_medium_dark_skin_tone": "1f469-1f3fe-200d-1f692", "woman_firefighter_medium_dark_skin_tone": "1f469-1f3fe-200d-1f692", "female-firefighter_dark_skin_tone": "1f469-1f3ff-200d-1f692", "woman_firefighter_dark_skin_tone": "1f469-1f3ff-200d-1f692", "woman_with_probing_cane_light_skin_tone": "1f469-1f3fb-200d-1f9af", "woman_with_probing_cane_medium_light_skin_tone": "1f469-1f3fc-200d-1f9af", "woman_with_probing_cane_medium_skin_tone": "1f469-1f3fd-200d-1f9af", "woman_with_probing_cane_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9af", "woman_with_probing_cane_dark_skin_tone": "1f469-1f3ff-200d-1f9af", "red_haired_woman_light_skin_tone": "1f469-1f3fb-200d-1f9b0", "red_haired_woman_medium_light_skin_tone": "1f469-1f3fc-200d-1f9b0", "red_haired_woman_medium_skin_tone": "1f469-1f3fd-200d-1f9b0", "red_haired_woman_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9b0", "red_haired_woman_dark_skin_tone": "1f469-1f3ff-200d-1f9b0", "curly_haired_woman_light_skin_tone": "1f469-1f3fb-200d-1f9b1", "curly_haired_woman_medium_light_skin_tone": "1f469-1f3fc-200d-1f9b1", "curly_haired_woman_medium_skin_tone": "1f469-1f3fd-200d-1f9b1", "curly_haired_woman_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9b1", "curly_haired_woman_dark_skin_tone": "1f469-1f3ff-200d-1f9b1", "bald_woman_light_skin_tone": "1f469-1f3fb-200d-1f9b2", "bald_woman_medium_light_skin_tone": "1f469-1f3fc-200d-1f9b2", "bald_woman_medium_skin_tone": "1f469-1f3fd-200d-1f9b2", "bald_woman_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9b2", "bald_woman_dark_skin_tone": "1f469-1f3ff-200d-1f9b2", "white_haired_woman_light_skin_tone": "1f469-1f3fb-200d-1f9b3", "white_haired_woman_medium_light_skin_tone": "1f469-1f3fc-200d-1f9b3", "white_haired_woman_medium_skin_tone": "1f469-1f3fd-200d-1f9b3", "white_haired_woman_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9b3", "white_haired_woman_dark_skin_tone": "1f469-1f3ff-200d-1f9b3", "woman_in_motorized_wheelchair_light_skin_tone": "1f469-1f3fb-200d-1f9bc", "woman_in_motorized_wheelchair_medium_light_skin_tone": "1f469-1f3fc-200d-1f9bc", "woman_in_motorized_wheelchair_medium_skin_tone": "1f469-1f3fd-200d-1f9bc", "woman_in_motorized_wheelchair_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9bc", "woman_in_motorized_wheelchair_dark_skin_tone": "1f469-1f3ff-200d-1f9bc", "woman_in_manual_wheelchair_light_skin_tone": "1f469-1f3fb-200d-1f9bd", "woman_in_manual_wheelchair_medium_light_skin_tone": "1f469-1f3fc-200d-1f9bd", "woman_in_manual_wheelchair_medium_skin_tone": "1f469-1f3fd-200d-1f9bd", "woman_in_manual_wheelchair_medium_dark_skin_tone": "1f469-1f3fe-200d-1f9bd", "woman_in_manual_wheelchair_dark_skin_tone": "1f469-1f3ff-200d-1f9bd", "female-doctor_light_skin_tone": "1f469-1f3fb-200d-2695-fe0f", "woman_health_worker_light_skin_tone": "1f469-1f3fb-200d-2695-fe0f", "female-doctor_medium_light_skin_tone": "1f469-1f3fc-200d-2695-fe0f", "woman_health_worker_medium_light_skin_tone": "1f469-1f3fc-200d-2695-fe0f", "female-doctor_medium_skin_tone": "1f469-1f3fd-200d-2695-fe0f", "woman_health_worker_medium_skin_tone": "1f469-1f3fd-200d-2695-fe0f", "female-doctor_medium_dark_skin_tone": "1f469-1f3fe-200d-2695-fe0f", "woman_health_worker_medium_dark_skin_tone": "1f469-1f3fe-200d-2695-fe0f", "female-doctor_dark_skin_tone": "1f469-1f3ff-200d-2695-fe0f", "woman_health_worker_dark_skin_tone": "1f469-1f3ff-200d-2695-fe0f", "female-judge_light_skin_tone": "1f469-1f3fb-200d-2696-fe0f", "woman_judge_light_skin_tone": "1f469-1f3fb-200d-2696-fe0f", "female-judge_medium_light_skin_tone": "1f469-1f3fc-200d-2696-fe0f", "woman_judge_medium_light_skin_tone": "1f469-1f3fc-200d-2696-fe0f", "female-judge_medium_skin_tone": "1f469-1f3fd-200d-2696-fe0f", "woman_judge_medium_skin_tone": "1f469-1f3fd-200d-2696-fe0f", "female-judge_medium_dark_skin_tone": "1f469-1f3fe-200d-2696-fe0f", "woman_judge_medium_dark_skin_tone": "1f469-1f3fe-200d-2696-fe0f", "female-judge_dark_skin_tone": "1f469-1f3ff-200d-2696-fe0f", "woman_judge_dark_skin_tone": "1f469-1f3ff-200d-2696-fe0f", "female-pilot_light_skin_tone": "1f469-1f3fb-200d-2708-fe0f", "woman_pilot_light_skin_tone": "1f469-1f3fb-200d-2708-fe0f", "female-pilot_medium_light_skin_tone": "1f469-1f3fc-200d-2708-fe0f", "woman_pilot_medium_light_skin_tone": "1f469-1f3fc-200d-2708-fe0f", "female-pilot_medium_skin_tone": "1f469-1f3fd-200d-2708-fe0f", "woman_pilot_medium_skin_tone": "1f469-1f3fd-200d-2708-fe0f", "female-pilot_medium_dark_skin_tone": "1f469-1f3fe-200d-2708-fe0f", "woman_pilot_medium_dark_skin_tone": "1f469-1f3fe-200d-2708-fe0f", "female-pilot_dark_skin_tone": "1f469-1f3ff-200d-2708-fe0f", "woman_pilot_dark_skin_tone": "1f469-1f3ff-200d-2708-fe0f", "woman_light_skin_tone": "1f469-1f3fb", "woman_medium_light_skin_tone": "1f469-1f3fc", "woman_medium_skin_tone": "1f469-1f3fd", "woman_medium_dark_skin_tone": "1f469-1f3fe", "woman_dark_skin_tone": "1f469-1f3ff", "man_and_woman_holding_hands_light_skin_tone": "1f46b-1f3fb", "woman_and_man_holding_hands_light_skin_tone": "1f46b-1f3fb", "couple_light_skin_tone": "1f46b-1f3fb", "man_and_woman_holding_hands_medium_light_skin_tone": "1f46b-1f3fc", "woman_and_man_holding_hands_medium_light_skin_tone": "1f46b-1f3fc", "couple_medium_light_skin_tone": "1f46b-1f3fc", "man_and_woman_holding_hands_medium_skin_tone": "1f46b-1f3fd", "woman_and_man_holding_hands_medium_skin_tone": "1f46b-1f3fd", "couple_medium_skin_tone": "1f46b-1f3fd", "man_and_woman_holding_hands_medium_dark_skin_tone": "1f46b-1f3fe", "woman_and_man_holding_hands_medium_dark_skin_tone": "1f46b-1f3fe", "couple_medium_dark_skin_tone": "1f46b-1f3fe", "man_and_woman_holding_hands_dark_skin_tone": "1f46b-1f3ff", "woman_and_man_holding_hands_dark_skin_tone": "1f46b-1f3ff", "couple_dark_skin_tone": "1f46b-1f3ff", "man_and_woman_holding_hands_light_skin_tone_medium_light_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fc", "woman_and_man_holding_hands_light_skin_tone_medium_light_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fc", "couple_light_skin_tone_medium_light_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fc", "man_and_woman_holding_hands_light_skin_tone_medium_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fd", "woman_and_man_holding_hands_light_skin_tone_medium_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fd", "couple_light_skin_tone_medium_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fd", "man_and_woman_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fe", "woman_and_man_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fe", "couple_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3fe", "man_and_woman_holding_hands_light_skin_tone_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3ff", "woman_and_man_holding_hands_light_skin_tone_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3ff", "couple_light_skin_tone_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f468-1f3ff", "man_and_woman_holding_hands_medium_light_skin_tone_light_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fb", "woman_and_man_holding_hands_medium_light_skin_tone_light_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fb", "couple_medium_light_skin_tone_light_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fb", "man_and_woman_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fd", "woman_and_man_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fd", "couple_medium_light_skin_tone_medium_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fd", "man_and_woman_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fe", "woman_and_man_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fe", "couple_medium_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3fe", "man_and_woman_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3ff", "woman_and_man_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3ff", "couple_medium_light_skin_tone_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f468-1f3ff", "man_and_woman_holding_hands_medium_skin_tone_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fb", "woman_and_man_holding_hands_medium_skin_tone_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fb", "couple_medium_skin_tone_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fb", "man_and_woman_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fc", "woman_and_man_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fc", "couple_medium_skin_tone_medium_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fc", "man_and_woman_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fe", "woman_and_man_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fe", "couple_medium_skin_tone_medium_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3fe", "man_and_woman_holding_hands_medium_skin_tone_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3ff", "woman_and_man_holding_hands_medium_skin_tone_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3ff", "couple_medium_skin_tone_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f468-1f3ff", "man_and_woman_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fb", "woman_and_man_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fb", "couple_medium_dark_skin_tone_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fb", "man_and_woman_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fc", "woman_and_man_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fc", "couple_medium_dark_skin_tone_medium_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fc", "man_and_woman_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fd", "woman_and_man_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fd", "couple_medium_dark_skin_tone_medium_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3fd", "man_and_woman_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3ff", "woman_and_man_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3ff", "couple_medium_dark_skin_tone_dark_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f468-1f3ff", "man_and_woman_holding_hands_dark_skin_tone_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fb", "woman_and_man_holding_hands_dark_skin_tone_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fb", "couple_dark_skin_tone_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fb", "man_and_woman_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fc", "woman_and_man_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fc", "couple_dark_skin_tone_medium_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fc", "man_and_woman_holding_hands_dark_skin_tone_medium_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fd", "woman_and_man_holding_hands_dark_skin_tone_medium_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fd", "couple_dark_skin_tone_medium_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fd", "man_and_woman_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fe", "woman_and_man_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fe", "couple_dark_skin_tone_medium_dark_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f468-1f3fe", "two_men_holding_hands_light_skin_tone": "1f46c-1f3fb", "men_holding_hands_light_skin_tone": "1f46c-1f3fb", "two_men_holding_hands_medium_light_skin_tone": "1f46c-1f3fc", "men_holding_hands_medium_light_skin_tone": "1f46c-1f3fc", "two_men_holding_hands_medium_skin_tone": "1f46c-1f3fd", "men_holding_hands_medium_skin_tone": "1f46c-1f3fd", "two_men_holding_hands_medium_dark_skin_tone": "1f46c-1f3fe", "men_holding_hands_medium_dark_skin_tone": "1f46c-1f3fe", "two_men_holding_hands_dark_skin_tone": "1f46c-1f3ff", "men_holding_hands_dark_skin_tone": "1f46c-1f3ff", "two_men_holding_hands_light_skin_tone_medium_light_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fc", "men_holding_hands_light_skin_tone_medium_light_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fc", "two_men_holding_hands_light_skin_tone_medium_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fd", "men_holding_hands_light_skin_tone_medium_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fd", "two_men_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fe", "men_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3fe", "two_men_holding_hands_light_skin_tone_dark_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3ff", "men_holding_hands_light_skin_tone_dark_skin_tone": "1f468-1f3fb-200d-1f91d-200d-1f468-1f3ff", "two_men_holding_hands_medium_light_skin_tone_light_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fb", "men_holding_hands_medium_light_skin_tone_light_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fb", "two_men_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fd", "men_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fd", "two_men_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fe", "men_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3fe", "two_men_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3ff", "men_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f468-1f3fc-200d-1f91d-200d-1f468-1f3ff", "two_men_holding_hands_medium_skin_tone_light_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fb", "men_holding_hands_medium_skin_tone_light_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fb", "two_men_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fc", "men_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fc", "two_men_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fe", "men_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3fe", "two_men_holding_hands_medium_skin_tone_dark_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3ff", "men_holding_hands_medium_skin_tone_dark_skin_tone": "1f468-1f3fd-200d-1f91d-200d-1f468-1f3ff", "two_men_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fb", "men_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fb", "two_men_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fc", "men_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fc", "two_men_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fd", "men_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3fd", "two_men_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3ff", "men_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f468-1f3fe-200d-1f91d-200d-1f468-1f3ff", "two_men_holding_hands_dark_skin_tone_light_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fb", "men_holding_hands_dark_skin_tone_light_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fb", "two_men_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fc", "men_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fc", "two_men_holding_hands_dark_skin_tone_medium_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fd", "men_holding_hands_dark_skin_tone_medium_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fd", "two_men_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fe", "men_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f468-1f3ff-200d-1f91d-200d-1f468-1f3fe", "two_women_holding_hands_light_skin_tone": "1f46d-1f3fb", "women_holding_hands_light_skin_tone": "1f46d-1f3fb", "two_women_holding_hands_medium_light_skin_tone": "1f46d-1f3fc", "women_holding_hands_medium_light_skin_tone": "1f46d-1f3fc", "two_women_holding_hands_medium_skin_tone": "1f46d-1f3fd", "women_holding_hands_medium_skin_tone": "1f46d-1f3fd", "two_women_holding_hands_medium_dark_skin_tone": "1f46d-1f3fe", "women_holding_hands_medium_dark_skin_tone": "1f46d-1f3fe", "two_women_holding_hands_dark_skin_tone": "1f46d-1f3ff", "women_holding_hands_dark_skin_tone": "1f46d-1f3ff", "two_women_holding_hands_light_skin_tone_medium_light_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fc", "women_holding_hands_light_skin_tone_medium_light_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fc", "two_women_holding_hands_light_skin_tone_medium_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fd", "women_holding_hands_light_skin_tone_medium_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fd", "two_women_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fe", "women_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3fe", "two_women_holding_hands_light_skin_tone_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3ff", "women_holding_hands_light_skin_tone_dark_skin_tone": "1f469-1f3fb-200d-1f91d-200d-1f469-1f3ff", "two_women_holding_hands_medium_light_skin_tone_light_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fb", "women_holding_hands_medium_light_skin_tone_light_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fb", "two_women_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fd", "women_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fd", "two_women_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fe", "women_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3fe", "two_women_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3ff", "women_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f469-1f3fc-200d-1f91d-200d-1f469-1f3ff", "two_women_holding_hands_medium_skin_tone_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fb", "women_holding_hands_medium_skin_tone_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fb", "two_women_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fc", "women_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fc", "two_women_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fe", "women_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3fe", "two_women_holding_hands_medium_skin_tone_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3ff", "women_holding_hands_medium_skin_tone_dark_skin_tone": "1f469-1f3fd-200d-1f91d-200d-1f469-1f3ff", "two_women_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fb", "women_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fb", "two_women_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fc", "women_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fc", "two_women_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fd", "women_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3fd", "two_women_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3ff", "women_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f469-1f3fe-200d-1f91d-200d-1f469-1f3ff", "two_women_holding_hands_dark_skin_tone_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fb", "women_holding_hands_dark_skin_tone_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fb", "two_women_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fc", "women_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fc", "two_women_holding_hands_dark_skin_tone_medium_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fd", "women_holding_hands_dark_skin_tone_medium_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fd", "two_women_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fe", "women_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f469-1f3ff-200d-1f91d-200d-1f469-1f3fe", "female-police-officer_light_skin_tone": "1f46e-1f3fb-200d-2640-fe0f", "policewoman_light_skin_tone": "1f46e-1f3fb-200d-2640-fe0f", "female-police-officer_medium_light_skin_tone": "1f46e-1f3fc-200d-2640-fe0f", "policewoman_medium_light_skin_tone": "1f46e-1f3fc-200d-2640-fe0f", "female-police-officer_medium_skin_tone": "1f46e-1f3fd-200d-2640-fe0f", "policewoman_medium_skin_tone": "1f46e-1f3fd-200d-2640-fe0f", "female-police-officer_medium_dark_skin_tone": "1f46e-1f3fe-200d-2640-fe0f", "policewoman_medium_dark_skin_tone": "1f46e-1f3fe-200d-2640-fe0f", "female-police-officer_dark_skin_tone": "1f46e-1f3ff-200d-2640-fe0f", "policewoman_dark_skin_tone": "1f46e-1f3ff-200d-2640-fe0f", "male-police-officer_light_skin_tone": "1f46e-1f3fb-200d-2642-fe0f", "policeman_light_skin_tone": "1f46e-1f3fb-200d-2642-fe0f", "male-police-officer_medium_light_skin_tone": "1f46e-1f3fc-200d-2642-fe0f", "policeman_medium_light_skin_tone": "1f46e-1f3fc-200d-2642-fe0f", "male-police-officer_medium_skin_tone": "1f46e-1f3fd-200d-2642-fe0f", "policeman_medium_skin_tone": "1f46e-1f3fd-200d-2642-fe0f", "male-police-officer_medium_dark_skin_tone": "1f46e-1f3fe-200d-2642-fe0f", "policeman_medium_dark_skin_tone": "1f46e-1f3fe-200d-2642-fe0f", "male-police-officer_dark_skin_tone": "1f46e-1f3ff-200d-2642-fe0f", "policeman_dark_skin_tone": "1f46e-1f3ff-200d-2642-fe0f", "cop_light_skin_tone": "1f46e-1f3fb", "cop_medium_light_skin_tone": "1f46e-1f3fc", "cop_medium_skin_tone": "1f46e-1f3fd", "cop_medium_dark_skin_tone": "1f46e-1f3fe", "cop_dark_skin_tone": "1f46e-1f3ff", "woman_with_veil_light_skin_tone": "1f470-1f3fb-200d-2640-fe0f", "woman_with_veil_medium_light_skin_tone": "1f470-1f3fc-200d-2640-fe0f", "woman_with_veil_medium_skin_tone": "1f470-1f3fd-200d-2640-fe0f", "woman_with_veil_medium_dark_skin_tone": "1f470-1f3fe-200d-2640-fe0f", "woman_with_veil_dark_skin_tone": "1f470-1f3ff-200d-2640-fe0f", "man_with_veil_light_skin_tone": "1f470-1f3fb-200d-2642-fe0f", "man_with_veil_medium_light_skin_tone": "1f470-1f3fc-200d-2642-fe0f", "man_with_veil_medium_skin_tone": "1f470-1f3fd-200d-2642-fe0f", "man_with_veil_medium_dark_skin_tone": "1f470-1f3fe-200d-2642-fe0f", "man_with_veil_dark_skin_tone": "1f470-1f3ff-200d-2642-fe0f", "bride_with_veil_light_skin_tone": "1f470-1f3fb", "bride_with_veil_medium_light_skin_tone": "1f470-1f3fc", "bride_with_veil_medium_skin_tone": "1f470-1f3fd", "bride_with_veil_medium_dark_skin_tone": "1f470-1f3fe", "bride_with_veil_dark_skin_tone": "1f470-1f3ff", "blond-haired-woman_light_skin_tone": "1f471-1f3fb-200d-2640-fe0f", "blonde_woman_light_skin_tone": "1f471-1f3fb-200d-2640-fe0f", "blond-haired-woman_medium_light_skin_tone": "1f471-1f3fc-200d-2640-fe0f", "blonde_woman_medium_light_skin_tone": "1f471-1f3fc-200d-2640-fe0f", "blond-haired-woman_medium_skin_tone": "1f471-1f3fd-200d-2640-fe0f", "blonde_woman_medium_skin_tone": "1f471-1f3fd-200d-2640-fe0f", "blond-haired-woman_medium_dark_skin_tone": "1f471-1f3fe-200d-2640-fe0f", "blonde_woman_medium_dark_skin_tone": "1f471-1f3fe-200d-2640-fe0f", "blond-haired-woman_dark_skin_tone": "1f471-1f3ff-200d-2640-fe0f", "blonde_woman_dark_skin_tone": "1f471-1f3ff-200d-2640-fe0f", "blond-haired-man_light_skin_tone": "1f471-1f3fb-200d-2642-fe0f", "blonde_man_light_skin_tone": "1f471-1f3fb-200d-2642-fe0f", "blond-haired-man_medium_light_skin_tone": "1f471-1f3fc-200d-2642-fe0f", "blonde_man_medium_light_skin_tone": "1f471-1f3fc-200d-2642-fe0f", "blond-haired-man_medium_skin_tone": "1f471-1f3fd-200d-2642-fe0f", "blonde_man_medium_skin_tone": "1f471-1f3fd-200d-2642-fe0f", "blond-haired-man_medium_dark_skin_tone": "1f471-1f3fe-200d-2642-fe0f", "blonde_man_medium_dark_skin_tone": "1f471-1f3fe-200d-2642-fe0f", "blond-haired-man_dark_skin_tone": "1f471-1f3ff-200d-2642-fe0f", "blonde_man_dark_skin_tone": "1f471-1f3ff-200d-2642-fe0f", "person_with_blond_hair_light_skin_tone": "1f471-1f3fb", "person_with_blond_hair_medium_light_skin_tone": "1f471-1f3fc", "person_with_blond_hair_medium_skin_tone": "1f471-1f3fd", "person_with_blond_hair_medium_dark_skin_tone": "1f471-1f3fe", "person_with_blond_hair_dark_skin_tone": "1f471-1f3ff", "man_with_gua_pi_mao_light_skin_tone": "1f472-1f3fb", "man_with_gua_pi_mao_medium_light_skin_tone": "1f472-1f3fc", "man_with_gua_pi_mao_medium_skin_tone": "1f472-1f3fd", "man_with_gua_pi_mao_medium_dark_skin_tone": "1f472-1f3fe", "man_with_gua_pi_mao_dark_skin_tone": "1f472-1f3ff", "woman-wearing-turban_light_skin_tone": "1f473-1f3fb-200d-2640-fe0f", "woman_with_turban_light_skin_tone": "1f473-1f3fb-200d-2640-fe0f", "woman-wearing-turban_medium_light_skin_tone": "1f473-1f3fc-200d-2640-fe0f", "woman_with_turban_medium_light_skin_tone": "1f473-1f3fc-200d-2640-fe0f", "woman-wearing-turban_medium_skin_tone": "1f473-1f3fd-200d-2640-fe0f", "woman_with_turban_medium_skin_tone": "1f473-1f3fd-200d-2640-fe0f", "woman-wearing-turban_medium_dark_skin_tone": "1f473-1f3fe-200d-2640-fe0f", "woman_with_turban_medium_dark_skin_tone": "1f473-1f3fe-200d-2640-fe0f", "woman-wearing-turban_dark_skin_tone": "1f473-1f3ff-200d-2640-fe0f", "woman_with_turban_dark_skin_tone": "1f473-1f3ff-200d-2640-fe0f", "man-wearing-turban_light_skin_tone": "1f473-1f3fb-200d-2642-fe0f", "man-wearing-turban_medium_light_skin_tone": "1f473-1f3fc-200d-2642-fe0f", "man-wearing-turban_medium_skin_tone": "1f473-1f3fd-200d-2642-fe0f", "man-wearing-turban_medium_dark_skin_tone": "1f473-1f3fe-200d-2642-fe0f", "man-wearing-turban_dark_skin_tone": "1f473-1f3ff-200d-2642-fe0f", "man_with_turban_light_skin_tone": "1f473-1f3fb", "man_with_turban_medium_light_skin_tone": "1f473-1f3fc", "man_with_turban_medium_skin_tone": "1f473-1f3fd", "man_with_turban_medium_dark_skin_tone": "1f473-1f3fe", "man_with_turban_dark_skin_tone": "1f473-1f3ff", "older_man_light_skin_tone": "1f474-1f3fb", "older_man_medium_light_skin_tone": "1f474-1f3fc", "older_man_medium_skin_tone": "1f474-1f3fd", "older_man_medium_dark_skin_tone": "1f474-1f3fe", "older_man_dark_skin_tone": "1f474-1f3ff", "older_woman_light_skin_tone": "1f475-1f3fb", "older_woman_medium_light_skin_tone": "1f475-1f3fc", "older_woman_medium_skin_tone": "1f475-1f3fd", "older_woman_medium_dark_skin_tone": "1f475-1f3fe", "older_woman_dark_skin_tone": "1f475-1f3ff", "baby_light_skin_tone": "1f476-1f3fb", "baby_medium_light_skin_tone": "1f476-1f3fc", "baby_medium_skin_tone": "1f476-1f3fd", "baby_medium_dark_skin_tone": "1f476-1f3fe", "baby_dark_skin_tone": "1f476-1f3ff", "female-construction-worker_light_skin_tone": "1f477-1f3fb-200d-2640-fe0f", "construction_worker_woman_light_skin_tone": "1f477-1f3fb-200d-2640-fe0f", "female-construction-worker_medium_light_skin_tone": "1f477-1f3fc-200d-2640-fe0f", "construction_worker_woman_medium_light_skin_tone": "1f477-1f3fc-200d-2640-fe0f", "female-construction-worker_medium_skin_tone": "1f477-1f3fd-200d-2640-fe0f", "construction_worker_woman_medium_skin_tone": "1f477-1f3fd-200d-2640-fe0f", "female-construction-worker_medium_dark_skin_tone": "1f477-1f3fe-200d-2640-fe0f", "construction_worker_woman_medium_dark_skin_tone": "1f477-1f3fe-200d-2640-fe0f", "female-construction-worker_dark_skin_tone": "1f477-1f3ff-200d-2640-fe0f", "construction_worker_woman_dark_skin_tone": "1f477-1f3ff-200d-2640-fe0f", "male-construction-worker_light_skin_tone": "1f477-1f3fb-200d-2642-fe0f", "construction_worker_man_light_skin_tone": "1f477-1f3fb-200d-2642-fe0f", "male-construction-worker_medium_light_skin_tone": "1f477-1f3fc-200d-2642-fe0f", "construction_worker_man_medium_light_skin_tone": "1f477-1f3fc-200d-2642-fe0f", "male-construction-worker_medium_skin_tone": "1f477-1f3fd-200d-2642-fe0f", "construction_worker_man_medium_skin_tone": "1f477-1f3fd-200d-2642-fe0f", "male-construction-worker_medium_dark_skin_tone": "1f477-1f3fe-200d-2642-fe0f", "construction_worker_man_medium_dark_skin_tone": "1f477-1f3fe-200d-2642-fe0f", "male-construction-worker_dark_skin_tone": "1f477-1f3ff-200d-2642-fe0f", "construction_worker_man_dark_skin_tone": "1f477-1f3ff-200d-2642-fe0f", "construction_worker_light_skin_tone": "1f477-1f3fb", "construction_worker_medium_light_skin_tone": "1f477-1f3fc", "construction_worker_medium_skin_tone": "1f477-1f3fd", "construction_worker_medium_dark_skin_tone": "1f477-1f3fe", "construction_worker_dark_skin_tone": "1f477-1f3ff", "princess_light_skin_tone": "1f478-1f3fb", "princess_medium_light_skin_tone": "1f478-1f3fc", "princess_medium_skin_tone": "1f478-1f3fd", "princess_medium_dark_skin_tone": "1f478-1f3fe", "princess_dark_skin_tone": "1f478-1f3ff", "angel_light_skin_tone": "1f47c-1f3fb", "angel_medium_light_skin_tone": "1f47c-1f3fc", "angel_medium_skin_tone": "1f47c-1f3fd", "angel_medium_dark_skin_tone": "1f47c-1f3fe", "angel_dark_skin_tone": "1f47c-1f3ff", "woman-tipping-hand_light_skin_tone": "1f481-1f3fb-200d-2640-fe0f", "tipping_hand_woman_light_skin_tone": "1f481-1f3fb-200d-2640-fe0f", "woman-tipping-hand_medium_light_skin_tone": "1f481-1f3fc-200d-2640-fe0f", "tipping_hand_woman_medium_light_skin_tone": "1f481-1f3fc-200d-2640-fe0f", "woman-tipping-hand_medium_skin_tone": "1f481-1f3fd-200d-2640-fe0f", "tipping_hand_woman_medium_skin_tone": "1f481-1f3fd-200d-2640-fe0f", "woman-tipping-hand_medium_dark_skin_tone": "1f481-1f3fe-200d-2640-fe0f", "tipping_hand_woman_medium_dark_skin_tone": "1f481-1f3fe-200d-2640-fe0f", "woman-tipping-hand_dark_skin_tone": "1f481-1f3ff-200d-2640-fe0f", "tipping_hand_woman_dark_skin_tone": "1f481-1f3ff-200d-2640-fe0f", "man-tipping-hand_light_skin_tone": "1f481-1f3fb-200d-2642-fe0f", "tipping_hand_man_light_skin_tone": "1f481-1f3fb-200d-2642-fe0f", "man-tipping-hand_medium_light_skin_tone": "1f481-1f3fc-200d-2642-fe0f", "tipping_hand_man_medium_light_skin_tone": "1f481-1f3fc-200d-2642-fe0f", "man-tipping-hand_medium_skin_tone": "1f481-1f3fd-200d-2642-fe0f", "tipping_hand_man_medium_skin_tone": "1f481-1f3fd-200d-2642-fe0f", "man-tipping-hand_medium_dark_skin_tone": "1f481-1f3fe-200d-2642-fe0f", "tipping_hand_man_medium_dark_skin_tone": "1f481-1f3fe-200d-2642-fe0f", "man-tipping-hand_dark_skin_tone": "1f481-1f3ff-200d-2642-fe0f", "tipping_hand_man_dark_skin_tone": "1f481-1f3ff-200d-2642-fe0f", "information_desk_person_light_skin_tone": "1f481-1f3fb", "information_desk_person_medium_light_skin_tone": "1f481-1f3fc", "information_desk_person_medium_skin_tone": "1f481-1f3fd", "information_desk_person_medium_dark_skin_tone": "1f481-1f3fe", "information_desk_person_dark_skin_tone": "1f481-1f3ff", "female-guard_light_skin_tone": "1f482-1f3fb-200d-2640-fe0f", "guardswoman_light_skin_tone": "1f482-1f3fb-200d-2640-fe0f", "female-guard_medium_light_skin_tone": "1f482-1f3fc-200d-2640-fe0f", "guardswoman_medium_light_skin_tone": "1f482-1f3fc-200d-2640-fe0f", "female-guard_medium_skin_tone": "1f482-1f3fd-200d-2640-fe0f", "guardswoman_medium_skin_tone": "1f482-1f3fd-200d-2640-fe0f", "female-guard_medium_dark_skin_tone": "1f482-1f3fe-200d-2640-fe0f", "guardswoman_medium_dark_skin_tone": "1f482-1f3fe-200d-2640-fe0f", "female-guard_dark_skin_tone": "1f482-1f3ff-200d-2640-fe0f", "guardswoman_dark_skin_tone": "1f482-1f3ff-200d-2640-fe0f", "male-guard_light_skin_tone": "1f482-1f3fb-200d-2642-fe0f", "male-guard_medium_light_skin_tone": "1f482-1f3fc-200d-2642-fe0f", "male-guard_medium_skin_tone": "1f482-1f3fd-200d-2642-fe0f", "male-guard_medium_dark_skin_tone": "1f482-1f3fe-200d-2642-fe0f", "male-guard_dark_skin_tone": "1f482-1f3ff-200d-2642-fe0f", "guardsman_light_skin_tone": "1f482-1f3fb", "guardsman_medium_light_skin_tone": "1f482-1f3fc", "guardsman_medium_skin_tone": "1f482-1f3fd", "guardsman_medium_dark_skin_tone": "1f482-1f3fe", "guardsman_dark_skin_tone": "1f482-1f3ff", "dancer_light_skin_tone": "1f483-1f3fb", "dancer_medium_light_skin_tone": "1f483-1f3fc", "dancer_medium_skin_tone": "1f483-1f3fd", "dancer_medium_dark_skin_tone": "1f483-1f3fe", "dancer_dark_skin_tone": "1f483-1f3ff", "nail_care_light_skin_tone": "1f485-1f3fb", "nail_care_medium_light_skin_tone": "1f485-1f3fc", "nail_care_medium_skin_tone": "1f485-1f3fd", "nail_care_medium_dark_skin_tone": "1f485-1f3fe", "nail_care_dark_skin_tone": "1f485-1f3ff", "woman-getting-massage_light_skin_tone": "1f486-1f3fb-200d-2640-fe0f", "massage_woman_light_skin_tone": "1f486-1f3fb-200d-2640-fe0f", "woman-getting-massage_medium_light_skin_tone": "1f486-1f3fc-200d-2640-fe0f", "massage_woman_medium_light_skin_tone": "1f486-1f3fc-200d-2640-fe0f", "woman-getting-massage_medium_skin_tone": "1f486-1f3fd-200d-2640-fe0f", "massage_woman_medium_skin_tone": "1f486-1f3fd-200d-2640-fe0f", "woman-getting-massage_medium_dark_skin_tone": "1f486-1f3fe-200d-2640-fe0f", "massage_woman_medium_dark_skin_tone": "1f486-1f3fe-200d-2640-fe0f", "woman-getting-massage_dark_skin_tone": "1f486-1f3ff-200d-2640-fe0f", "massage_woman_dark_skin_tone": "1f486-1f3ff-200d-2640-fe0f", "man-getting-massage_light_skin_tone": "1f486-1f3fb-200d-2642-fe0f", "massage_man_light_skin_tone": "1f486-1f3fb-200d-2642-fe0f", "man-getting-massage_medium_light_skin_tone": "1f486-1f3fc-200d-2642-fe0f", "massage_man_medium_light_skin_tone": "1f486-1f3fc-200d-2642-fe0f", "man-getting-massage_medium_skin_tone": "1f486-1f3fd-200d-2642-fe0f", "massage_man_medium_skin_tone": "1f486-1f3fd-200d-2642-fe0f", "man-getting-massage_medium_dark_skin_tone": "1f486-1f3fe-200d-2642-fe0f", "massage_man_medium_dark_skin_tone": "1f486-1f3fe-200d-2642-fe0f", "man-getting-massage_dark_skin_tone": "1f486-1f3ff-200d-2642-fe0f", "massage_man_dark_skin_tone": "1f486-1f3ff-200d-2642-fe0f", "massage_light_skin_tone": "1f486-1f3fb", "massage_medium_light_skin_tone": "1f486-1f3fc", "massage_medium_skin_tone": "1f486-1f3fd", "massage_medium_dark_skin_tone": "1f486-1f3fe", "massage_dark_skin_tone": "1f486-1f3ff", "woman-getting-haircut_light_skin_tone": "1f487-1f3fb-200d-2640-fe0f", "haircut_woman_light_skin_tone": "1f487-1f3fb-200d-2640-fe0f", "woman-getting-haircut_medium_light_skin_tone": "1f487-1f3fc-200d-2640-fe0f", "haircut_woman_medium_light_skin_tone": "1f487-1f3fc-200d-2640-fe0f", "woman-getting-haircut_medium_skin_tone": "1f487-1f3fd-200d-2640-fe0f", "haircut_woman_medium_skin_tone": "1f487-1f3fd-200d-2640-fe0f", "woman-getting-haircut_medium_dark_skin_tone": "1f487-1f3fe-200d-2640-fe0f", "haircut_woman_medium_dark_skin_tone": "1f487-1f3fe-200d-2640-fe0f", "woman-getting-haircut_dark_skin_tone": "1f487-1f3ff-200d-2640-fe0f", "haircut_woman_dark_skin_tone": "1f487-1f3ff-200d-2640-fe0f", "man-getting-haircut_light_skin_tone": "1f487-1f3fb-200d-2642-fe0f", "haircut_man_light_skin_tone": "1f487-1f3fb-200d-2642-fe0f", "man-getting-haircut_medium_light_skin_tone": "1f487-1f3fc-200d-2642-fe0f", "haircut_man_medium_light_skin_tone": "1f487-1f3fc-200d-2642-fe0f", "man-getting-haircut_medium_skin_tone": "1f487-1f3fd-200d-2642-fe0f", "haircut_man_medium_skin_tone": "1f487-1f3fd-200d-2642-fe0f", "man-getting-haircut_medium_dark_skin_tone": "1f487-1f3fe-200d-2642-fe0f", "haircut_man_medium_dark_skin_tone": "1f487-1f3fe-200d-2642-fe0f", "man-getting-haircut_dark_skin_tone": "1f487-1f3ff-200d-2642-fe0f", "haircut_man_dark_skin_tone": "1f487-1f3ff-200d-2642-fe0f", "haircut_light_skin_tone": "1f487-1f3fb", "haircut_medium_light_skin_tone": "1f487-1f3fc", "haircut_medium_skin_tone": "1f487-1f3fd", "haircut_medium_dark_skin_tone": "1f487-1f3fe", "haircut_dark_skin_tone": "1f487-1f3ff", "muscle_light_skin_tone": "1f4aa-1f3fb", "muscle_medium_light_skin_tone": "1f4aa-1f3fc", "muscle_medium_skin_tone": "1f4aa-1f3fd", "muscle_medium_dark_skin_tone": "1f4aa-1f3fe", "muscle_dark_skin_tone": "1f4aa-1f3ff", "man_in_business_suit_levitating_light_skin_tone": "1f574-1f3fb", "business_suit_levitating_light_skin_tone": "1f574-1f3fb", "man_in_business_suit_levitating_medium_light_skin_tone": "1f574-1f3fc", "business_suit_levitating_medium_light_skin_tone": "1f574-1f3fc", "man_in_business_suit_levitating_medium_skin_tone": "1f574-1f3fd", "business_suit_levitating_medium_skin_tone": "1f574-1f3fd", "man_in_business_suit_levitating_medium_dark_skin_tone": "1f574-1f3fe", "business_suit_levitating_medium_dark_skin_tone": "1f574-1f3fe", "man_in_business_suit_levitating_dark_skin_tone": "1f574-1f3ff", "business_suit_levitating_dark_skin_tone": "1f574-1f3ff", "female-detective_light_skin_tone": "1f575-1f3fb-200d-2640-fe0f", "female_detective_light_skin_tone": "1f575-1f3fb-200d-2640-fe0f", "female-detective_medium_light_skin_tone": "1f575-1f3fc-200d-2640-fe0f", "female_detective_medium_light_skin_tone": "1f575-1f3fc-200d-2640-fe0f", "female-detective_medium_skin_tone": "1f575-1f3fd-200d-2640-fe0f", "female_detective_medium_skin_tone": "1f575-1f3fd-200d-2640-fe0f", "female-detective_medium_dark_skin_tone": "1f575-1f3fe-200d-2640-fe0f", "female_detective_medium_dark_skin_tone": "1f575-1f3fe-200d-2640-fe0f", "female-detective_dark_skin_tone": "1f575-1f3ff-200d-2640-fe0f", "female_detective_dark_skin_tone": "1f575-1f3ff-200d-2640-fe0f", "male-detective_light_skin_tone": "1f575-1f3fb-200d-2642-fe0f", "male_detective_light_skin_tone": "1f575-1f3fb-200d-2642-fe0f", "male-detective_medium_light_skin_tone": "1f575-1f3fc-200d-2642-fe0f", "male_detective_medium_light_skin_tone": "1f575-1f3fc-200d-2642-fe0f", "male-detective_medium_skin_tone": "1f575-1f3fd-200d-2642-fe0f", "male_detective_medium_skin_tone": "1f575-1f3fd-200d-2642-fe0f", "male-detective_medium_dark_skin_tone": "1f575-1f3fe-200d-2642-fe0f", "male_detective_medium_dark_skin_tone": "1f575-1f3fe-200d-2642-fe0f", "male-detective_dark_skin_tone": "1f575-1f3ff-200d-2642-fe0f", "male_detective_dark_skin_tone": "1f575-1f3ff-200d-2642-fe0f", "sleuth_or_spy_light_skin_tone": "1f575-1f3fb", "sleuth_or_spy_medium_light_skin_tone": "1f575-1f3fc", "sleuth_or_spy_medium_skin_tone": "1f575-1f3fd", "sleuth_or_spy_medium_dark_skin_tone": "1f575-1f3fe", "sleuth_or_spy_dark_skin_tone": "1f575-1f3ff", "man_dancing_light_skin_tone": "1f57a-1f3fb", "man_dancing_medium_light_skin_tone": "1f57a-1f3fc", "man_dancing_medium_skin_tone": "1f57a-1f3fd", "man_dancing_medium_dark_skin_tone": "1f57a-1f3fe", "man_dancing_dark_skin_tone": "1f57a-1f3ff", "raised_hand_with_fingers_splayed_light_skin_tone": "1f590-1f3fb", "raised_hand_with_fingers_splayed_medium_light_skin_tone": "1f590-1f3fc", "raised_hand_with_fingers_splayed_medium_skin_tone": "1f590-1f3fd", "raised_hand_with_fingers_splayed_medium_dark_skin_tone": "1f590-1f3fe", "raised_hand_with_fingers_splayed_dark_skin_tone": "1f590-1f3ff", "middle_finger_light_skin_tone": "1f595-1f3fb", "reversed_hand_with_middle_finger_extended_light_skin_tone": "1f595-1f3fb", "middle_finger_medium_light_skin_tone": "1f595-1f3fc", "reversed_hand_with_middle_finger_extended_medium_light_skin_tone": "1f595-1f3fc", "middle_finger_medium_skin_tone": "1f595-1f3fd", "reversed_hand_with_middle_finger_extended_medium_skin_tone": "1f595-1f3fd", "middle_finger_medium_dark_skin_tone": "1f595-1f3fe", "reversed_hand_with_middle_finger_extended_medium_dark_skin_tone": "1f595-1f3fe", "middle_finger_dark_skin_tone": "1f595-1f3ff", "reversed_hand_with_middle_finger_extended_dark_skin_tone": "1f595-1f3ff", "spock-hand_light_skin_tone": "1f596-1f3fb", "vulcan_salute_light_skin_tone": "1f596-1f3fb", "spock-hand_medium_light_skin_tone": "1f596-1f3fc", "vulcan_salute_medium_light_skin_tone": "1f596-1f3fc", "spock-hand_medium_skin_tone": "1f596-1f3fd", "vulcan_salute_medium_skin_tone": "1f596-1f3fd", "spock-hand_medium_dark_skin_tone": "1f596-1f3fe", "vulcan_salute_medium_dark_skin_tone": "1f596-1f3fe", "spock-hand_dark_skin_tone": "1f596-1f3ff", "vulcan_salute_dark_skin_tone": "1f596-1f3ff", "woman-gesturing-no_light_skin_tone": "1f645-1f3fb-200d-2640-fe0f", "no_good_woman_light_skin_tone": "1f645-1f3fb-200d-2640-fe0f", "woman-gesturing-no_medium_light_skin_tone": "1f645-1f3fc-200d-2640-fe0f", "no_good_woman_medium_light_skin_tone": "1f645-1f3fc-200d-2640-fe0f", "woman-gesturing-no_medium_skin_tone": "1f645-1f3fd-200d-2640-fe0f", "no_good_woman_medium_skin_tone": "1f645-1f3fd-200d-2640-fe0f", "woman-gesturing-no_medium_dark_skin_tone": "1f645-1f3fe-200d-2640-fe0f", "no_good_woman_medium_dark_skin_tone": "1f645-1f3fe-200d-2640-fe0f", "woman-gesturing-no_dark_skin_tone": "1f645-1f3ff-200d-2640-fe0f", "no_good_woman_dark_skin_tone": "1f645-1f3ff-200d-2640-fe0f", "man-gesturing-no_light_skin_tone": "1f645-1f3fb-200d-2642-fe0f", "no_good_man_light_skin_tone": "1f645-1f3fb-200d-2642-fe0f", "man-gesturing-no_medium_light_skin_tone": "1f645-1f3fc-200d-2642-fe0f", "no_good_man_medium_light_skin_tone": "1f645-1f3fc-200d-2642-fe0f", "man-gesturing-no_medium_skin_tone": "1f645-1f3fd-200d-2642-fe0f", "no_good_man_medium_skin_tone": "1f645-1f3fd-200d-2642-fe0f", "man-gesturing-no_medium_dark_skin_tone": "1f645-1f3fe-200d-2642-fe0f", "no_good_man_medium_dark_skin_tone": "1f645-1f3fe-200d-2642-fe0f", "man-gesturing-no_dark_skin_tone": "1f645-1f3ff-200d-2642-fe0f", "no_good_man_dark_skin_tone": "1f645-1f3ff-200d-2642-fe0f", "no_good_light_skin_tone": "1f645-1f3fb", "no_good_medium_light_skin_tone": "1f645-1f3fc", "no_good_medium_skin_tone": "1f645-1f3fd", "no_good_medium_dark_skin_tone": "1f645-1f3fe", "no_good_dark_skin_tone": "1f645-1f3ff", "woman-gesturing-ok_light_skin_tone": "1f646-1f3fb-200d-2640-fe0f", "woman-gesturing-ok_medium_light_skin_tone": "1f646-1f3fc-200d-2640-fe0f", "woman-gesturing-ok_medium_skin_tone": "1f646-1f3fd-200d-2640-fe0f", "woman-gesturing-ok_medium_dark_skin_tone": "1f646-1f3fe-200d-2640-fe0f", "woman-gesturing-ok_dark_skin_tone": "1f646-1f3ff-200d-2640-fe0f", "man-gesturing-ok_light_skin_tone": "1f646-1f3fb-200d-2642-fe0f", "ok_man_light_skin_tone": "1f646-1f3fb-200d-2642-fe0f", "man-gesturing-ok_medium_light_skin_tone": "1f646-1f3fc-200d-2642-fe0f", "ok_man_medium_light_skin_tone": "1f646-1f3fc-200d-2642-fe0f", "man-gesturing-ok_medium_skin_tone": "1f646-1f3fd-200d-2642-fe0f", "ok_man_medium_skin_tone": "1f646-1f3fd-200d-2642-fe0f", "man-gesturing-ok_medium_dark_skin_tone": "1f646-1f3fe-200d-2642-fe0f", "ok_man_medium_dark_skin_tone": "1f646-1f3fe-200d-2642-fe0f", "man-gesturing-ok_dark_skin_tone": "1f646-1f3ff-200d-2642-fe0f", "ok_man_dark_skin_tone": "1f646-1f3ff-200d-2642-fe0f", "ok_woman_light_skin_tone": "1f646-1f3fb", "ok_woman_medium_light_skin_tone": "1f646-1f3fc", "ok_woman_medium_skin_tone": "1f646-1f3fd", "ok_woman_medium_dark_skin_tone": "1f646-1f3fe", "ok_woman_dark_skin_tone": "1f646-1f3ff", "woman-bowing_light_skin_tone": "1f647-1f3fb-200d-2640-fe0f", "bowing_woman_light_skin_tone": "1f647-1f3fb-200d-2640-fe0f", "woman-bowing_medium_light_skin_tone": "1f647-1f3fc-200d-2640-fe0f", "bowing_woman_medium_light_skin_tone": "1f647-1f3fc-200d-2640-fe0f", "woman-bowing_medium_skin_tone": "1f647-1f3fd-200d-2640-fe0f", "bowing_woman_medium_skin_tone": "1f647-1f3fd-200d-2640-fe0f", "woman-bowing_medium_dark_skin_tone": "1f647-1f3fe-200d-2640-fe0f", "bowing_woman_medium_dark_skin_tone": "1f647-1f3fe-200d-2640-fe0f", "woman-bowing_dark_skin_tone": "1f647-1f3ff-200d-2640-fe0f", "bowing_woman_dark_skin_tone": "1f647-1f3ff-200d-2640-fe0f", "man-bowing_light_skin_tone": "1f647-1f3fb-200d-2642-fe0f", "bowing_man_light_skin_tone": "1f647-1f3fb-200d-2642-fe0f", "man-bowing_medium_light_skin_tone": "1f647-1f3fc-200d-2642-fe0f", "bowing_man_medium_light_skin_tone": "1f647-1f3fc-200d-2642-fe0f", "man-bowing_medium_skin_tone": "1f647-1f3fd-200d-2642-fe0f", "bowing_man_medium_skin_tone": "1f647-1f3fd-200d-2642-fe0f", "man-bowing_medium_dark_skin_tone": "1f647-1f3fe-200d-2642-fe0f", "bowing_man_medium_dark_skin_tone": "1f647-1f3fe-200d-2642-fe0f", "man-bowing_dark_skin_tone": "1f647-1f3ff-200d-2642-fe0f", "bowing_man_dark_skin_tone": "1f647-1f3ff-200d-2642-fe0f", "bow_light_skin_tone": "1f647-1f3fb", "bow_medium_light_skin_tone": "1f647-1f3fc", "bow_medium_skin_tone": "1f647-1f3fd", "bow_medium_dark_skin_tone": "1f647-1f3fe", "bow_dark_skin_tone": "1f647-1f3ff", "woman-raising-hand_light_skin_tone": "1f64b-1f3fb-200d-2640-fe0f", "raising_hand_woman_light_skin_tone": "1f64b-1f3fb-200d-2640-fe0f", "woman-raising-hand_medium_light_skin_tone": "1f64b-1f3fc-200d-2640-fe0f", "raising_hand_woman_medium_light_skin_tone": "1f64b-1f3fc-200d-2640-fe0f", "woman-raising-hand_medium_skin_tone": "1f64b-1f3fd-200d-2640-fe0f", "raising_hand_woman_medium_skin_tone": "1f64b-1f3fd-200d-2640-fe0f", "woman-raising-hand_medium_dark_skin_tone": "1f64b-1f3fe-200d-2640-fe0f", "raising_hand_woman_medium_dark_skin_tone": "1f64b-1f3fe-200d-2640-fe0f", "woman-raising-hand_dark_skin_tone": "1f64b-1f3ff-200d-2640-fe0f", "raising_hand_woman_dark_skin_tone": "1f64b-1f3ff-200d-2640-fe0f", "man-raising-hand_light_skin_tone": "1f64b-1f3fb-200d-2642-fe0f", "raising_hand_man_light_skin_tone": "1f64b-1f3fb-200d-2642-fe0f", "man-raising-hand_medium_light_skin_tone": "1f64b-1f3fc-200d-2642-fe0f", "raising_hand_man_medium_light_skin_tone": "1f64b-1f3fc-200d-2642-fe0f", "man-raising-hand_medium_skin_tone": "1f64b-1f3fd-200d-2642-fe0f", "raising_hand_man_medium_skin_tone": "1f64b-1f3fd-200d-2642-fe0f", "man-raising-hand_medium_dark_skin_tone": "1f64b-1f3fe-200d-2642-fe0f", "raising_hand_man_medium_dark_skin_tone": "1f64b-1f3fe-200d-2642-fe0f", "man-raising-hand_dark_skin_tone": "1f64b-1f3ff-200d-2642-fe0f", "raising_hand_man_dark_skin_tone": "1f64b-1f3ff-200d-2642-fe0f", "raising_hand_light_skin_tone": "1f64b-1f3fb", "raising_hand_medium_light_skin_tone": "1f64b-1f3fc", "raising_hand_medium_skin_tone": "1f64b-1f3fd", "raising_hand_medium_dark_skin_tone": "1f64b-1f3fe", "raising_hand_dark_skin_tone": "1f64b-1f3ff", "raised_hands_light_skin_tone": "1f64c-1f3fb", "raised_hands_medium_light_skin_tone": "1f64c-1f3fc", "raised_hands_medium_skin_tone": "1f64c-1f3fd", "raised_hands_medium_dark_skin_tone": "1f64c-1f3fe", "raised_hands_dark_skin_tone": "1f64c-1f3ff", "woman-frowning_light_skin_tone": "1f64d-1f3fb-200d-2640-fe0f", "frowning_woman_light_skin_tone": "1f64d-1f3fb-200d-2640-fe0f", "woman-frowning_medium_light_skin_tone": "1f64d-1f3fc-200d-2640-fe0f", "frowning_woman_medium_light_skin_tone": "1f64d-1f3fc-200d-2640-fe0f", "woman-frowning_medium_skin_tone": "1f64d-1f3fd-200d-2640-fe0f", "frowning_woman_medium_skin_tone": "1f64d-1f3fd-200d-2640-fe0f", "woman-frowning_medium_dark_skin_tone": "1f64d-1f3fe-200d-2640-fe0f", "frowning_woman_medium_dark_skin_tone": "1f64d-1f3fe-200d-2640-fe0f", "woman-frowning_dark_skin_tone": "1f64d-1f3ff-200d-2640-fe0f", "frowning_woman_dark_skin_tone": "1f64d-1f3ff-200d-2640-fe0f", "man-frowning_light_skin_tone": "1f64d-1f3fb-200d-2642-fe0f", "frowning_man_light_skin_tone": "1f64d-1f3fb-200d-2642-fe0f", "man-frowning_medium_light_skin_tone": "1f64d-1f3fc-200d-2642-fe0f", "frowning_man_medium_light_skin_tone": "1f64d-1f3fc-200d-2642-fe0f", "man-frowning_medium_skin_tone": "1f64d-1f3fd-200d-2642-fe0f", "frowning_man_medium_skin_tone": "1f64d-1f3fd-200d-2642-fe0f", "man-frowning_medium_dark_skin_tone": "1f64d-1f3fe-200d-2642-fe0f", "frowning_man_medium_dark_skin_tone": "1f64d-1f3fe-200d-2642-fe0f", "man-frowning_dark_skin_tone": "1f64d-1f3ff-200d-2642-fe0f", "frowning_man_dark_skin_tone": "1f64d-1f3ff-200d-2642-fe0f", "person_frowning_light_skin_tone": "1f64d-1f3fb", "person_frowning_medium_light_skin_tone": "1f64d-1f3fc", "person_frowning_medium_skin_tone": "1f64d-1f3fd", "person_frowning_medium_dark_skin_tone": "1f64d-1f3fe", "person_frowning_dark_skin_tone": "1f64d-1f3ff", "woman-pouting_light_skin_tone": "1f64e-1f3fb-200d-2640-fe0f", "pouting_woman_light_skin_tone": "1f64e-1f3fb-200d-2640-fe0f", "woman-pouting_medium_light_skin_tone": "1f64e-1f3fc-200d-2640-fe0f", "pouting_woman_medium_light_skin_tone": "1f64e-1f3fc-200d-2640-fe0f", "woman-pouting_medium_skin_tone": "1f64e-1f3fd-200d-2640-fe0f", "pouting_woman_medium_skin_tone": "1f64e-1f3fd-200d-2640-fe0f", "woman-pouting_medium_dark_skin_tone": "1f64e-1f3fe-200d-2640-fe0f", "pouting_woman_medium_dark_skin_tone": "1f64e-1f3fe-200d-2640-fe0f", "woman-pouting_dark_skin_tone": "1f64e-1f3ff-200d-2640-fe0f", "pouting_woman_dark_skin_tone": "1f64e-1f3ff-200d-2640-fe0f", "man-pouting_light_skin_tone": "1f64e-1f3fb-200d-2642-fe0f", "pouting_man_light_skin_tone": "1f64e-1f3fb-200d-2642-fe0f", "man-pouting_medium_light_skin_tone": "1f64e-1f3fc-200d-2642-fe0f", "pouting_man_medium_light_skin_tone": "1f64e-1f3fc-200d-2642-fe0f", "man-pouting_medium_skin_tone": "1f64e-1f3fd-200d-2642-fe0f", "pouting_man_medium_skin_tone": "1f64e-1f3fd-200d-2642-fe0f", "man-pouting_medium_dark_skin_tone": "1f64e-1f3fe-200d-2642-fe0f", "pouting_man_medium_dark_skin_tone": "1f64e-1f3fe-200d-2642-fe0f", "man-pouting_dark_skin_tone": "1f64e-1f3ff-200d-2642-fe0f", "pouting_man_dark_skin_tone": "1f64e-1f3ff-200d-2642-fe0f", "person_with_pouting_face_light_skin_tone": "1f64e-1f3fb", "person_with_pouting_face_medium_light_skin_tone": "1f64e-1f3fc", "person_with_pouting_face_medium_skin_tone": "1f64e-1f3fd", "person_with_pouting_face_medium_dark_skin_tone": "1f64e-1f3fe", "person_with_pouting_face_dark_skin_tone": "1f64e-1f3ff", "pray_light_skin_tone": "1f64f-1f3fb", "pray_medium_light_skin_tone": "1f64f-1f3fc", "pray_medium_skin_tone": "1f64f-1f3fd", "pray_medium_dark_skin_tone": "1f64f-1f3fe", "pray_dark_skin_tone": "1f64f-1f3ff", "woman-rowing-boat_light_skin_tone": "1f6a3-1f3fb-200d-2640-fe0f", "rowing_woman_light_skin_tone": "1f6a3-1f3fb-200d-2640-fe0f", "woman-rowing-boat_medium_light_skin_tone": "1f6a3-1f3fc-200d-2640-fe0f", "rowing_woman_medium_light_skin_tone": "1f6a3-1f3fc-200d-2640-fe0f", "woman-rowing-boat_medium_skin_tone": "1f6a3-1f3fd-200d-2640-fe0f", "rowing_woman_medium_skin_tone": "1f6a3-1f3fd-200d-2640-fe0f", "woman-rowing-boat_medium_dark_skin_tone": "1f6a3-1f3fe-200d-2640-fe0f", "rowing_woman_medium_dark_skin_tone": "1f6a3-1f3fe-200d-2640-fe0f", "woman-rowing-boat_dark_skin_tone": "1f6a3-1f3ff-200d-2640-fe0f", "rowing_woman_dark_skin_tone": "1f6a3-1f3ff-200d-2640-fe0f", "man-rowing-boat_light_skin_tone": "1f6a3-1f3fb-200d-2642-fe0f", "rowing_man_light_skin_tone": "1f6a3-1f3fb-200d-2642-fe0f", "man-rowing-boat_medium_light_skin_tone": "1f6a3-1f3fc-200d-2642-fe0f", "rowing_man_medium_light_skin_tone": "1f6a3-1f3fc-200d-2642-fe0f", "man-rowing-boat_medium_skin_tone": "1f6a3-1f3fd-200d-2642-fe0f", "rowing_man_medium_skin_tone": "1f6a3-1f3fd-200d-2642-fe0f", "man-rowing-boat_medium_dark_skin_tone": "1f6a3-1f3fe-200d-2642-fe0f", "rowing_man_medium_dark_skin_tone": "1f6a3-1f3fe-200d-2642-fe0f", "man-rowing-boat_dark_skin_tone": "1f6a3-1f3ff-200d-2642-fe0f", "rowing_man_dark_skin_tone": "1f6a3-1f3ff-200d-2642-fe0f", "rowboat_light_skin_tone": "1f6a3-1f3fb", "rowboat_medium_light_skin_tone": "1f6a3-1f3fc", "rowboat_medium_skin_tone": "1f6a3-1f3fd", "rowboat_medium_dark_skin_tone": "1f6a3-1f3fe", "rowboat_dark_skin_tone": "1f6a3-1f3ff", "woman-biking_light_skin_tone": "1f6b4-1f3fb-200d-2640-fe0f", "biking_woman_light_skin_tone": "1f6b4-1f3fb-200d-2640-fe0f", "woman-biking_medium_light_skin_tone": "1f6b4-1f3fc-200d-2640-fe0f", "biking_woman_medium_light_skin_tone": "1f6b4-1f3fc-200d-2640-fe0f", "woman-biking_medium_skin_tone": "1f6b4-1f3fd-200d-2640-fe0f", "biking_woman_medium_skin_tone": "1f6b4-1f3fd-200d-2640-fe0f", "woman-biking_medium_dark_skin_tone": "1f6b4-1f3fe-200d-2640-fe0f", "biking_woman_medium_dark_skin_tone": "1f6b4-1f3fe-200d-2640-fe0f", "woman-biking_dark_skin_tone": "1f6b4-1f3ff-200d-2640-fe0f", "biking_woman_dark_skin_tone": "1f6b4-1f3ff-200d-2640-fe0f", "man-biking_light_skin_tone": "1f6b4-1f3fb-200d-2642-fe0f", "biking_man_light_skin_tone": "1f6b4-1f3fb-200d-2642-fe0f", "man-biking_medium_light_skin_tone": "1f6b4-1f3fc-200d-2642-fe0f", "biking_man_medium_light_skin_tone": "1f6b4-1f3fc-200d-2642-fe0f", "man-biking_medium_skin_tone": "1f6b4-1f3fd-200d-2642-fe0f", "biking_man_medium_skin_tone": "1f6b4-1f3fd-200d-2642-fe0f", "man-biking_medium_dark_skin_tone": "1f6b4-1f3fe-200d-2642-fe0f", "biking_man_medium_dark_skin_tone": "1f6b4-1f3fe-200d-2642-fe0f", "man-biking_dark_skin_tone": "1f6b4-1f3ff-200d-2642-fe0f", "biking_man_dark_skin_tone": "1f6b4-1f3ff-200d-2642-fe0f", "bicyclist_light_skin_tone": "1f6b4-1f3fb", "bicyclist_medium_light_skin_tone": "1f6b4-1f3fc", "bicyclist_medium_skin_tone": "1f6b4-1f3fd", "bicyclist_medium_dark_skin_tone": "1f6b4-1f3fe", "bicyclist_dark_skin_tone": "1f6b4-1f3ff", "woman-mountain-biking_light_skin_tone": "1f6b5-1f3fb-200d-2640-fe0f", "mountain_biking_woman_light_skin_tone": "1f6b5-1f3fb-200d-2640-fe0f", "woman-mountain-biking_medium_light_skin_tone": "1f6b5-1f3fc-200d-2640-fe0f", "mountain_biking_woman_medium_light_skin_tone": "1f6b5-1f3fc-200d-2640-fe0f", "woman-mountain-biking_medium_skin_tone": "1f6b5-1f3fd-200d-2640-fe0f", "mountain_biking_woman_medium_skin_tone": "1f6b5-1f3fd-200d-2640-fe0f", "woman-mountain-biking_medium_dark_skin_tone": "1f6b5-1f3fe-200d-2640-fe0f", "mountain_biking_woman_medium_dark_skin_tone": "1f6b5-1f3fe-200d-2640-fe0f", "woman-mountain-biking_dark_skin_tone": "1f6b5-1f3ff-200d-2640-fe0f", "mountain_biking_woman_dark_skin_tone": "1f6b5-1f3ff-200d-2640-fe0f", "man-mountain-biking_light_skin_tone": "1f6b5-1f3fb-200d-2642-fe0f", "mountain_biking_man_light_skin_tone": "1f6b5-1f3fb-200d-2642-fe0f", "man-mountain-biking_medium_light_skin_tone": "1f6b5-1f3fc-200d-2642-fe0f", "mountain_biking_man_medium_light_skin_tone": "1f6b5-1f3fc-200d-2642-fe0f", "man-mountain-biking_medium_skin_tone": "1f6b5-1f3fd-200d-2642-fe0f", "mountain_biking_man_medium_skin_tone": "1f6b5-1f3fd-200d-2642-fe0f", "man-mountain-biking_medium_dark_skin_tone": "1f6b5-1f3fe-200d-2642-fe0f", "mountain_biking_man_medium_dark_skin_tone": "1f6b5-1f3fe-200d-2642-fe0f", "man-mountain-biking_dark_skin_tone": "1f6b5-1f3ff-200d-2642-fe0f", "mountain_biking_man_dark_skin_tone": "1f6b5-1f3ff-200d-2642-fe0f", "mountain_bicyclist_light_skin_tone": "1f6b5-1f3fb", "mountain_bicyclist_medium_light_skin_tone": "1f6b5-1f3fc", "mountain_bicyclist_medium_skin_tone": "1f6b5-1f3fd", "mountain_bicyclist_medium_dark_skin_tone": "1f6b5-1f3fe", "mountain_bicyclist_dark_skin_tone": "1f6b5-1f3ff", "woman-walking_light_skin_tone": "1f6b6-1f3fb-200d-2640-fe0f", "walking_woman_light_skin_tone": "1f6b6-1f3fb-200d-2640-fe0f", "woman-walking_medium_light_skin_tone": "1f6b6-1f3fc-200d-2640-fe0f", "walking_woman_medium_light_skin_tone": "1f6b6-1f3fc-200d-2640-fe0f", "woman-walking_medium_skin_tone": "1f6b6-1f3fd-200d-2640-fe0f", "walking_woman_medium_skin_tone": "1f6b6-1f3fd-200d-2640-fe0f", "woman-walking_medium_dark_skin_tone": "1f6b6-1f3fe-200d-2640-fe0f", "walking_woman_medium_dark_skin_tone": "1f6b6-1f3fe-200d-2640-fe0f", "woman-walking_dark_skin_tone": "1f6b6-1f3ff-200d-2640-fe0f", "walking_woman_dark_skin_tone": "1f6b6-1f3ff-200d-2640-fe0f", "man-walking_light_skin_tone": "1f6b6-1f3fb-200d-2642-fe0f", "walking_man_light_skin_tone": "1f6b6-1f3fb-200d-2642-fe0f", "man-walking_medium_light_skin_tone": "1f6b6-1f3fc-200d-2642-fe0f", "walking_man_medium_light_skin_tone": "1f6b6-1f3fc-200d-2642-fe0f", "man-walking_medium_skin_tone": "1f6b6-1f3fd-200d-2642-fe0f", "walking_man_medium_skin_tone": "1f6b6-1f3fd-200d-2642-fe0f", "man-walking_medium_dark_skin_tone": "1f6b6-1f3fe-200d-2642-fe0f", "walking_man_medium_dark_skin_tone": "1f6b6-1f3fe-200d-2642-fe0f", "man-walking_dark_skin_tone": "1f6b6-1f3ff-200d-2642-fe0f", "walking_man_dark_skin_tone": "1f6b6-1f3ff-200d-2642-fe0f", "walking_light_skin_tone": "1f6b6-1f3fb", "walking_medium_light_skin_tone": "1f6b6-1f3fc", "walking_medium_skin_tone": "1f6b6-1f3fd", "walking_medium_dark_skin_tone": "1f6b6-1f3fe", "walking_dark_skin_tone": "1f6b6-1f3ff", "bath_light_skin_tone": "1f6c0-1f3fb", "bath_medium_light_skin_tone": "1f6c0-1f3fc", "bath_medium_skin_tone": "1f6c0-1f3fd", "bath_medium_dark_skin_tone": "1f6c0-1f3fe", "bath_dark_skin_tone": "1f6c0-1f3ff", "sleeping_accommodation_light_skin_tone": "1f6cc-1f3fb", "sleeping_accommodation_medium_light_skin_tone": "1f6cc-1f3fc", "sleeping_accommodation_medium_skin_tone": "1f6cc-1f3fd", "sleeping_accommodation_medium_dark_skin_tone": "1f6cc-1f3fe", "sleeping_accommodation_dark_skin_tone": "1f6cc-1f3ff", "pinched_fingers_light_skin_tone": "1f90c-1f3fb", "pinched_fingers_medium_light_skin_tone": "1f90c-1f3fc", "pinched_fingers_medium_skin_tone": "1f90c-1f3fd", "pinched_fingers_medium_dark_skin_tone": "1f90c-1f3fe", "pinched_fingers_dark_skin_tone": "1f90c-1f3ff", "pinching_hand_light_skin_tone": "1f90f-1f3fb", "pinching_hand_medium_light_skin_tone": "1f90f-1f3fc", "pinching_hand_medium_skin_tone": "1f90f-1f3fd", "pinching_hand_medium_dark_skin_tone": "1f90f-1f3fe", "pinching_hand_dark_skin_tone": "1f90f-1f3ff", "the_horns_light_skin_tone": "1f918-1f3fb", "sign_of_the_horns_light_skin_tone": "1f918-1f3fb", "metal_light_skin_tone": "1f918-1f3fb", "the_horns_medium_light_skin_tone": "1f918-1f3fc", "sign_of_the_horns_medium_light_skin_tone": "1f918-1f3fc", "metal_medium_light_skin_tone": "1f918-1f3fc", "the_horns_medium_skin_tone": "1f918-1f3fd", "sign_of_the_horns_medium_skin_tone": "1f918-1f3fd", "metal_medium_skin_tone": "1f918-1f3fd", "the_horns_medium_dark_skin_tone": "1f918-1f3fe", "sign_of_the_horns_medium_dark_skin_tone": "1f918-1f3fe", "metal_medium_dark_skin_tone": "1f918-1f3fe", "the_horns_dark_skin_tone": "1f918-1f3ff", "sign_of_the_horns_dark_skin_tone": "1f918-1f3ff", "metal_dark_skin_tone": "1f918-1f3ff", "call_me_hand_light_skin_tone": "1f919-1f3fb", "call_me_hand_medium_light_skin_tone": "1f919-1f3fc", "call_me_hand_medium_skin_tone": "1f919-1f3fd", "call_me_hand_medium_dark_skin_tone": "1f919-1f3fe", "call_me_hand_dark_skin_tone": "1f919-1f3ff", "raised_back_of_hand_light_skin_tone": "1f91a-1f3fb", "raised_back_of_hand_medium_light_skin_tone": "1f91a-1f3fc", "raised_back_of_hand_medium_skin_tone": "1f91a-1f3fd", "raised_back_of_hand_medium_dark_skin_tone": "1f91a-1f3fe", "raised_back_of_hand_dark_skin_tone": "1f91a-1f3ff", "left-facing_fist_light_skin_tone": "1f91b-1f3fb", "fist_left_light_skin_tone": "1f91b-1f3fb", "left-facing_fist_medium_light_skin_tone": "1f91b-1f3fc", "fist_left_medium_light_skin_tone": "1f91b-1f3fc", "left-facing_fist_medium_skin_tone": "1f91b-1f3fd", "fist_left_medium_skin_tone": "1f91b-1f3fd", "left-facing_fist_medium_dark_skin_tone": "1f91b-1f3fe", "fist_left_medium_dark_skin_tone": "1f91b-1f3fe", "left-facing_fist_dark_skin_tone": "1f91b-1f3ff", "fist_left_dark_skin_tone": "1f91b-1f3ff", "right-facing_fist_light_skin_tone": "1f91c-1f3fb", "fist_right_light_skin_tone": "1f91c-1f3fb", "right-facing_fist_medium_light_skin_tone": "1f91c-1f3fc", "fist_right_medium_light_skin_tone": "1f91c-1f3fc", "right-facing_fist_medium_skin_tone": "1f91c-1f3fd", "fist_right_medium_skin_tone": "1f91c-1f3fd", "right-facing_fist_medium_dark_skin_tone": "1f91c-1f3fe", "fist_right_medium_dark_skin_tone": "1f91c-1f3fe", "right-facing_fist_dark_skin_tone": "1f91c-1f3ff", "fist_right_dark_skin_tone": "1f91c-1f3ff", "crossed_fingers_light_skin_tone": "1f91e-1f3fb", "hand_with_index_and_middle_fingers_crossed_light_skin_tone": "1f91e-1f3fb", "crossed_fingers_medium_light_skin_tone": "1f91e-1f3fc", "hand_with_index_and_middle_fingers_crossed_medium_light_skin_tone": "1f91e-1f3fc", "crossed_fingers_medium_skin_tone": "1f91e-1f3fd", "hand_with_index_and_middle_fingers_crossed_medium_skin_tone": "1f91e-1f3fd", "crossed_fingers_medium_dark_skin_tone": "1f91e-1f3fe", "hand_with_index_and_middle_fingers_crossed_medium_dark_skin_tone": "1f91e-1f3fe", "crossed_fingers_dark_skin_tone": "1f91e-1f3ff", "hand_with_index_and_middle_fingers_crossed_dark_skin_tone": "1f91e-1f3ff", "i_love_you_hand_sign_light_skin_tone": "1f91f-1f3fb", "i_love_you_hand_sign_medium_light_skin_tone": "1f91f-1f3fc", "i_love_you_hand_sign_medium_skin_tone": "1f91f-1f3fd", "i_love_you_hand_sign_medium_dark_skin_tone": "1f91f-1f3fe", "i_love_you_hand_sign_dark_skin_tone": "1f91f-1f3ff", "woman-facepalming_light_skin_tone": "1f926-1f3fb-200d-2640-fe0f", "woman_facepalming_light_skin_tone": "1f926-1f3fb-200d-2640-fe0f", "woman-facepalming_medium_light_skin_tone": "1f926-1f3fc-200d-2640-fe0f", "woman_facepalming_medium_light_skin_tone": "1f926-1f3fc-200d-2640-fe0f", "woman-facepalming_medium_skin_tone": "1f926-1f3fd-200d-2640-fe0f", "woman_facepalming_medium_skin_tone": "1f926-1f3fd-200d-2640-fe0f", "woman-facepalming_medium_dark_skin_tone": "1f926-1f3fe-200d-2640-fe0f", "woman_facepalming_medium_dark_skin_tone": "1f926-1f3fe-200d-2640-fe0f", "woman-facepalming_dark_skin_tone": "1f926-1f3ff-200d-2640-fe0f", "woman_facepalming_dark_skin_tone": "1f926-1f3ff-200d-2640-fe0f", "man-facepalming_light_skin_tone": "1f926-1f3fb-200d-2642-fe0f", "man_facepalming_light_skin_tone": "1f926-1f3fb-200d-2642-fe0f", "man-facepalming_medium_light_skin_tone": "1f926-1f3fc-200d-2642-fe0f", "man_facepalming_medium_light_skin_tone": "1f926-1f3fc-200d-2642-fe0f", "man-facepalming_medium_skin_tone": "1f926-1f3fd-200d-2642-fe0f", "man_facepalming_medium_skin_tone": "1f926-1f3fd-200d-2642-fe0f", "man-facepalming_medium_dark_skin_tone": "1f926-1f3fe-200d-2642-fe0f", "man_facepalming_medium_dark_skin_tone": "1f926-1f3fe-200d-2642-fe0f", "man-facepalming_dark_skin_tone": "1f926-1f3ff-200d-2642-fe0f", "man_facepalming_dark_skin_tone": "1f926-1f3ff-200d-2642-fe0f", "face_palm_light_skin_tone": "1f926-1f3fb", "face_palm_medium_light_skin_tone": "1f926-1f3fc", "face_palm_medium_skin_tone": "1f926-1f3fd", "face_palm_medium_dark_skin_tone": "1f926-1f3fe", "face_palm_dark_skin_tone": "1f926-1f3ff", "pregnant_woman_light_skin_tone": "1f930-1f3fb", "pregnant_woman_medium_light_skin_tone": "1f930-1f3fc", "pregnant_woman_medium_skin_tone": "1f930-1f3fd", "pregnant_woman_medium_dark_skin_tone": "1f930-1f3fe", "pregnant_woman_dark_skin_tone": "1f930-1f3ff", "breast-feeding_light_skin_tone": "1f931-1f3fb", "breast-feeding_medium_light_skin_tone": "1f931-1f3fc", "breast-feeding_medium_skin_tone": "1f931-1f3fd", "breast-feeding_medium_dark_skin_tone": "1f931-1f3fe", "breast-feeding_dark_skin_tone": "1f931-1f3ff", "palms_up_together_light_skin_tone": "1f932-1f3fb", "palms_up_together_medium_light_skin_tone": "1f932-1f3fc", "palms_up_together_medium_skin_tone": "1f932-1f3fd", "palms_up_together_medium_dark_skin_tone": "1f932-1f3fe", "palms_up_together_dark_skin_tone": "1f932-1f3ff", "selfie_light_skin_tone": "1f933-1f3fb", "selfie_medium_light_skin_tone": "1f933-1f3fc", "selfie_medium_skin_tone": "1f933-1f3fd", "selfie_medium_dark_skin_tone": "1f933-1f3fe", "selfie_dark_skin_tone": "1f933-1f3ff", "prince_light_skin_tone": "1f934-1f3fb", "prince_medium_light_skin_tone": "1f934-1f3fc", "prince_medium_skin_tone": "1f934-1f3fd", "prince_medium_dark_skin_tone": "1f934-1f3fe", "prince_dark_skin_tone": "1f934-1f3ff", "woman_in_tuxedo_light_skin_tone": "1f935-1f3fb-200d-2640-fe0f", "woman_in_tuxedo_medium_light_skin_tone": "1f935-1f3fc-200d-2640-fe0f", "woman_in_tuxedo_medium_skin_tone": "1f935-1f3fd-200d-2640-fe0f", "woman_in_tuxedo_medium_dark_skin_tone": "1f935-1f3fe-200d-2640-fe0f", "woman_in_tuxedo_dark_skin_tone": "1f935-1f3ff-200d-2640-fe0f", "man_in_tuxedo_light_skin_tone": "1f935-1f3fb-200d-2642-fe0f", "man_in_tuxedo_medium_light_skin_tone": "1f935-1f3fc-200d-2642-fe0f", "man_in_tuxedo_medium_skin_tone": "1f935-1f3fd-200d-2642-fe0f", "man_in_tuxedo_medium_dark_skin_tone": "1f935-1f3fe-200d-2642-fe0f", "man_in_tuxedo_dark_skin_tone": "1f935-1f3ff-200d-2642-fe0f", "person_in_tuxedo_light_skin_tone": "1f935-1f3fb", "person_in_tuxedo_medium_light_skin_tone": "1f935-1f3fc", "person_in_tuxedo_medium_skin_tone": "1f935-1f3fd", "person_in_tuxedo_medium_dark_skin_tone": "1f935-1f3fe", "person_in_tuxedo_dark_skin_tone": "1f935-1f3ff", "mrs_claus_light_skin_tone": "1f936-1f3fb", "mother_christmas_light_skin_tone": "1f936-1f3fb", "mrs_claus_medium_light_skin_tone": "1f936-1f3fc", "mother_christmas_medium_light_skin_tone": "1f936-1f3fc", "mrs_claus_medium_skin_tone": "1f936-1f3fd", "mother_christmas_medium_skin_tone": "1f936-1f3fd", "mrs_claus_medium_dark_skin_tone": "1f936-1f3fe", "mother_christmas_medium_dark_skin_tone": "1f936-1f3fe", "mrs_claus_dark_skin_tone": "1f936-1f3ff", "mother_christmas_dark_skin_tone": "1f936-1f3ff", "woman-shrugging_light_skin_tone": "1f937-1f3fb-200d-2640-fe0f", "woman_shrugging_light_skin_tone": "1f937-1f3fb-200d-2640-fe0f", "woman-shrugging_medium_light_skin_tone": "1f937-1f3fc-200d-2640-fe0f", "woman_shrugging_medium_light_skin_tone": "1f937-1f3fc-200d-2640-fe0f", "woman-shrugging_medium_skin_tone": "1f937-1f3fd-200d-2640-fe0f", "woman_shrugging_medium_skin_tone": "1f937-1f3fd-200d-2640-fe0f", "woman-shrugging_medium_dark_skin_tone": "1f937-1f3fe-200d-2640-fe0f", "woman_shrugging_medium_dark_skin_tone": "1f937-1f3fe-200d-2640-fe0f", "woman-shrugging_dark_skin_tone": "1f937-1f3ff-200d-2640-fe0f", "woman_shrugging_dark_skin_tone": "1f937-1f3ff-200d-2640-fe0f", "man-shrugging_light_skin_tone": "1f937-1f3fb-200d-2642-fe0f", "man_shrugging_light_skin_tone": "1f937-1f3fb-200d-2642-fe0f", "man-shrugging_medium_light_skin_tone": "1f937-1f3fc-200d-2642-fe0f", "man_shrugging_medium_light_skin_tone": "1f937-1f3fc-200d-2642-fe0f", "man-shrugging_medium_skin_tone": "1f937-1f3fd-200d-2642-fe0f", "man_shrugging_medium_skin_tone": "1f937-1f3fd-200d-2642-fe0f", "man-shrugging_medium_dark_skin_tone": "1f937-1f3fe-200d-2642-fe0f", "man_shrugging_medium_dark_skin_tone": "1f937-1f3fe-200d-2642-fe0f", "man-shrugging_dark_skin_tone": "1f937-1f3ff-200d-2642-fe0f", "man_shrugging_dark_skin_tone": "1f937-1f3ff-200d-2642-fe0f", "shrug_light_skin_tone": "1f937-1f3fb", "shrug_medium_light_skin_tone": "1f937-1f3fc", "shrug_medium_skin_tone": "1f937-1f3fd", "shrug_medium_dark_skin_tone": "1f937-1f3fe", "shrug_dark_skin_tone": "1f937-1f3ff", "woman-cartwheeling_light_skin_tone": "1f938-1f3fb-200d-2640-fe0f", "woman_cartwheeling_light_skin_tone": "1f938-1f3fb-200d-2640-fe0f", "woman-cartwheeling_medium_light_skin_tone": "1f938-1f3fc-200d-2640-fe0f", "woman_cartwheeling_medium_light_skin_tone": "1f938-1f3fc-200d-2640-fe0f", "woman-cartwheeling_medium_skin_tone": "1f938-1f3fd-200d-2640-fe0f", "woman_cartwheeling_medium_skin_tone": "1f938-1f3fd-200d-2640-fe0f", "woman-cartwheeling_medium_dark_skin_tone": "1f938-1f3fe-200d-2640-fe0f", "woman_cartwheeling_medium_dark_skin_tone": "1f938-1f3fe-200d-2640-fe0f", "woman-cartwheeling_dark_skin_tone": "1f938-1f3ff-200d-2640-fe0f", "woman_cartwheeling_dark_skin_tone": "1f938-1f3ff-200d-2640-fe0f", "man-cartwheeling_light_skin_tone": "1f938-1f3fb-200d-2642-fe0f", "man_cartwheeling_light_skin_tone": "1f938-1f3fb-200d-2642-fe0f", "man-cartwheeling_medium_light_skin_tone": "1f938-1f3fc-200d-2642-fe0f", "man_cartwheeling_medium_light_skin_tone": "1f938-1f3fc-200d-2642-fe0f", "man-cartwheeling_medium_skin_tone": "1f938-1f3fd-200d-2642-fe0f", "man_cartwheeling_medium_skin_tone": "1f938-1f3fd-200d-2642-fe0f", "man-cartwheeling_medium_dark_skin_tone": "1f938-1f3fe-200d-2642-fe0f", "man_cartwheeling_medium_dark_skin_tone": "1f938-1f3fe-200d-2642-fe0f", "man-cartwheeling_dark_skin_tone": "1f938-1f3ff-200d-2642-fe0f", "man_cartwheeling_dark_skin_tone": "1f938-1f3ff-200d-2642-fe0f", "person_doing_cartwheel_light_skin_tone": "1f938-1f3fb", "person_doing_cartwheel_medium_light_skin_tone": "1f938-1f3fc", "person_doing_cartwheel_medium_skin_tone": "1f938-1f3fd", "person_doing_cartwheel_medium_dark_skin_tone": "1f938-1f3fe", "person_doing_cartwheel_dark_skin_tone": "1f938-1f3ff", "woman-juggling_light_skin_tone": "1f939-1f3fb-200d-2640-fe0f", "woman_juggling_light_skin_tone": "1f939-1f3fb-200d-2640-fe0f", "woman-juggling_medium_light_skin_tone": "1f939-1f3fc-200d-2640-fe0f", "woman_juggling_medium_light_skin_tone": "1f939-1f3fc-200d-2640-fe0f", "woman-juggling_medium_skin_tone": "1f939-1f3fd-200d-2640-fe0f", "woman_juggling_medium_skin_tone": "1f939-1f3fd-200d-2640-fe0f", "woman-juggling_medium_dark_skin_tone": "1f939-1f3fe-200d-2640-fe0f", "woman_juggling_medium_dark_skin_tone": "1f939-1f3fe-200d-2640-fe0f", "woman-juggling_dark_skin_tone": "1f939-1f3ff-200d-2640-fe0f", "woman_juggling_dark_skin_tone": "1f939-1f3ff-200d-2640-fe0f", "man-juggling_light_skin_tone": "1f939-1f3fb-200d-2642-fe0f", "man_juggling_light_skin_tone": "1f939-1f3fb-200d-2642-fe0f", "man-juggling_medium_light_skin_tone": "1f939-1f3fc-200d-2642-fe0f", "man_juggling_medium_light_skin_tone": "1f939-1f3fc-200d-2642-fe0f", "man-juggling_medium_skin_tone": "1f939-1f3fd-200d-2642-fe0f", "man_juggling_medium_skin_tone": "1f939-1f3fd-200d-2642-fe0f", "man-juggling_medium_dark_skin_tone": "1f939-1f3fe-200d-2642-fe0f", "man_juggling_medium_dark_skin_tone": "1f939-1f3fe-200d-2642-fe0f", "man-juggling_dark_skin_tone": "1f939-1f3ff-200d-2642-fe0f", "man_juggling_dark_skin_tone": "1f939-1f3ff-200d-2642-fe0f", "juggling_light_skin_tone": "1f939-1f3fb", "juggling_medium_light_skin_tone": "1f939-1f3fc", "juggling_medium_skin_tone": "1f939-1f3fd", "juggling_medium_dark_skin_tone": "1f939-1f3fe", "juggling_dark_skin_tone": "1f939-1f3ff", "woman-playing-water-polo_light_skin_tone": "1f93d-1f3fb-200d-2640-fe0f", "woman_playing_water_polo_light_skin_tone": "1f93d-1f3fb-200d-2640-fe0f", "woman-playing-water-polo_medium_light_skin_tone": "1f93d-1f3fc-200d-2640-fe0f", "woman_playing_water_polo_medium_light_skin_tone": "1f93d-1f3fc-200d-2640-fe0f", "woman-playing-water-polo_medium_skin_tone": "1f93d-1f3fd-200d-2640-fe0f", "woman_playing_water_polo_medium_skin_tone": "1f93d-1f3fd-200d-2640-fe0f", "woman-playing-water-polo_medium_dark_skin_tone": "1f93d-1f3fe-200d-2640-fe0f", "woman_playing_water_polo_medium_dark_skin_tone": "1f93d-1f3fe-200d-2640-fe0f", "woman-playing-water-polo_dark_skin_tone": "1f93d-1f3ff-200d-2640-fe0f", "woman_playing_water_polo_dark_skin_tone": "1f93d-1f3ff-200d-2640-fe0f", "man-playing-water-polo_light_skin_tone": "1f93d-1f3fb-200d-2642-fe0f", "man_playing_water_polo_light_skin_tone": "1f93d-1f3fb-200d-2642-fe0f", "man-playing-water-polo_medium_light_skin_tone": "1f93d-1f3fc-200d-2642-fe0f", "man_playing_water_polo_medium_light_skin_tone": "1f93d-1f3fc-200d-2642-fe0f", "man-playing-water-polo_medium_skin_tone": "1f93d-1f3fd-200d-2642-fe0f", "man_playing_water_polo_medium_skin_tone": "1f93d-1f3fd-200d-2642-fe0f", "man-playing-water-polo_medium_dark_skin_tone": "1f93d-1f3fe-200d-2642-fe0f", "man_playing_water_polo_medium_dark_skin_tone": "1f93d-1f3fe-200d-2642-fe0f", "man-playing-water-polo_dark_skin_tone": "1f93d-1f3ff-200d-2642-fe0f", "man_playing_water_polo_dark_skin_tone": "1f93d-1f3ff-200d-2642-fe0f", "water_polo_light_skin_tone": "1f93d-1f3fb", "water_polo_medium_light_skin_tone": "1f93d-1f3fc", "water_polo_medium_skin_tone": "1f93d-1f3fd", "water_polo_medium_dark_skin_tone": "1f93d-1f3fe", "water_polo_dark_skin_tone": "1f93d-1f3ff", "woman-playing-handball_light_skin_tone": "1f93e-1f3fb-200d-2640-fe0f", "woman_playing_handball_light_skin_tone": "1f93e-1f3fb-200d-2640-fe0f", "woman-playing-handball_medium_light_skin_tone": "1f93e-1f3fc-200d-2640-fe0f", "woman_playing_handball_medium_light_skin_tone": "1f93e-1f3fc-200d-2640-fe0f", "woman-playing-handball_medium_skin_tone": "1f93e-1f3fd-200d-2640-fe0f", "woman_playing_handball_medium_skin_tone": "1f93e-1f3fd-200d-2640-fe0f", "woman-playing-handball_medium_dark_skin_tone": "1f93e-1f3fe-200d-2640-fe0f", "woman_playing_handball_medium_dark_skin_tone": "1f93e-1f3fe-200d-2640-fe0f", "woman-playing-handball_dark_skin_tone": "1f93e-1f3ff-200d-2640-fe0f", "woman_playing_handball_dark_skin_tone": "1f93e-1f3ff-200d-2640-fe0f", "man-playing-handball_light_skin_tone": "1f93e-1f3fb-200d-2642-fe0f", "man_playing_handball_light_skin_tone": "1f93e-1f3fb-200d-2642-fe0f", "man-playing-handball_medium_light_skin_tone": "1f93e-1f3fc-200d-2642-fe0f", "man_playing_handball_medium_light_skin_tone": "1f93e-1f3fc-200d-2642-fe0f", "man-playing-handball_medium_skin_tone": "1f93e-1f3fd-200d-2642-fe0f", "man_playing_handball_medium_skin_tone": "1f93e-1f3fd-200d-2642-fe0f", "man-playing-handball_medium_dark_skin_tone": "1f93e-1f3fe-200d-2642-fe0f", "man_playing_handball_medium_dark_skin_tone": "1f93e-1f3fe-200d-2642-fe0f", "man-playing-handball_dark_skin_tone": "1f93e-1f3ff-200d-2642-fe0f", "man_playing_handball_dark_skin_tone": "1f93e-1f3ff-200d-2642-fe0f", "handball_light_skin_tone": "1f93e-1f3fb", "handball_medium_light_skin_tone": "1f93e-1f3fc", "handball_medium_skin_tone": "1f93e-1f3fd", "handball_medium_dark_skin_tone": "1f93e-1f3fe", "handball_dark_skin_tone": "1f93e-1f3ff", "ninja_light_skin_tone": "1f977-1f3fb", "ninja_medium_light_skin_tone": "1f977-1f3fc", "ninja_medium_skin_tone": "1f977-1f3fd", "ninja_medium_dark_skin_tone": "1f977-1f3fe", "ninja_dark_skin_tone": "1f977-1f3ff", "leg_light_skin_tone": "1f9b5-1f3fb", "leg_medium_light_skin_tone": "1f9b5-1f3fc", "leg_medium_skin_tone": "1f9b5-1f3fd", "leg_medium_dark_skin_tone": "1f9b5-1f3fe", "leg_dark_skin_tone": "1f9b5-1f3ff", "foot_light_skin_tone": "1f9b6-1f3fb", "foot_medium_light_skin_tone": "1f9b6-1f3fc", "foot_medium_skin_tone": "1f9b6-1f3fd", "foot_medium_dark_skin_tone": "1f9b6-1f3fe", "foot_dark_skin_tone": "1f9b6-1f3ff", "female_superhero_light_skin_tone": "1f9b8-1f3fb-200d-2640-fe0f", "female_superhero_medium_light_skin_tone": "1f9b8-1f3fc-200d-2640-fe0f", "female_superhero_medium_skin_tone": "1f9b8-1f3fd-200d-2640-fe0f", "female_superhero_medium_dark_skin_tone": "1f9b8-1f3fe-200d-2640-fe0f", "female_superhero_dark_skin_tone": "1f9b8-1f3ff-200d-2640-fe0f", "male_superhero_light_skin_tone": "1f9b8-1f3fb-200d-2642-fe0f", "male_superhero_medium_light_skin_tone": "1f9b8-1f3fc-200d-2642-fe0f", "male_superhero_medium_skin_tone": "1f9b8-1f3fd-200d-2642-fe0f", "male_superhero_medium_dark_skin_tone": "1f9b8-1f3fe-200d-2642-fe0f", "male_superhero_dark_skin_tone": "1f9b8-1f3ff-200d-2642-fe0f", "superhero_light_skin_tone": "1f9b8-1f3fb", "superhero_medium_light_skin_tone": "1f9b8-1f3fc", "superhero_medium_skin_tone": "1f9b8-1f3fd", "superhero_medium_dark_skin_tone": "1f9b8-1f3fe", "superhero_dark_skin_tone": "1f9b8-1f3ff", "female_supervillain_light_skin_tone": "1f9b9-1f3fb-200d-2640-fe0f", "female_supervillain_medium_light_skin_tone": "1f9b9-1f3fc-200d-2640-fe0f", "female_supervillain_medium_skin_tone": "1f9b9-1f3fd-200d-2640-fe0f", "female_supervillain_medium_dark_skin_tone": "1f9b9-1f3fe-200d-2640-fe0f", "female_supervillain_dark_skin_tone": "1f9b9-1f3ff-200d-2640-fe0f", "male_supervillain_light_skin_tone": "1f9b9-1f3fb-200d-2642-fe0f", "male_supervillain_medium_light_skin_tone": "1f9b9-1f3fc-200d-2642-fe0f", "male_supervillain_medium_skin_tone": "1f9b9-1f3fd-200d-2642-fe0f", "male_supervillain_medium_dark_skin_tone": "1f9b9-1f3fe-200d-2642-fe0f", "male_supervillain_dark_skin_tone": "1f9b9-1f3ff-200d-2642-fe0f", "supervillain_light_skin_tone": "1f9b9-1f3fb", "supervillain_medium_light_skin_tone": "1f9b9-1f3fc", "supervillain_medium_skin_tone": "1f9b9-1f3fd", "supervillain_medium_dark_skin_tone": "1f9b9-1f3fe", "supervillain_dark_skin_tone": "1f9b9-1f3ff", "ear_with_hearing_aid_light_skin_tone": "1f9bb-1f3fb", "ear_with_hearing_aid_medium_light_skin_tone": "1f9bb-1f3fc", "ear_with_hearing_aid_medium_skin_tone": "1f9bb-1f3fd", "ear_with_hearing_aid_medium_dark_skin_tone": "1f9bb-1f3fe", "ear_with_hearing_aid_dark_skin_tone": "1f9bb-1f3ff", "woman_standing_light_skin_tone": "1f9cd-1f3fb-200d-2640-fe0f", "woman_standing_medium_light_skin_tone": "1f9cd-1f3fc-200d-2640-fe0f", "woman_standing_medium_skin_tone": "1f9cd-1f3fd-200d-2640-fe0f", "woman_standing_medium_dark_skin_tone": "1f9cd-1f3fe-200d-2640-fe0f", "woman_standing_dark_skin_tone": "1f9cd-1f3ff-200d-2640-fe0f", "man_standing_light_skin_tone": "1f9cd-1f3fb-200d-2642-fe0f", "man_standing_medium_light_skin_tone": "1f9cd-1f3fc-200d-2642-fe0f", "man_standing_medium_skin_tone": "1f9cd-1f3fd-200d-2642-fe0f", "man_standing_medium_dark_skin_tone": "1f9cd-1f3fe-200d-2642-fe0f", "man_standing_dark_skin_tone": "1f9cd-1f3ff-200d-2642-fe0f", "standing_person_light_skin_tone": "1f9cd-1f3fb", "standing_person_medium_light_skin_tone": "1f9cd-1f3fc", "standing_person_medium_skin_tone": "1f9cd-1f3fd", "standing_person_medium_dark_skin_tone": "1f9cd-1f3fe", "standing_person_dark_skin_tone": "1f9cd-1f3ff", "woman_kneeling_light_skin_tone": "1f9ce-1f3fb-200d-2640-fe0f", "woman_kneeling_medium_light_skin_tone": "1f9ce-1f3fc-200d-2640-fe0f", "woman_kneeling_medium_skin_tone": "1f9ce-1f3fd-200d-2640-fe0f", "woman_kneeling_medium_dark_skin_tone": "1f9ce-1f3fe-200d-2640-fe0f", "woman_kneeling_dark_skin_tone": "1f9ce-1f3ff-200d-2640-fe0f", "man_kneeling_light_skin_tone": "1f9ce-1f3fb-200d-2642-fe0f", "man_kneeling_medium_light_skin_tone": "1f9ce-1f3fc-200d-2642-fe0f", "man_kneeling_medium_skin_tone": "1f9ce-1f3fd-200d-2642-fe0f", "man_kneeling_medium_dark_skin_tone": "1f9ce-1f3fe-200d-2642-fe0f", "man_kneeling_dark_skin_tone": "1f9ce-1f3ff-200d-2642-fe0f", "kneeling_person_light_skin_tone": "1f9ce-1f3fb", "kneeling_person_medium_light_skin_tone": "1f9ce-1f3fc", "kneeling_person_medium_skin_tone": "1f9ce-1f3fd", "kneeling_person_medium_dark_skin_tone": "1f9ce-1f3fe", "kneeling_person_dark_skin_tone": "1f9ce-1f3ff", "deaf_woman_light_skin_tone": "1f9cf-1f3fb-200d-2640-fe0f", "deaf_woman_medium_light_skin_tone": "1f9cf-1f3fc-200d-2640-fe0f", "deaf_woman_medium_skin_tone": "1f9cf-1f3fd-200d-2640-fe0f", "deaf_woman_medium_dark_skin_tone": "1f9cf-1f3fe-200d-2640-fe0f", "deaf_woman_dark_skin_tone": "1f9cf-1f3ff-200d-2640-fe0f", "deaf_man_light_skin_tone": "1f9cf-1f3fb-200d-2642-fe0f", "deaf_man_medium_light_skin_tone": "1f9cf-1f3fc-200d-2642-fe0f", "deaf_man_medium_skin_tone": "1f9cf-1f3fd-200d-2642-fe0f", "deaf_man_medium_dark_skin_tone": "1f9cf-1f3fe-200d-2642-fe0f", "deaf_man_dark_skin_tone": "1f9cf-1f3ff-200d-2642-fe0f", "deaf_person_light_skin_tone": "1f9cf-1f3fb", "deaf_person_medium_light_skin_tone": "1f9cf-1f3fc", "deaf_person_medium_skin_tone": "1f9cf-1f3fd", "deaf_person_medium_dark_skin_tone": "1f9cf-1f3fe", "deaf_person_dark_skin_tone": "1f9cf-1f3ff", "farmer_light_skin_tone": "1f9d1-1f3fb-200d-1f33e", "farmer_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f33e", "farmer_medium_skin_tone": "1f9d1-1f3fd-200d-1f33e", "farmer_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f33e", "farmer_dark_skin_tone": "1f9d1-1f3ff-200d-1f33e", "cook_light_skin_tone": "1f9d1-1f3fb-200d-1f373", "cook_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f373", "cook_medium_skin_tone": "1f9d1-1f3fd-200d-1f373", "cook_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f373", "cook_dark_skin_tone": "1f9d1-1f3ff-200d-1f373", "person_feeding_baby_light_skin_tone": "1f9d1-1f3fb-200d-1f37c", "person_feeding_baby_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f37c", "person_feeding_baby_medium_skin_tone": "1f9d1-1f3fd-200d-1f37c", "person_feeding_baby_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f37c", "person_feeding_baby_dark_skin_tone": "1f9d1-1f3ff-200d-1f37c", "mx_claus_light_skin_tone": "1f9d1-1f3fb-200d-1f384", "mx_claus_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f384", "mx_claus_medium_skin_tone": "1f9d1-1f3fd-200d-1f384", "mx_claus_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f384", "mx_claus_dark_skin_tone": "1f9d1-1f3ff-200d-1f384", "student_light_skin_tone": "1f9d1-1f3fb-200d-1f393", "student_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f393", "student_medium_skin_tone": "1f9d1-1f3fd-200d-1f393", "student_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f393", "student_dark_skin_tone": "1f9d1-1f3ff-200d-1f393", "singer_light_skin_tone": "1f9d1-1f3fb-200d-1f3a4", "singer_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f3a4", "singer_medium_skin_tone": "1f9d1-1f3fd-200d-1f3a4", "singer_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f3a4", "singer_dark_skin_tone": "1f9d1-1f3ff-200d-1f3a4", "artist_light_skin_tone": "1f9d1-1f3fb-200d-1f3a8", "artist_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f3a8", "artist_medium_skin_tone": "1f9d1-1f3fd-200d-1f3a8", "artist_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f3a8", "artist_dark_skin_tone": "1f9d1-1f3ff-200d-1f3a8", "teacher_light_skin_tone": "1f9d1-1f3fb-200d-1f3eb", "teacher_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f3eb", "teacher_medium_skin_tone": "1f9d1-1f3fd-200d-1f3eb", "teacher_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f3eb", "teacher_dark_skin_tone": "1f9d1-1f3ff-200d-1f3eb", "factory_worker_light_skin_tone": "1f9d1-1f3fb-200d-1f3ed", "factory_worker_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f3ed", "factory_worker_medium_skin_tone": "1f9d1-1f3fd-200d-1f3ed", "factory_worker_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f3ed", "factory_worker_dark_skin_tone": "1f9d1-1f3ff-200d-1f3ed", "technologist_light_skin_tone": "1f9d1-1f3fb-200d-1f4bb", "technologist_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f4bb", "technologist_medium_skin_tone": "1f9d1-1f3fd-200d-1f4bb", "technologist_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f4bb", "technologist_dark_skin_tone": "1f9d1-1f3ff-200d-1f4bb", "office_worker_light_skin_tone": "1f9d1-1f3fb-200d-1f4bc", "office_worker_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f4bc", "office_worker_medium_skin_tone": "1f9d1-1f3fd-200d-1f4bc", "office_worker_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f4bc", "office_worker_dark_skin_tone": "1f9d1-1f3ff-200d-1f4bc", "mechanic_light_skin_tone": "1f9d1-1f3fb-200d-1f527", "mechanic_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f527", "mechanic_medium_skin_tone": "1f9d1-1f3fd-200d-1f527", "mechanic_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f527", "mechanic_dark_skin_tone": "1f9d1-1f3ff-200d-1f527", "scientist_light_skin_tone": "1f9d1-1f3fb-200d-1f52c", "scientist_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f52c", "scientist_medium_skin_tone": "1f9d1-1f3fd-200d-1f52c", "scientist_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f52c", "scientist_dark_skin_tone": "1f9d1-1f3ff-200d-1f52c", "astronaut_light_skin_tone": "1f9d1-1f3fb-200d-1f680", "astronaut_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f680", "astronaut_medium_skin_tone": "1f9d1-1f3fd-200d-1f680", "astronaut_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f680", "astronaut_dark_skin_tone": "1f9d1-1f3ff-200d-1f680", "firefighter_light_skin_tone": "1f9d1-1f3fb-200d-1f692", "firefighter_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f692", "firefighter_medium_skin_tone": "1f9d1-1f3fd-200d-1f692", "firefighter_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f692", "firefighter_dark_skin_tone": "1f9d1-1f3ff-200d-1f692", "people_holding_hands_light_skin_tone_light_skin_tone": "1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3fb", "people_holding_hands_light_skin_tone_medium_light_skin_tone": "1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3fc", "people_holding_hands_light_skin_tone_medium_skin_tone": "1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3fd", "people_holding_hands_light_skin_tone_medium_dark_skin_tone": "1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3fe", "people_holding_hands_light_skin_tone_dark_skin_tone": "1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3ff", "people_holding_hands_medium_light_skin_tone_light_skin_tone": "1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3fb", "people_holding_hands_medium_light_skin_tone_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3fc", "people_holding_hands_medium_light_skin_tone_medium_skin_tone": "1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3fd", "people_holding_hands_medium_light_skin_tone_medium_dark_skin_tone": "1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3fe", "people_holding_hands_medium_light_skin_tone_dark_skin_tone": "1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3ff", "people_holding_hands_medium_skin_tone_light_skin_tone": "1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3fb", "people_holding_hands_medium_skin_tone_medium_light_skin_tone": "1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3fc", "people_holding_hands_medium_skin_tone_medium_skin_tone": "1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3fd", "people_holding_hands_medium_skin_tone_medium_dark_skin_tone": "1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3fe", "people_holding_hands_medium_skin_tone_dark_skin_tone": "1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3ff", "people_holding_hands_medium_dark_skin_tone_light_skin_tone": "1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3fb", "people_holding_hands_medium_dark_skin_tone_medium_light_skin_tone": "1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3fc", "people_holding_hands_medium_dark_skin_tone_medium_skin_tone": "1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3fd", "people_holding_hands_medium_dark_skin_tone_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3fe", "people_holding_hands_medium_dark_skin_tone_dark_skin_tone": "1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3ff", "people_holding_hands_dark_skin_tone_light_skin_tone": "1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3fb", "people_holding_hands_dark_skin_tone_medium_light_skin_tone": "1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3fc", "people_holding_hands_dark_skin_tone_medium_skin_tone": "1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3fd", "people_holding_hands_dark_skin_tone_medium_dark_skin_tone": "1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3fe", "people_holding_hands_dark_skin_tone_dark_skin_tone": "1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3ff", "person_with_probing_cane_light_skin_tone": "1f9d1-1f3fb-200d-1f9af", "person_with_probing_cane_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9af", "person_with_probing_cane_medium_skin_tone": "1f9d1-1f3fd-200d-1f9af", "person_with_probing_cane_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9af", "person_with_probing_cane_dark_skin_tone": "1f9d1-1f3ff-200d-1f9af", "red_haired_person_light_skin_tone": "1f9d1-1f3fb-200d-1f9b0", "red_haired_person_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9b0", "red_haired_person_medium_skin_tone": "1f9d1-1f3fd-200d-1f9b0", "red_haired_person_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9b0", "red_haired_person_dark_skin_tone": "1f9d1-1f3ff-200d-1f9b0", "curly_haired_person_light_skin_tone": "1f9d1-1f3fb-200d-1f9b1", "curly_haired_person_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9b1", "curly_haired_person_medium_skin_tone": "1f9d1-1f3fd-200d-1f9b1", "curly_haired_person_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9b1", "curly_haired_person_dark_skin_tone": "1f9d1-1f3ff-200d-1f9b1", "bald_person_light_skin_tone": "1f9d1-1f3fb-200d-1f9b2", "bald_person_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9b2", "bald_person_medium_skin_tone": "1f9d1-1f3fd-200d-1f9b2", "bald_person_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9b2", "bald_person_dark_skin_tone": "1f9d1-1f3ff-200d-1f9b2", "white_haired_person_light_skin_tone": "1f9d1-1f3fb-200d-1f9b3", "white_haired_person_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9b3", "white_haired_person_medium_skin_tone": "1f9d1-1f3fd-200d-1f9b3", "white_haired_person_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9b3", "white_haired_person_dark_skin_tone": "1f9d1-1f3ff-200d-1f9b3", "person_in_motorized_wheelchair_light_skin_tone": "1f9d1-1f3fb-200d-1f9bc", "person_in_motorized_wheelchair_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9bc", "person_in_motorized_wheelchair_medium_skin_tone": "1f9d1-1f3fd-200d-1f9bc", "person_in_motorized_wheelchair_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9bc", "person_in_motorized_wheelchair_dark_skin_tone": "1f9d1-1f3ff-200d-1f9bc", "person_in_manual_wheelchair_light_skin_tone": "1f9d1-1f3fb-200d-1f9bd", "person_in_manual_wheelchair_medium_light_skin_tone": "1f9d1-1f3fc-200d-1f9bd", "person_in_manual_wheelchair_medium_skin_tone": "1f9d1-1f3fd-200d-1f9bd", "person_in_manual_wheelchair_medium_dark_skin_tone": "1f9d1-1f3fe-200d-1f9bd", "person_in_manual_wheelchair_dark_skin_tone": "1f9d1-1f3ff-200d-1f9bd", "health_worker_light_skin_tone": "1f9d1-1f3fb-200d-2695-fe0f", "health_worker_medium_light_skin_tone": "1f9d1-1f3fc-200d-2695-fe0f", "health_worker_medium_skin_tone": "1f9d1-1f3fd-200d-2695-fe0f", "health_worker_medium_dark_skin_tone": "1f9d1-1f3fe-200d-2695-fe0f", "health_worker_dark_skin_tone": "1f9d1-1f3ff-200d-2695-fe0f", "judge_light_skin_tone": "1f9d1-1f3fb-200d-2696-fe0f", "judge_medium_light_skin_tone": "1f9d1-1f3fc-200d-2696-fe0f", "judge_medium_skin_tone": "1f9d1-1f3fd-200d-2696-fe0f", "judge_medium_dark_skin_tone": "1f9d1-1f3fe-200d-2696-fe0f", "judge_dark_skin_tone": "1f9d1-1f3ff-200d-2696-fe0f", "pilot_light_skin_tone": "1f9d1-1f3fb-200d-2708-fe0f", "pilot_medium_light_skin_tone": "1f9d1-1f3fc-200d-2708-fe0f", "pilot_medium_skin_tone": "1f9d1-1f3fd-200d-2708-fe0f", "pilot_medium_dark_skin_tone": "1f9d1-1f3fe-200d-2708-fe0f", "pilot_dark_skin_tone": "1f9d1-1f3ff-200d-2708-fe0f", "adult_light_skin_tone": "1f9d1-1f3fb", "adult_medium_light_skin_tone": "1f9d1-1f3fc", "adult_medium_skin_tone": "1f9d1-1f3fd", "adult_medium_dark_skin_tone": "1f9d1-1f3fe", "adult_dark_skin_tone": "1f9d1-1f3ff", "child_light_skin_tone": "1f9d2-1f3fb", "child_medium_light_skin_tone": "1f9d2-1f3fc", "child_medium_skin_tone": "1f9d2-1f3fd", "child_medium_dark_skin_tone": "1f9d2-1f3fe", "child_dark_skin_tone": "1f9d2-1f3ff", "older_adult_light_skin_tone": "1f9d3-1f3fb", "older_adult_medium_light_skin_tone": "1f9d3-1f3fc", "older_adult_medium_skin_tone": "1f9d3-1f3fd", "older_adult_medium_dark_skin_tone": "1f9d3-1f3fe", "older_adult_dark_skin_tone": "1f9d3-1f3ff", "bearded_person_light_skin_tone": "1f9d4-1f3fb", "bearded_person_medium_light_skin_tone": "1f9d4-1f3fc", "bearded_person_medium_skin_tone": "1f9d4-1f3fd", "bearded_person_medium_dark_skin_tone": "1f9d4-1f3fe", "bearded_person_dark_skin_tone": "1f9d4-1f3ff", "person_with_headscarf_light_skin_tone": "1f9d5-1f3fb", "person_with_headscarf_medium_light_skin_tone": "1f9d5-1f3fc", "person_with_headscarf_medium_skin_tone": "1f9d5-1f3fd", "person_with_headscarf_medium_dark_skin_tone": "1f9d5-1f3fe", "person_with_headscarf_dark_skin_tone": "1f9d5-1f3ff", "woman_in_steamy_room_light_skin_tone": "1f9d6-1f3fb-200d-2640-fe0f", "woman_in_steamy_room_medium_light_skin_tone": "1f9d6-1f3fc-200d-2640-fe0f", "woman_in_steamy_room_medium_skin_tone": "1f9d6-1f3fd-200d-2640-fe0f", "woman_in_steamy_room_medium_dark_skin_tone": "1f9d6-1f3fe-200d-2640-fe0f", "woman_in_steamy_room_dark_skin_tone": "1f9d6-1f3ff-200d-2640-fe0f", "man_in_steamy_room_light_skin_tone": "1f9d6-1f3fb-200d-2642-fe0f", "man_in_steamy_room_medium_light_skin_tone": "1f9d6-1f3fc-200d-2642-fe0f", "man_in_steamy_room_medium_skin_tone": "1f9d6-1f3fd-200d-2642-fe0f", "man_in_steamy_room_medium_dark_skin_tone": "1f9d6-1f3fe-200d-2642-fe0f", "man_in_steamy_room_dark_skin_tone": "1f9d6-1f3ff-200d-2642-fe0f", "person_in_steamy_room_light_skin_tone": "1f9d6-1f3fb", "person_in_steamy_room_medium_light_skin_tone": "1f9d6-1f3fc", "person_in_steamy_room_medium_skin_tone": "1f9d6-1f3fd", "person_in_steamy_room_medium_dark_skin_tone": "1f9d6-1f3fe", "person_in_steamy_room_dark_skin_tone": "1f9d6-1f3ff", "woman_climbing_light_skin_tone": "1f9d7-1f3fb-200d-2640-fe0f", "woman_climbing_medium_light_skin_tone": "1f9d7-1f3fc-200d-2640-fe0f", "woman_climbing_medium_skin_tone": "1f9d7-1f3fd-200d-2640-fe0f", "woman_climbing_medium_dark_skin_tone": "1f9d7-1f3fe-200d-2640-fe0f", "woman_climbing_dark_skin_tone": "1f9d7-1f3ff-200d-2640-fe0f", "man_climbing_light_skin_tone": "1f9d7-1f3fb-200d-2642-fe0f", "man_climbing_medium_light_skin_tone": "1f9d7-1f3fc-200d-2642-fe0f", "man_climbing_medium_skin_tone": "1f9d7-1f3fd-200d-2642-fe0f", "man_climbing_medium_dark_skin_tone": "1f9d7-1f3fe-200d-2642-fe0f", "man_climbing_dark_skin_tone": "1f9d7-1f3ff-200d-2642-fe0f", "person_climbing_light_skin_tone": "1f9d7-1f3fb", "person_climbing_medium_light_skin_tone": "1f9d7-1f3fc", "person_climbing_medium_skin_tone": "1f9d7-1f3fd", "person_climbing_medium_dark_skin_tone": "1f9d7-1f3fe", "person_climbing_dark_skin_tone": "1f9d7-1f3ff", "woman_in_lotus_position_light_skin_tone": "1f9d8-1f3fb-200d-2640-fe0f", "woman_in_lotus_position_medium_light_skin_tone": "1f9d8-1f3fc-200d-2640-fe0f", "woman_in_lotus_position_medium_skin_tone": "1f9d8-1f3fd-200d-2640-fe0f", "woman_in_lotus_position_medium_dark_skin_tone": "1f9d8-1f3fe-200d-2640-fe0f", "woman_in_lotus_position_dark_skin_tone": "1f9d8-1f3ff-200d-2640-fe0f", "man_in_lotus_position_light_skin_tone": "1f9d8-1f3fb-200d-2642-fe0f", "man_in_lotus_position_medium_light_skin_tone": "1f9d8-1f3fc-200d-2642-fe0f", "man_in_lotus_position_medium_skin_tone": "1f9d8-1f3fd-200d-2642-fe0f", "man_in_lotus_position_medium_dark_skin_tone": "1f9d8-1f3fe-200d-2642-fe0f", "man_in_lotus_position_dark_skin_tone": "1f9d8-1f3ff-200d-2642-fe0f", "person_in_lotus_position_light_skin_tone": "1f9d8-1f3fb", "person_in_lotus_position_medium_light_skin_tone": "1f9d8-1f3fc", "person_in_lotus_position_medium_skin_tone": "1f9d8-1f3fd", "person_in_lotus_position_medium_dark_skin_tone": "1f9d8-1f3fe", "person_in_lotus_position_dark_skin_tone": "1f9d8-1f3ff", "female_mage_light_skin_tone": "1f9d9-1f3fb-200d-2640-fe0f", "female_mage_medium_light_skin_tone": "1f9d9-1f3fc-200d-2640-fe0f", "female_mage_medium_skin_tone": "1f9d9-1f3fd-200d-2640-fe0f", "female_mage_medium_dark_skin_tone": "1f9d9-1f3fe-200d-2640-fe0f", "female_mage_dark_skin_tone": "1f9d9-1f3ff-200d-2640-fe0f", "male_mage_light_skin_tone": "1f9d9-1f3fb-200d-2642-fe0f", "male_mage_medium_light_skin_tone": "1f9d9-1f3fc-200d-2642-fe0f", "male_mage_medium_skin_tone": "1f9d9-1f3fd-200d-2642-fe0f", "male_mage_medium_dark_skin_tone": "1f9d9-1f3fe-200d-2642-fe0f", "male_mage_dark_skin_tone": "1f9d9-1f3ff-200d-2642-fe0f", "mage_light_skin_tone": "1f9d9-1f3fb", "mage_medium_light_skin_tone": "1f9d9-1f3fc", "mage_medium_skin_tone": "1f9d9-1f3fd", "mage_medium_dark_skin_tone": "1f9d9-1f3fe", "mage_dark_skin_tone": "1f9d9-1f3ff", "female_fairy_light_skin_tone": "1f9da-1f3fb-200d-2640-fe0f", "female_fairy_medium_light_skin_tone": "1f9da-1f3fc-200d-2640-fe0f", "female_fairy_medium_skin_tone": "1f9da-1f3fd-200d-2640-fe0f", "female_fairy_medium_dark_skin_tone": "1f9da-1f3fe-200d-2640-fe0f", "female_fairy_dark_skin_tone": "1f9da-1f3ff-200d-2640-fe0f", "male_fairy_light_skin_tone": "1f9da-1f3fb-200d-2642-fe0f", "male_fairy_medium_light_skin_tone": "1f9da-1f3fc-200d-2642-fe0f", "male_fairy_medium_skin_tone": "1f9da-1f3fd-200d-2642-fe0f", "male_fairy_medium_dark_skin_tone": "1f9da-1f3fe-200d-2642-fe0f", "male_fairy_dark_skin_tone": "1f9da-1f3ff-200d-2642-fe0f", "fairy_light_skin_tone": "1f9da-1f3fb", "fairy_medium_light_skin_tone": "1f9da-1f3fc", "fairy_medium_skin_tone": "1f9da-1f3fd", "fairy_medium_dark_skin_tone": "1f9da-1f3fe", "fairy_dark_skin_tone": "1f9da-1f3ff", "female_vampire_light_skin_tone": "1f9db-1f3fb-200d-2640-fe0f", "female_vampire_medium_light_skin_tone": "1f9db-1f3fc-200d-2640-fe0f", "female_vampire_medium_skin_tone": "1f9db-1f3fd-200d-2640-fe0f", "female_vampire_medium_dark_skin_tone": "1f9db-1f3fe-200d-2640-fe0f", "female_vampire_dark_skin_tone": "1f9db-1f3ff-200d-2640-fe0f", "male_vampire_light_skin_tone": "1f9db-1f3fb-200d-2642-fe0f", "male_vampire_medium_light_skin_tone": "1f9db-1f3fc-200d-2642-fe0f", "male_vampire_medium_skin_tone": "1f9db-1f3fd-200d-2642-fe0f", "male_vampire_medium_dark_skin_tone": "1f9db-1f3fe-200d-2642-fe0f", "male_vampire_dark_skin_tone": "1f9db-1f3ff-200d-2642-fe0f", "vampire_light_skin_tone": "1f9db-1f3fb", "vampire_medium_light_skin_tone": "1f9db-1f3fc", "vampire_medium_skin_tone": "1f9db-1f3fd", "vampire_medium_dark_skin_tone": "1f9db-1f3fe", "vampire_dark_skin_tone": "1f9db-1f3ff", "mermaid_light_skin_tone": "1f9dc-1f3fb-200d-2640-fe0f", "mermaid_medium_light_skin_tone": "1f9dc-1f3fc-200d-2640-fe0f", "mermaid_medium_skin_tone": "1f9dc-1f3fd-200d-2640-fe0f", "mermaid_medium_dark_skin_tone": "1f9dc-1f3fe-200d-2640-fe0f", "mermaid_dark_skin_tone": "1f9dc-1f3ff-200d-2640-fe0f", "merman_light_skin_tone": "1f9dc-1f3fb-200d-2642-fe0f", "merman_medium_light_skin_tone": "1f9dc-1f3fc-200d-2642-fe0f", "merman_medium_skin_tone": "1f9dc-1f3fd-200d-2642-fe0f", "merman_medium_dark_skin_tone": "1f9dc-1f3fe-200d-2642-fe0f", "merman_dark_skin_tone": "1f9dc-1f3ff-200d-2642-fe0f", "merperson_light_skin_tone": "1f9dc-1f3fb", "merperson_medium_light_skin_tone": "1f9dc-1f3fc", "merperson_medium_skin_tone": "1f9dc-1f3fd", "merperson_medium_dark_skin_tone": "1f9dc-1f3fe", "merperson_dark_skin_tone": "1f9dc-1f3ff", "female_elf_light_skin_tone": "1f9dd-1f3fb-200d-2640-fe0f", "female_elf_medium_light_skin_tone": "1f9dd-1f3fc-200d-2640-fe0f", "female_elf_medium_skin_tone": "1f9dd-1f3fd-200d-2640-fe0f", "female_elf_medium_dark_skin_tone": "1f9dd-1f3fe-200d-2640-fe0f", "female_elf_dark_skin_tone": "1f9dd-1f3ff-200d-2640-fe0f", "male_elf_light_skin_tone": "1f9dd-1f3fb-200d-2642-fe0f", "male_elf_medium_light_skin_tone": "1f9dd-1f3fc-200d-2642-fe0f", "male_elf_medium_skin_tone": "1f9dd-1f3fd-200d-2642-fe0f", "male_elf_medium_dark_skin_tone": "1f9dd-1f3fe-200d-2642-fe0f", "male_elf_dark_skin_tone": "1f9dd-1f3ff-200d-2642-fe0f", "elf_light_skin_tone": "1f9dd-1f3fb", "elf_medium_light_skin_tone": "1f9dd-1f3fc", "elf_medium_skin_tone": "1f9dd-1f3fd", "elf_medium_dark_skin_tone": "1f9dd-1f3fe", "elf_dark_skin_tone": "1f9dd-1f3ff", "point_up_light_skin_tone": "261d-1f3fb", "point_up_medium_light_skin_tone": "261d-1f3fc", "point_up_medium_skin_tone": "261d-1f3fd", "point_up_medium_dark_skin_tone": "261d-1f3fe", "point_up_dark_skin_tone": "261d-1f3ff", "woman-bouncing-ball_light_skin_tone": "26f9-1f3fb-200d-2640-fe0f", "basketball_woman_light_skin_tone": "26f9-1f3fb-200d-2640-fe0f", "woman-bouncing-ball_medium_light_skin_tone": "26f9-1f3fc-200d-2640-fe0f", "basketball_woman_medium_light_skin_tone": "26f9-1f3fc-200d-2640-fe0f", "woman-bouncing-ball_medium_skin_tone": "26f9-1f3fd-200d-2640-fe0f", "basketball_woman_medium_skin_tone": "26f9-1f3fd-200d-2640-fe0f", "woman-bouncing-ball_medium_dark_skin_tone": "26f9-1f3fe-200d-2640-fe0f", "basketball_woman_medium_dark_skin_tone": "26f9-1f3fe-200d-2640-fe0f", "woman-bouncing-ball_dark_skin_tone": "26f9-1f3ff-200d-2640-fe0f", "basketball_woman_dark_skin_tone": "26f9-1f3ff-200d-2640-fe0f", "man-bouncing-ball_light_skin_tone": "26f9-1f3fb-200d-2642-fe0f", "basketball_man_light_skin_tone": "26f9-1f3fb-200d-2642-fe0f", "man-bouncing-ball_medium_light_skin_tone": "26f9-1f3fc-200d-2642-fe0f", "basketball_man_medium_light_skin_tone": "26f9-1f3fc-200d-2642-fe0f", "man-bouncing-ball_medium_skin_tone": "26f9-1f3fd-200d-2642-fe0f", "basketball_man_medium_skin_tone": "26f9-1f3fd-200d-2642-fe0f", "man-bouncing-ball_medium_dark_skin_tone": "26f9-1f3fe-200d-2642-fe0f", "basketball_man_medium_dark_skin_tone": "26f9-1f3fe-200d-2642-fe0f", "man-bouncing-ball_dark_skin_tone": "26f9-1f3ff-200d-2642-fe0f", "basketball_man_dark_skin_tone": "26f9-1f3ff-200d-2642-fe0f", "person_with_ball_light_skin_tone": "26f9-1f3fb", "person_with_ball_medium_light_skin_tone": "26f9-1f3fc", "person_with_ball_medium_skin_tone": "26f9-1f3fd", "person_with_ball_medium_dark_skin_tone": "26f9-1f3fe", "person_with_ball_dark_skin_tone": "26f9-1f3ff", "fist_light_skin_tone": "270a-1f3fb", "fist_raised_light_skin_tone": "270a-1f3fb", "fist_medium_light_skin_tone": "270a-1f3fc", "fist_raised_medium_light_skin_tone": "270a-1f3fc", "fist_medium_skin_tone": "270a-1f3fd", "fist_raised_medium_skin_tone": "270a-1f3fd", "fist_medium_dark_skin_tone": "270a-1f3fe", "fist_raised_medium_dark_skin_tone": "270a-1f3fe", "fist_dark_skin_tone": "270a-1f3ff", "fist_raised_dark_skin_tone": "270a-1f3ff", "hand_light_skin_tone": "270b-1f3fb", "raised_hand_light_skin_tone": "270b-1f3fb", "hand_medium_light_skin_tone": "270b-1f3fc", "raised_hand_medium_light_skin_tone": "270b-1f3fc", "hand_medium_skin_tone": "270b-1f3fd", "raised_hand_medium_skin_tone": "270b-1f3fd", "hand_medium_dark_skin_tone": "270b-1f3fe", "raised_hand_medium_dark_skin_tone": "270b-1f3fe", "hand_dark_skin_tone": "270b-1f3ff", "raised_hand_dark_skin_tone": "270b-1f3ff", "v_light_skin_tone": "270c-1f3fb", "v_medium_light_skin_tone": "270c-1f3fc", "v_medium_skin_tone": "270c-1f3fd", "v_medium_dark_skin_tone": "270c-1f3fe", "v_dark_skin_tone": "270c-1f3ff", "writing_hand_light_skin_tone": "270d-1f3fb", "writing_hand_medium_light_skin_tone": "270d-1f3fc", "writing_hand_medium_skin_tone": "270d-1f3fd", "writing_hand_medium_dark_skin_tone": "270d-1f3fe", "writing_hand_dark_skin_tone": "270d-1f3ff", "mattermost": "mattermost"} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_search.go deleted file mode 100644 index 71e2671c..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/emoji_search.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type EmojiSearch struct { - Term string `json:"term"` - PrefixOnly bool `json:"prefix_only"` -} - -func (es *EmojiSearch) ToJson() string { - b, _ := json.Marshal(es) - return string(b) -} - -func EmojiSearchFromJson(data io.Reader) *EmojiSearch { - var es *EmojiSearch - json.NewDecoder(data).Decode(&es) - return es -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/feature_flags.go b/vendor/github.com/mattermost/mattermost-server/v5/model/feature_flags.go deleted file mode 100644 index 7d3d6680..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/feature_flags.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "reflect" - "strconv" -) - -type FeatureFlags struct { - // Exists only for unit and manual testing. - // When set to a value, will be returned by the ping endpoint. - TestFeature string - // Exists only for testing bool functionality. Boolean feature flags interpret "on" or "true" as true and - // all other values as false. - TestBoolFeature bool - - // Toggle on and off scheduled jobs for cloud user limit emails see MM-29999 - CloudDelinquentEmailJobsEnabled bool - - // Toggle on and off support for Collapsed Threads - CollapsedThreads bool - - // Enable the remote cluster service for shared channels. - EnableRemoteClusterService bool - - // AppsEnabled toggle the Apps framework functionalities both in server and client side - AppsEnabled bool - - // Feature flags to control plugin versions - PluginIncidentManagement string `plugin_id:"com.mattermost.plugin-incident-management"` - PluginApps string `plugin_id:"com.mattermost.apps"` - PluginFocalboard string `plugin_id:"focalboard"` - - // Enable timed dnd support for user status - TimedDND bool -} - -func (f *FeatureFlags) SetDefaults() { - f.TestFeature = "off" - f.TestBoolFeature = false - f.CloudDelinquentEmailJobsEnabled = false - f.CollapsedThreads = true - f.EnableRemoteClusterService = false - f.AppsEnabled = false - f.PluginIncidentManagement = "1.16.1" - f.PluginApps = "" - f.PluginFocalboard = "" - f.TimedDND = false -} - -func (f *FeatureFlags) Plugins() map[string]string { - rFFVal := reflect.ValueOf(f).Elem() - rFFType := reflect.TypeOf(f).Elem() - - pluginVersions := make(map[string]string) - for i := 0; i < rFFVal.NumField(); i++ { - rFieldVal := rFFVal.Field(i) - rFieldType := rFFType.Field(i) - - pluginId, hasPluginId := rFieldType.Tag.Lookup("plugin_id") - if !hasPluginId { - continue - } - - pluginVersions[pluginId] = rFieldVal.String() - } - - return pluginVersions -} - -// ToMap returns the feature flags as a map[string]string -// Supports boolean and string feature flags. -func (f *FeatureFlags) ToMap() map[string]string { - refStructVal := reflect.ValueOf(*f) - refStructType := reflect.TypeOf(*f) - ret := make(map[string]string) - for i := 0; i < refStructVal.NumField(); i++ { - refFieldVal := refStructVal.Field(i) - if !refFieldVal.IsValid() { - continue - } - refFieldType := refStructType.Field(i) - switch refFieldType.Type.Kind() { - case reflect.Bool: - ret[refFieldType.Name] = strconv.FormatBool(refFieldVal.Bool()) - default: - ret[refFieldType.Name] = refFieldVal.String() - } - } - - return ret -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/file.go b/vendor/github.com/mattermost/mattermost-server/v5/model/file.go deleted file mode 100644 index d2cb8f34..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/file.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -const ( - MaxImageSize = int64(6048 * 4032) // 24 megapixels, roughly 36MB as a raw image -) - -type FileUploadResponse struct { - FileInfos []*FileInfo `json:"file_infos"` - ClientIds []string `json:"client_ids"` -} - -func FileUploadResponseFromJson(data io.Reader) *FileUploadResponse { - var o *FileUploadResponse - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *FileUploadResponse) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/file_info.go b/vendor/github.com/mattermost/mattermost-server/v5/model/file_info.go deleted file mode 100644 index 2bad9023..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/file_info.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "image" - "image/gif" - "io" - "mime" - "net/http" - "path/filepath" - "strings" -) - -const ( - FILEINFO_SORT_BY_CREATED = "CreateAt" - FILEINFO_SORT_BY_SIZE = "Size" -) - -// GetFileInfosOptions contains options for getting FileInfos -type GetFileInfosOptions struct { - // UserIds optionally limits the FileInfos to those created by the given users. - UserIds []string `json:"user_ids"` - // ChannelIds optionally limits the FileInfos to those created in the given channels. - ChannelIds []string `json:"channel_ids"` - // Since optionally limits FileInfos to those created at or after the given time, specified as Unix time in milliseconds. - Since int64 `json:"since"` - // IncludeDeleted if set includes deleted FileInfos. - IncludeDeleted bool `json:"include_deleted"` - // SortBy sorts the FileInfos by this field. The default is to sort by date created. - SortBy string `json:"sort_by"` - // SortDescending changes the sort direction to descending order when true. - SortDescending bool `json:"sort_descending"` -} - -type FileInfo struct { - Id string `json:"id"` - CreatorId string `json:"user_id"` - PostId string `json:"post_id,omitempty"` - ChannelId string `db:"-" json:"channel_id"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - Path string `json:"-"` // not sent back to the client - ThumbnailPath string `json:"-"` // not sent back to the client - PreviewPath string `json:"-"` // not sent back to the client - Name string `json:"name"` - Extension string `json:"extension"` - Size int64 `json:"size"` - MimeType string `json:"mime_type"` - Width int `json:"width,omitempty"` - Height int `json:"height,omitempty"` - HasPreviewImage bool `json:"has_preview_image,omitempty"` - MiniPreview *[]byte `json:"mini_preview"` // declared as *[]byte to avoid postgres/mysql differences in deserialization - Content string `json:"-"` - RemoteId *string `json:"remote_id"` -} - -func (fi *FileInfo) ToJson() string { - b, _ := json.Marshal(fi) - return string(b) -} - -func FileInfoFromJson(data io.Reader) *FileInfo { - decoder := json.NewDecoder(data) - - var fi FileInfo - if err := decoder.Decode(&fi); err != nil { - return nil - } - return &fi -} - -func FileInfosToJson(infos []*FileInfo) string { - b, _ := json.Marshal(infos) - return string(b) -} - -func FileInfosFromJson(data io.Reader) []*FileInfo { - decoder := json.NewDecoder(data) - - var infos []*FileInfo - if err := decoder.Decode(&infos); err != nil { - return nil - } - return infos -} - -func (fi *FileInfo) PreSave() { - if fi.Id == "" { - fi.Id = NewId() - } - - if fi.CreateAt == 0 { - fi.CreateAt = GetMillis() - } - - if fi.UpdateAt < fi.CreateAt { - fi.UpdateAt = fi.CreateAt - } - - if fi.RemoteId == nil { - fi.RemoteId = NewString("") - } -} - -func (fi *FileInfo) IsValid() *AppError { - if !IsValidId(fi.Id) { - return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.id.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidId(fi.CreatorId) && fi.CreatorId != "nouser" { - return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.user_id.app_error", nil, "id="+fi.Id, http.StatusBadRequest) - } - - if fi.PostId != "" && !IsValidId(fi.PostId) { - return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.post_id.app_error", nil, "id="+fi.Id, http.StatusBadRequest) - } - - if fi.CreateAt == 0 { - return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.create_at.app_error", nil, "id="+fi.Id, http.StatusBadRequest) - } - - if fi.UpdateAt == 0 { - return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.update_at.app_error", nil, "id="+fi.Id, http.StatusBadRequest) - } - - if fi.Path == "" { - return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.path.app_error", nil, "id="+fi.Id, http.StatusBadRequest) - } - - return nil -} - -func (fi *FileInfo) IsImage() bool { - return strings.HasPrefix(fi.MimeType, "image") -} - -func NewInfo(name string) *FileInfo { - info := &FileInfo{ - Name: name, - } - - extension := strings.ToLower(filepath.Ext(name)) - info.MimeType = mime.TypeByExtension(extension) - - if extension != "" && extension[0] == '.' { - // The client expects a file extension without the leading period - info.Extension = extension[1:] - } else { - info.Extension = extension - } - - return info -} - -func GetInfoForBytes(name string, data io.ReadSeeker, size int) (*FileInfo, *AppError) { - info := &FileInfo{ - Name: name, - Size: int64(size), - } - var err *AppError - - extension := strings.ToLower(filepath.Ext(name)) - info.MimeType = mime.TypeByExtension(extension) - - if extension != "" && extension[0] == '.' { - // The client expects a file extension without the leading period - info.Extension = extension[1:] - } else { - info.Extension = extension - } - - if info.IsImage() { - // Only set the width and height if it's actually an image that we can understand - if config, _, err := image.DecodeConfig(data); err == nil { - info.Width = config.Width - info.Height = config.Height - - if info.MimeType == "image/gif" { - // Just show the gif itself instead of a preview image for animated gifs - data.Seek(0, io.SeekStart) - gifConfig, err := gif.DecodeAll(data) - if err != nil { - // Still return the rest of the info even though it doesn't appear to be an actual gif - info.HasPreviewImage = true - return info, NewAppError("GetInfoForBytes", "model.file_info.get.gif.app_error", nil, err.Error(), http.StatusBadRequest) - } - info.HasPreviewImage = len(gifConfig.Image) == 1 - } else { - info.HasPreviewImage = true - } - } - } - - return info, err -} - -func GetEtagForFileInfos(infos []*FileInfo) string { - if len(infos) == 0 { - return Etag() - } - - var maxUpdateAt int64 - - for _, info := range infos { - if info.UpdateAt > maxUpdateAt { - maxUpdateAt = info.UpdateAt - } - } - - return Etag(infos[0].PostId, maxUpdateAt) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_list.go b/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_list.go deleted file mode 100644 index cd9694f5..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_list.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "sort" -) - -type FileInfoList struct { - Order []string `json:"order"` - FileInfos map[string]*FileInfo `json:"file_infos"` - NextFileInfoId string `json:"next_file_info_id"` - PrevFileInfoId string `json:"prev_file_info_id"` -} - -func NewFileInfoList() *FileInfoList { - return &FileInfoList{ - Order: make([]string, 0), - FileInfos: make(map[string]*FileInfo), - NextFileInfoId: "", - PrevFileInfoId: "", - } -} - -func (o *FileInfoList) ToSlice() []*FileInfo { - var fileInfos []*FileInfo - for _, id := range o.Order { - fileInfos = append(fileInfos, o.FileInfos[id]) - } - return fileInfos -} - -func (o *FileInfoList) ToJson() string { - b, err := json.Marshal(o) - if err != nil { - return "" - } else { - return string(b) - } -} - -func (o *FileInfoList) MakeNonNil() { - if o.Order == nil { - o.Order = make([]string, 0) - } - - if o.FileInfos == nil { - o.FileInfos = make(map[string]*FileInfo) - } -} - -func (o *FileInfoList) AddOrder(id string) { - if o.Order == nil { - o.Order = make([]string, 0, 128) - } - - o.Order = append(o.Order, id) -} - -func (o *FileInfoList) AddFileInfo(fileInfo *FileInfo) { - if o.FileInfos == nil { - o.FileInfos = make(map[string]*FileInfo) - } - - o.FileInfos[fileInfo.Id] = fileInfo -} - -func (o *FileInfoList) UniqueOrder() { - keys := make(map[string]bool) - order := []string{} - for _, fileInfoId := range o.Order { - if _, value := keys[fileInfoId]; !value { - keys[fileInfoId] = true - order = append(order, fileInfoId) - } - } - - o.Order = order -} - -func (o *FileInfoList) Extend(other *FileInfoList) { - for fileInfoId := range other.FileInfos { - o.AddFileInfo(other.FileInfos[fileInfoId]) - } - - for _, fileInfoId := range other.Order { - o.AddOrder(fileInfoId) - } - - o.UniqueOrder() -} - -func (o *FileInfoList) SortByCreateAt() { - sort.Slice(o.Order, func(i, j int) bool { - return o.FileInfos[o.Order[i]].CreateAt > o.FileInfos[o.Order[j]].CreateAt - }) -} - -func (o *FileInfoList) Etag() string { - id := "0" - var t int64 = 0 - - for _, v := range o.FileInfos { - if v.UpdateAt > t { - t = v.UpdateAt - id = v.Id - } else if v.UpdateAt == t && v.Id > id { - t = v.UpdateAt - id = v.Id - } - } - - orderId := "" - if len(o.Order) > 0 { - orderId = o.Order[0] - } - - return Etag(orderId, id, t) -} - -func FileInfoListFromJson(data io.Reader) *FileInfoList { - var o *FileInfoList - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_search_results.go b/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_search_results.go deleted file mode 100644 index 90f2922b..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/file_info_search_results.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type FileInfoSearchMatches map[string][]string - -type FileInfoSearchResults struct { - *FileInfoList - Matches FileInfoSearchMatches `json:"matches"` -} - -func MakeFileInfoSearchResults(fileInfos *FileInfoList, matches FileInfoSearchMatches) *FileInfoSearchResults { - return &FileInfoSearchResults{ - fileInfos, - matches, - } -} - -func (o *FileInfoSearchResults) ToJson() string { - b, err := json.Marshal(o) - if err != nil { - return "" - } - return string(b) -} - -func FileInfoSearchResultsFromJson(data io.Reader) *FileInfoSearchResults { - var o *FileInfoSearchResults - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/gitlab.go b/vendor/github.com/mattermost/mattermost-server/v5/model/gitlab.go deleted file mode 100644 index 0b069cd6..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/gitlab.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -const ( - USER_AUTH_SERVICE_GITLAB = "gitlab" -) diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/group.go b/vendor/github.com/mattermost/mattermost-server/v5/model/group.go deleted file mode 100644 index c70b7aa1..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/group.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" - "regexp" -) - -const ( - GroupSourceLdap GroupSource = "ldap" - - GroupNameMaxLength = 64 - GroupSourceMaxLength = 64 - GroupDisplayNameMaxLength = 128 - GroupDescriptionMaxLength = 1024 - GroupRemoteIDMaxLength = 48 -) - -type GroupSource string - -var allGroupSources = []GroupSource{ - GroupSourceLdap, -} - -var groupSourcesRequiringRemoteID = []GroupSource{ - GroupSourceLdap, -} - -type Group struct { - Id string `json:"id"` - Name *string `json:"name,omitempty"` - DisplayName string `json:"display_name"` - Description string `json:"description"` - Source GroupSource `json:"source"` - RemoteId string `json:"remote_id"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - HasSyncables bool `db:"-" json:"has_syncables"` - MemberCount *int `db:"-" json:"member_count,omitempty"` - AllowReference bool `json:"allow_reference"` -} - -type GroupWithSchemeAdmin struct { - Group - SchemeAdmin *bool `db:"SyncableSchemeAdmin" json:"scheme_admin,omitempty"` -} - -type GroupsAssociatedToChannelWithSchemeAdmin struct { - ChannelId string `json:"channel_id"` - Group - SchemeAdmin *bool `db:"SyncableSchemeAdmin" json:"scheme_admin,omitempty"` -} -type GroupsAssociatedToChannel struct { - ChannelId string `json:"channel_id"` - Groups []*GroupWithSchemeAdmin `json:"groups"` -} - -type GroupPatch struct { - Name *string `json:"name"` - DisplayName *string `json:"display_name"` - Description *string `json:"description"` - AllowReference *bool `json:"allow_reference"` -} - -type LdapGroupSearchOpts struct { - Q string - IsLinked *bool - IsConfigured *bool -} - -type GroupSearchOpts struct { - Q string - NotAssociatedToTeam string - NotAssociatedToChannel string - IncludeMemberCount bool - FilterAllowReference bool - PageOpts *PageOpts - Since int64 - - // FilterParentTeamPermitted filters the groups to the intersect of the - // set associated to the parent team and those returned by the query. - // If the parent team is not group-constrained or if NotAssociatedToChannel - // is not set then this option is ignored. - FilterParentTeamPermitted bool -} - -type PageOpts struct { - Page int - PerPage int -} - -type GroupStats struct { - GroupID string `json:"group_id"` - TotalMemberCount int64 `json:"total_member_count"` -} - -func (group *Group) Patch(patch *GroupPatch) { - if patch.Name != nil { - group.Name = patch.Name - } - if patch.DisplayName != nil { - group.DisplayName = *patch.DisplayName - } - if patch.Description != nil { - group.Description = *patch.Description - } - if patch.AllowReference != nil { - group.AllowReference = *patch.AllowReference - } -} - -func (group *Group) IsValidForCreate() *AppError { - err := group.IsValidName() - if err != nil { - return err - } - - if l := len(group.DisplayName); l == 0 || l > GroupDisplayNameMaxLength { - return NewAppError("Group.IsValidForCreate", "model.group.display_name.app_error", map[string]interface{}{"GroupDisplayNameMaxLength": GroupDisplayNameMaxLength}, "", http.StatusBadRequest) - } - - if len(group.Description) > GroupDescriptionMaxLength { - return NewAppError("Group.IsValidForCreate", "model.group.description.app_error", map[string]interface{}{"GroupDescriptionMaxLength": GroupDescriptionMaxLength}, "", http.StatusBadRequest) - } - - isValidSource := false - for _, groupSource := range allGroupSources { - if group.Source == groupSource { - isValidSource = true - break - } - } - if !isValidSource { - return NewAppError("Group.IsValidForCreate", "model.group.source.app_error", nil, "", http.StatusBadRequest) - } - - if len(group.RemoteId) > GroupRemoteIDMaxLength || (group.RemoteId == "" && group.requiresRemoteId()) { - return NewAppError("Group.IsValidForCreate", "model.group.remote_id.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (group *Group) requiresRemoteId() bool { - for _, groupSource := range groupSourcesRequiringRemoteID { - if groupSource == group.Source { - return true - } - } - return false -} - -func (group *Group) IsValidForUpdate() *AppError { - if !IsValidId(group.Id) { - return NewAppError("Group.IsValidForUpdate", "app.group.id.app_error", nil, "", http.StatusBadRequest) - } - if group.CreateAt == 0 { - return NewAppError("Group.IsValidForUpdate", "model.group.create_at.app_error", nil, "", http.StatusBadRequest) - } - if group.UpdateAt == 0 { - return NewAppError("Group.IsValidForUpdate", "model.group.update_at.app_error", nil, "", http.StatusBadRequest) - } - if err := group.IsValidForCreate(); err != nil { - return err - } - return nil -} - -func (group *Group) ToJson() string { - b, _ := json.Marshal(group) - return string(b) -} - -var validGroupnameChars = regexp.MustCompile(`^[a-z0-9\.\-_]+$`) - -func (group *Group) IsValidName() *AppError { - - if group.Name == nil { - if group.AllowReference { - return NewAppError("Group.IsValidName", "model.group.name.app_error", map[string]interface{}{"GroupNameMaxLength": GroupNameMaxLength}, "", http.StatusBadRequest) - } - } else { - if l := len(*group.Name); l == 0 || l > GroupNameMaxLength { - return NewAppError("Group.IsValidName", "model.group.name.invalid_length.app_error", map[string]interface{}{"GroupNameMaxLength": GroupNameMaxLength}, "", http.StatusBadRequest) - } - - if !validGroupnameChars.MatchString(*group.Name) { - return NewAppError("Group.IsValidName", "model.group.name.invalid_chars.app_error", nil, "", http.StatusBadRequest) - } - } - return nil -} - -func GroupFromJson(data io.Reader) *Group { - var group *Group - json.NewDecoder(data).Decode(&group) - return group -} - -func GroupsFromJson(data io.Reader) []*Group { - var groups []*Group - json.NewDecoder(data).Decode(&groups) - return groups -} - -func GroupPatchFromJson(data io.Reader) *GroupPatch { - var groupPatch *GroupPatch - json.NewDecoder(data).Decode(&groupPatch) - return groupPatch -} - -func GroupStatsFromJson(data io.Reader) *GroupStats { - var groupStats *GroupStats - json.NewDecoder(data).Decode(&groupStats) - return groupStats -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/group_member.go b/vendor/github.com/mattermost/mattermost-server/v5/model/group_member.go deleted file mode 100644 index d18d7849..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/group_member.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import "net/http" - -type GroupMember struct { - GroupId string `json:"group_id"` - UserId string `json:"user_id"` - CreateAt int64 `json:"create_at"` - DeleteAt int64 `json:"delete_at"` -} - -func (gm *GroupMember) IsValid() *AppError { - if !IsValidId(gm.GroupId) { - return NewAppError("GroupMember.IsValid", "model.group_member.group_id.app_error", nil, "", http.StatusBadRequest) - } - if !IsValidId(gm.UserId) { - return NewAppError("GroupMember.IsValid", "model.group_member.user_id.app_error", nil, "", http.StatusBadRequest) - } - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/group_syncable.go b/vendor/github.com/mattermost/mattermost-server/v5/model/group_syncable.go deleted file mode 100644 index eb3bdf09..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/group_syncable.go +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" -) - -type GroupSyncableType string - -const ( - GroupSyncableTypeTeam GroupSyncableType = "Team" - GroupSyncableTypeChannel GroupSyncableType = "Channel" -) - -func (gst GroupSyncableType) String() string { - return string(gst) -} - -type GroupSyncable struct { - GroupId string `json:"group_id"` - - // SyncableId represents the Id of the model that is being synced with the group, for example a ChannelId or - // TeamId. - SyncableId string `db:"-" json:"-"` - - AutoAdd bool `json:"auto_add"` - SchemeAdmin bool `json:"scheme_admin"` - CreateAt int64 `json:"create_at"` - DeleteAt int64 `json:"delete_at"` - UpdateAt int64 `json:"update_at"` - Type GroupSyncableType `db:"-" json:"-"` - - // Values joined in from the associated team and/or channel - ChannelDisplayName string `db:"-" json:"-"` - TeamDisplayName string `db:"-" json:"-"` - TeamType string `db:"-" json:"-"` - ChannelType string `db:"-" json:"-"` - TeamID string `db:"-" json:"-"` -} - -func (syncable *GroupSyncable) IsValid() *AppError { - if !IsValidId(syncable.GroupId) { - return NewAppError("GroupSyncable.SyncableIsValid", "model.group_syncable.group_id.app_error", nil, "", http.StatusBadRequest) - } - if !IsValidId(syncable.SyncableId) { - return NewAppError("GroupSyncable.SyncableIsValid", "model.group_syncable.syncable_id.app_error", nil, "", http.StatusBadRequest) - } - return nil -} - -func (syncable *GroupSyncable) UnmarshalJSON(b []byte) error { - var kvp map[string]interface{} - err := json.Unmarshal(b, &kvp) - if err != nil { - return err - } - var channelId string - var teamId string - for key, value := range kvp { - switch key { - case "team_id": - teamId = value.(string) - case "channel_id": - channelId = value.(string) - case "group_id": - syncable.GroupId = value.(string) - case "auto_add": - syncable.AutoAdd = value.(bool) - default: - } - } - if channelId != "" { - syncable.TeamID = teamId - syncable.SyncableId = channelId - syncable.Type = GroupSyncableTypeChannel - } else { - syncable.SyncableId = teamId - syncable.Type = GroupSyncableTypeTeam - } - return nil -} - -func (syncable *GroupSyncable) MarshalJSON() ([]byte, error) { - type Alias GroupSyncable - switch syncable.Type { - case GroupSyncableTypeTeam: - return json.Marshal(&struct { - TeamID string `json:"team_id"` - TeamDisplayName string `json:"team_display_name,omitempty"` - TeamType string `json:"team_type,omitempty"` - Type GroupSyncableType `json:"type,omitempty"` - *Alias - }{ - TeamDisplayName: syncable.TeamDisplayName, - TeamType: syncable.TeamType, - TeamID: syncable.SyncableId, - Type: syncable.Type, - Alias: (*Alias)(syncable), - }) - case GroupSyncableTypeChannel: - return json.Marshal(&struct { - ChannelID string `json:"channel_id"` - ChannelDisplayName string `json:"channel_display_name,omitempty"` - ChannelType string `json:"channel_type,omitempty"` - Type GroupSyncableType `json:"type,omitempty"` - - TeamID string `json:"team_id,omitempty"` - TeamDisplayName string `json:"team_display_name,omitempty"` - TeamType string `json:"team_type,omitempty"` - - *Alias - }{ - ChannelID: syncable.SyncableId, - ChannelDisplayName: syncable.ChannelDisplayName, - ChannelType: syncable.ChannelType, - Type: syncable.Type, - - TeamID: syncable.TeamID, - TeamDisplayName: syncable.TeamDisplayName, - TeamType: syncable.TeamType, - - Alias: (*Alias)(syncable), - }) - default: - return nil, &json.MarshalerError{ - Err: fmt.Errorf("unknown syncable type: %s", syncable.Type), - } - } -} - -type GroupSyncablePatch struct { - AutoAdd *bool `json:"auto_add"` - SchemeAdmin *bool `json:"scheme_admin"` -} - -func (syncable *GroupSyncable) Patch(patch *GroupSyncablePatch) { - if patch.AutoAdd != nil { - syncable.AutoAdd = *patch.AutoAdd - } - if patch.SchemeAdmin != nil { - syncable.SchemeAdmin = *patch.SchemeAdmin - } -} - -type UserTeamIDPair struct { - UserID string - TeamID string -} - -type UserChannelIDPair struct { - UserID string - ChannelID string -} - -func GroupSyncableFromJson(data io.Reader) *GroupSyncable { - groupSyncable := &GroupSyncable{} - bodyBytes, _ := ioutil.ReadAll(data) - json.Unmarshal(bodyBytes, groupSyncable) - return groupSyncable -} - -func GroupSyncablesFromJson(data io.Reader) []*GroupSyncable { - groupSyncables := []*GroupSyncable{} - bodyBytes, _ := ioutil.ReadAll(data) - json.Unmarshal(bodyBytes, &groupSyncables) - return groupSyncables -} - -func NewGroupTeam(groupID, teamID string, autoAdd bool) *GroupSyncable { - return &GroupSyncable{ - GroupId: groupID, - SyncableId: teamID, - Type: GroupSyncableTypeTeam, - AutoAdd: autoAdd, - } -} - -func NewGroupChannel(groupID, channelID string, autoAdd bool) *GroupSyncable { - return &GroupSyncable{ - GroupId: groupID, - SyncableId: channelID, - Type: GroupSyncableTypeChannel, - AutoAdd: autoAdd, - } -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/guest_invite.go b/vendor/github.com/mattermost/mattermost-server/v5/model/guest_invite.go deleted file mode 100644 index ac803a5d..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/guest_invite.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" -) - -type GuestsInvite struct { - Emails []string `json:"emails"` - Channels []string `json:"channels"` - Message string `json:"message"` -} - -// IsValid validates the user and returns an error if it isn't configured -// correctly. -func (i *GuestsInvite) IsValid() *AppError { - if len(i.Emails) == 0 { - return NewAppError("GuestsInvite.IsValid", "model.guest.is_valid.emails.app_error", nil, "", http.StatusBadRequest) - } - - for _, email := range i.Emails { - if len(email) > USER_EMAIL_MAX_LENGTH || email == "" || !IsValidEmail(email) { - return NewAppError("GuestsInvite.IsValid", "model.guest.is_valid.email.app_error", nil, "email="+email, http.StatusBadRequest) - } - } - - if len(i.Channels) == 0 { - return NewAppError("GuestsInvite.IsValid", "model.guest.is_valid.channels.app_error", nil, "", http.StatusBadRequest) - } - - for _, channel := range i.Channels { - if len(channel) != 26 { - return NewAppError("GuestsInvite.IsValid", "model.guest.is_valid.channel.app_error", nil, "channel="+channel, http.StatusBadRequest) - } - } - return nil -} - -// GuestsInviteFromJson will decode the input and return a GuestsInvite -func GuestsInviteFromJson(data io.Reader) *GuestsInvite { - var i *GuestsInvite - json.NewDecoder(data).Decode(&i) - return i -} - -func (i *GuestsInvite) ToJson() string { - b, _ := json.Marshal(i) - return string(b) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/incoming_webhook.go b/vendor/github.com/mattermost/mattermost-server/v5/model/incoming_webhook.go deleted file mode 100644 index f8fffe20..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/incoming_webhook.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "bytes" - "encoding/json" - "io" - "net/http" - "regexp" -) - -const ( - DEFAULT_WEBHOOK_USERNAME = "webhook" -) - -type IncomingWebhook struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - UserId string `json:"user_id"` - ChannelId string `json:"channel_id"` - TeamId string `json:"team_id"` - DisplayName string `json:"display_name"` - Description string `json:"description"` - Username string `json:"username"` - IconURL string `json:"icon_url"` - ChannelLocked bool `json:"channel_locked"` -} - -type IncomingWebhookRequest struct { - Text string `json:"text"` - Username string `json:"username"` - IconURL string `json:"icon_url"` - ChannelName string `json:"channel"` - Props StringInterface `json:"props"` - Attachments []*SlackAttachment `json:"attachments"` - Type string `json:"type"` - IconEmoji string `json:"icon_emoji"` -} - -func (o *IncomingWebhook) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func IncomingWebhookFromJson(data io.Reader) *IncomingWebhook { - var o *IncomingWebhook - json.NewDecoder(data).Decode(&o) - return o -} - -func IncomingWebhookListToJson(l []*IncomingWebhook) string { - b, _ := json.Marshal(l) - return string(b) -} - -func IncomingWebhookListFromJson(data io.Reader) []*IncomingWebhook { - var o []*IncomingWebhook - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *IncomingWebhook) IsValid() *AppError { - - if !IsValidId(o.Id) { - return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.id.app_error", nil, "", http.StatusBadRequest) - - } - - if o.CreateAt == 0 { - return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if o.UpdateAt == 0 { - return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if !IsValidId(o.UserId) { - return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.user_id.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidId(o.ChannelId) { - return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.channel_id.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidId(o.TeamId) { - return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.team_id.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.DisplayName) > 64 { - return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.display_name.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.Description) > 500 { - return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.description.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.Username) > 64 { - return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.username.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.IconURL) > 1024 { - return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.icon_url.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (o *IncomingWebhook) PreSave() { - if o.Id == "" { - o.Id = NewId() - } - - o.CreateAt = GetMillis() - o.UpdateAt = o.CreateAt -} - -func (o *IncomingWebhook) PreUpdate() { - o.UpdateAt = GetMillis() -} - -// escapeControlCharsFromPayload escapes control chars (\n, \t) from a byte slice. -// Context: -// JSON strings are not supposed to contain control characters such as \n, \t, -// ... but some incoming webhooks might still send invalid JSON and we want to -// try to handle that. An example invalid JSON string from an incoming webhook -// might look like this (strings for both "text" and "fallback" attributes are -// invalid JSON strings because they contain unescaped newlines and tabs): -// `{ -// "text": "this is a test -// that contains a newline and tabs", -// "attachments": [ -// { -// "fallback": "Required plain-text summary of the attachment -// that contains a newline and tabs", -// "color": "#36a64f", -// ... -// "text": "Optional text that appears within the attachment -// that contains a newline and tabs", -// ... -// "thumb_url": "http://example.com/path/to/thumb.png" -// } -// ] -// }` -// This function will search for `"key": "value"` pairs, and escape \n, \t -// from the value. -func escapeControlCharsFromPayload(by []byte) []byte { - // we'll search for `"text": "..."` or `"fallback": "..."`, ... - keys := "text|fallback|pretext|author_name|title|value" - - // the regexp reads like this: - // (?s): this flag let . match \n (default is false) - // "(keys)": we search for the keys defined above - // \s*:\s*: followed by 0..n spaces/tabs, a colon then 0..n spaces/tabs - // ": a double-quote - // (\\"|[^"])*: any number of times the `\"` string or any char but a double-quote - // ": a double-quote - r := `(?s)"(` + keys + `)"\s*:\s*"(\\"|[^"])*"` - re := regexp.MustCompile(r) - - // the function that will escape \n and \t on the regexp matches - repl := func(b []byte) []byte { - if bytes.Contains(b, []byte("\n")) { - b = bytes.Replace(b, []byte("\n"), []byte("\\n"), -1) - } - if bytes.Contains(b, []byte("\t")) { - b = bytes.Replace(b, []byte("\t"), []byte("\\t"), -1) - } - - return b - } - - return re.ReplaceAllFunc(by, repl) -} - -func decodeIncomingWebhookRequest(by []byte) (*IncomingWebhookRequest, error) { - decoder := json.NewDecoder(bytes.NewReader(by)) - var o IncomingWebhookRequest - err := decoder.Decode(&o) - if err == nil { - return &o, nil - } - return nil, err -} - -func IncomingWebhookRequestFromJson(data io.Reader) (*IncomingWebhookRequest, *AppError) { - buf := new(bytes.Buffer) - buf.ReadFrom(data) - by := buf.Bytes() - - // Try to decode the JSON data. Only if it fails, try to escape control - // characters from the strings contained in the JSON data. - o, err := decodeIncomingWebhookRequest(by) - if err != nil { - o, err = decodeIncomingWebhookRequest(escapeControlCharsFromPayload(by)) - if err != nil { - return nil, NewAppError("IncomingWebhookRequestFromJson", "model.incoming_hook.parse_data.app_error", nil, err.Error(), http.StatusBadRequest) - } - } - - o.Attachments = StringifySlackFieldValue(o.Attachments) - - return o, nil -} - -func (o *IncomingWebhookRequest) ToJson() string { - b, err := json.Marshal(o) - if err != nil { - return "" - } - return string(b) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/initial_load.go b/vendor/github.com/mattermost/mattermost-server/v5/model/initial_load.go deleted file mode 100644 index c533faa5..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/initial_load.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type InitialLoad struct { - User *User `json:"user"` - TeamMembers []*TeamMember `json:"team_members"` - Teams []*Team `json:"teams"` - Preferences Preferences `json:"preferences"` - ClientCfg map[string]string `json:"client_cfg"` - LicenseCfg map[string]string `json:"license_cfg"` - NoAccounts bool `json:"no_accounts"` -} - -func (il *InitialLoad) ToJson() string { - b, _ := json.Marshal(il) - return string(b) -} - -func InitialLoadFromJson(data io.Reader) *InitialLoad { - var il *InitialLoad - json.NewDecoder(data).Decode(&il) - return il -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/integration_action.go b/vendor/github.com/mattermost/mattermost-server/v5/model/integration_action.go deleted file mode 100644 index 7124a7e3..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/integration_action.go +++ /dev/null @@ -1,532 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "crypto" - "crypto/aes" - "crypto/cipher" - "crypto/ecdsa" - "crypto/rand" - "encoding/asn1" - "encoding/base64" - "encoding/json" - "fmt" - "io" - "math/big" - "net/http" - "reflect" - "strconv" - "strings" -) - -const ( - POST_ACTION_TYPE_BUTTON = "button" - POST_ACTION_TYPE_SELECT = "select" - INTERACTIVE_DIALOG_TRIGGER_TIMEOUT_MILLISECONDS = 3000 -) - -var PostActionRetainPropKeys = []string{"from_webhook", "override_username", "override_icon_url"} - -type DoPostActionRequest struct { - SelectedOption string `json:"selected_option,omitempty"` - Cookie string `json:"cookie,omitempty"` -} - -type PostAction struct { - // A unique Action ID. If not set, generated automatically. - Id string `json:"id,omitempty"` - - // The type of the interactive element. Currently supported are - // "select" and "button". - Type string `json:"type,omitempty"` - - // The text on the button, or in the select placeholder. - Name string `json:"name,omitempty"` - - // If the action is disabled. - Disabled bool `json:"disabled,omitempty"` - - // Style defines a text and border style. - // Supported values are "default", "primary", "success", "good", "warning", "danger" - // and any hex color. - Style string `json:"style,omitempty"` - - // DataSource indicates the data source for the select action. If left - // empty, the select is populated from Options. Other supported values - // are "users" and "channels". - DataSource string `json:"data_source,omitempty"` - - // Options contains the values listed in a select dropdown on the post. - Options []*PostActionOptions `json:"options,omitempty"` - - // DefaultOption contains the option, if any, that will appear as the - // default selection in a select box. It has no effect when used with - // other types of actions. - DefaultOption string `json:"default_option,omitempty"` - - // Defines the interaction with the backend upon a user action. - // Integration contains Context, which is private plugin data; - // Integrations are stripped from Posts when they are sent to the - // client, or are encrypted in a Cookie. - Integration *PostActionIntegration `json:"integration,omitempty"` - Cookie string `json:"cookie,omitempty" db:"-"` -} - -func (p *PostAction) Equals(input *PostAction) bool { - if p.Id != input.Id { - return false - } - - if p.Type != input.Type { - return false - } - - if p.Name != input.Name { - return false - } - - if p.DataSource != input.DataSource { - return false - } - - if p.DefaultOption != input.DefaultOption { - return false - } - - if p.Cookie != input.Cookie { - return false - } - - // Compare PostActionOptions - if len(p.Options) != len(input.Options) { - return false - } - - for k := range p.Options { - if p.Options[k].Text != input.Options[k].Text { - return false - } - - if p.Options[k].Value != input.Options[k].Value { - return false - } - } - - // Compare PostActionIntegration - if p.Integration.URL != input.Integration.URL { - return false - } - - if len(p.Integration.Context) != len(input.Integration.Context) { - return false - } - - for key, value := range p.Integration.Context { - inputValue, ok := input.Integration.Context[key] - if !ok { - return false - } - - switch inputValue.(type) { - case string, bool, int, float64: - if value != inputValue { - return false - } - default: - if !reflect.DeepEqual(value, inputValue) { - return false - } - } - } - - return true -} - -// PostActionCookie is set by the server, serialized and encrypted into -// PostAction.Cookie. The clients should hold on to it, and include it with -// subsequent DoPostAction requests. This allows the server to access the -// action metadata even when it's not available in the database, for ephemeral -// posts. -type PostActionCookie struct { - Type string `json:"type,omitempty"` - PostId string `json:"post_id,omitempty"` - RootPostId string `json:"root_post_id,omitempty"` - ChannelId string `json:"channel_id,omitempty"` - DataSource string `json:"data_source,omitempty"` - Integration *PostActionIntegration `json:"integration,omitempty"` - RetainProps map[string]interface{} `json:"retain_props,omitempty"` - RemoveProps []string `json:"remove_props,omitempty"` -} - -type PostActionOptions struct { - Text string `json:"text"` - Value string `json:"value"` -} - -type PostActionIntegration struct { - URL string `json:"url,omitempty"` - Context map[string]interface{} `json:"context,omitempty"` -} - -type PostActionIntegrationRequest struct { - UserId string `json:"user_id"` - UserName string `json:"user_name"` - ChannelId string `json:"channel_id"` - ChannelName string `json:"channel_name"` - TeamId string `json:"team_id"` - TeamName string `json:"team_domain"` - PostId string `json:"post_id"` - TriggerId string `json:"trigger_id"` - Type string `json:"type"` - DataSource string `json:"data_source"` - Context map[string]interface{} `json:"context,omitempty"` -} - -type PostActionIntegrationResponse struct { - Update *Post `json:"update"` - EphemeralText string `json:"ephemeral_text"` - SkipSlackParsing bool `json:"skip_slack_parsing"` // Set to `true` to skip the Slack-compatibility handling of Text. -} - -type PostActionAPIResponse struct { - Status string `json:"status"` // needed to maintain backwards compatibility - TriggerId string `json:"trigger_id"` -} - -type Dialog struct { - CallbackId string `json:"callback_id"` - Title string `json:"title"` - IntroductionText string `json:"introduction_text"` - IconURL string `json:"icon_url"` - Elements []DialogElement `json:"elements"` - SubmitLabel string `json:"submit_label"` - NotifyOnCancel bool `json:"notify_on_cancel"` - State string `json:"state"` -} - -type DialogElement struct { - DisplayName string `json:"display_name"` - Name string `json:"name"` - Type string `json:"type"` - SubType string `json:"subtype"` - Default string `json:"default"` - Placeholder string `json:"placeholder"` - HelpText string `json:"help_text"` - Optional bool `json:"optional"` - MinLength int `json:"min_length"` - MaxLength int `json:"max_length"` - DataSource string `json:"data_source"` - Options []*PostActionOptions `json:"options"` -} - -type OpenDialogRequest struct { - TriggerId string `json:"trigger_id"` - URL string `json:"url"` - Dialog Dialog `json:"dialog"` -} - -type SubmitDialogRequest struct { - Type string `json:"type"` - URL string `json:"url,omitempty"` - CallbackId string `json:"callback_id"` - State string `json:"state"` - UserId string `json:"user_id"` - ChannelId string `json:"channel_id"` - TeamId string `json:"team_id"` - Submission map[string]interface{} `json:"submission"` - Cancelled bool `json:"cancelled"` -} - -type SubmitDialogResponse struct { - Error string `json:"error,omitempty"` - Errors map[string]string `json:"errors,omitempty"` -} - -func GenerateTriggerId(userId string, s crypto.Signer) (string, string, *AppError) { - clientTriggerId := NewId() - triggerData := strings.Join([]string{clientTriggerId, userId, strconv.FormatInt(GetMillis(), 10)}, ":") + ":" - - h := crypto.SHA256 - sum := h.New() - sum.Write([]byte(triggerData)) - signature, err := s.Sign(rand.Reader, sum.Sum(nil), h) - if err != nil { - return "", "", NewAppError("GenerateTriggerId", "interactive_message.generate_trigger_id.signing_failed", nil, err.Error(), http.StatusInternalServerError) - } - - base64Sig := base64.StdEncoding.EncodeToString(signature) - - triggerId := base64.StdEncoding.EncodeToString([]byte(triggerData + base64Sig)) - return clientTriggerId, triggerId, nil -} - -func (r *PostActionIntegrationRequest) GenerateTriggerId(s crypto.Signer) (string, string, *AppError) { - clientTriggerId, triggerId, err := GenerateTriggerId(r.UserId, s) - if err != nil { - return "", "", err - } - - r.TriggerId = triggerId - return clientTriggerId, triggerId, nil -} - -func DecodeAndVerifyTriggerId(triggerId string, s *ecdsa.PrivateKey) (string, string, *AppError) { - triggerIdBytes, err := base64.StdEncoding.DecodeString(triggerId) - if err != nil { - return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.base64_decode_failed", nil, err.Error(), http.StatusBadRequest) - } - - split := strings.Split(string(triggerIdBytes), ":") - if len(split) != 4 { - return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.missing_data", nil, "", http.StatusBadRequest) - } - - clientTriggerId := split[0] - userId := split[1] - timestampStr := split[2] - timestamp, _ := strconv.ParseInt(timestampStr, 10, 64) - - now := GetMillis() - if now-timestamp > INTERACTIVE_DIALOG_TRIGGER_TIMEOUT_MILLISECONDS { - return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.expired", map[string]interface{}{"Seconds": INTERACTIVE_DIALOG_TRIGGER_TIMEOUT_MILLISECONDS / 1000}, "", http.StatusBadRequest) - } - - signature, err := base64.StdEncoding.DecodeString(split[3]) - if err != nil { - return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.base64_decode_failed_signature", nil, err.Error(), http.StatusBadRequest) - } - - var esig struct { - R, S *big.Int - } - - if _, err := asn1.Unmarshal(signature, &esig); err != nil { - return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.signature_decode_failed", nil, err.Error(), http.StatusBadRequest) - } - - triggerData := strings.Join([]string{clientTriggerId, userId, timestampStr}, ":") + ":" - - h := crypto.SHA256 - sum := h.New() - sum.Write([]byte(triggerData)) - - if !ecdsa.Verify(&s.PublicKey, sum.Sum(nil), esig.R, esig.S) { - return "", "", NewAppError("DecodeAndVerifyTriggerId", "interactive_message.decode_trigger_id.verify_signature_failed", nil, "", http.StatusBadRequest) - } - - return clientTriggerId, userId, nil -} - -func (r *OpenDialogRequest) DecodeAndVerifyTriggerId(s *ecdsa.PrivateKey) (string, string, *AppError) { - return DecodeAndVerifyTriggerId(r.TriggerId, s) -} - -func (r *PostActionIntegrationRequest) ToJson() []byte { - b, _ := json.Marshal(r) - return b -} - -func PostActionIntegrationRequestFromJson(data io.Reader) *PostActionIntegrationRequest { - var o *PostActionIntegrationRequest - err := json.NewDecoder(data).Decode(&o) - if err != nil { - return nil - } - return o -} - -func (r *PostActionIntegrationResponse) ToJson() []byte { - b, _ := json.Marshal(r) - return b -} - -func PostActionIntegrationResponseFromJson(data io.Reader) *PostActionIntegrationResponse { - var o *PostActionIntegrationResponse - err := json.NewDecoder(data).Decode(&o) - if err != nil { - return nil - } - return o -} - -func SubmitDialogRequestFromJson(data io.Reader) *SubmitDialogRequest { - var o *SubmitDialogRequest - err := json.NewDecoder(data).Decode(&o) - if err != nil { - return nil - } - return o -} - -func (r *SubmitDialogRequest) ToJson() []byte { - b, _ := json.Marshal(r) - return b -} - -func SubmitDialogResponseFromJson(data io.Reader) *SubmitDialogResponse { - var o *SubmitDialogResponse - err := json.NewDecoder(data).Decode(&o) - if err != nil { - return nil - } - return o -} - -func (r *SubmitDialogResponse) ToJson() []byte { - b, _ := json.Marshal(r) - return b -} - -func (o *Post) StripActionIntegrations() { - attachments := o.Attachments() - if o.GetProp("attachments") != nil { - o.AddProp("attachments", attachments) - } - for _, attachment := range attachments { - for _, action := range attachment.Actions { - action.Integration = nil - } - } -} - -func (o *Post) GetAction(id string) *PostAction { - for _, attachment := range o.Attachments() { - for _, action := range attachment.Actions { - if action != nil && action.Id == id { - return action - } - } - } - return nil -} - -func (o *Post) GenerateActionIds() { - if o.GetProp("attachments") != nil { - o.AddProp("attachments", o.Attachments()) - } - if attachments, ok := o.GetProp("attachments").([]*SlackAttachment); ok { - for _, attachment := range attachments { - for _, action := range attachment.Actions { - if action != nil && action.Id == "" { - action.Id = NewId() - } - } - } - } -} - -func AddPostActionCookies(o *Post, secret []byte) *Post { - p := o.Clone() - - // retainedProps carry over their value from the old post, including no value - retainProps := map[string]interface{}{} - removeProps := []string{} - for _, key := range PostActionRetainPropKeys { - value, ok := p.GetProps()[key] - if ok { - retainProps[key] = value - } else { - removeProps = append(removeProps, key) - } - } - - attachments := p.Attachments() - for _, attachment := range attachments { - for _, action := range attachment.Actions { - c := &PostActionCookie{ - Type: action.Type, - ChannelId: p.ChannelId, - DataSource: action.DataSource, - Integration: action.Integration, - RetainProps: retainProps, - RemoveProps: removeProps, - } - - c.PostId = p.Id - if p.RootId == "" { - c.RootPostId = p.Id - } else { - c.RootPostId = p.RootId - } - - b, _ := json.Marshal(c) - action.Cookie, _ = encryptPostActionCookie(string(b), secret) - } - } - - return p -} - -func encryptPostActionCookie(plain string, secret []byte) (string, error) { - if len(secret) == 0 { - return plain, nil - } - - block, err := aes.NewCipher(secret) - if err != nil { - return "", err - } - - aesgcm, err := cipher.NewGCM(block) - if err != nil { - return "", err - } - - nonce := make([]byte, aesgcm.NonceSize()) - _, err = io.ReadFull(rand.Reader, nonce) - if err != nil { - return "", err - } - - sealed := aesgcm.Seal(nil, nonce, []byte(plain), nil) - - combined := append(nonce, sealed...) - encoded := make([]byte, base64.StdEncoding.EncodedLen(len(combined))) - base64.StdEncoding.Encode(encoded, combined) - - return string(encoded), nil -} - -func DecryptPostActionCookie(encoded string, secret []byte) (string, error) { - if len(secret) == 0 { - return encoded, nil - } - - block, err := aes.NewCipher(secret) - if err != nil { - return "", err - } - - aesgcm, err := cipher.NewGCM(block) - if err != nil { - return "", err - } - - decoded := make([]byte, base64.StdEncoding.DecodedLen(len(encoded))) - n, err := base64.StdEncoding.Decode(decoded, []byte(encoded)) - if err != nil { - return "", err - } - decoded = decoded[:n] - - nonceSize := aesgcm.NonceSize() - if len(decoded) < nonceSize { - return "", fmt.Errorf("cookie too short") - } - - nonce, decoded := decoded[:nonceSize], decoded[nonceSize:] - plain, err := aesgcm.Open(nil, nonce, decoded, nil) - if err != nil { - return "", err - } - - return string(plain), nil -} - -func DoPostActionRequestFromJson(data io.Reader) *DoPostActionRequest { - var o *DoPostActionRequest - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/integrity.go b/vendor/github.com/mattermost/mattermost-server/v5/model/integrity.go deleted file mode 100644 index 744ad07c..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/integrity.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "errors" -) - -type OrphanedRecord struct { - ParentId *string `json:"parent_id"` - ChildId *string `json:"child_id"` -} - -type RelationalIntegrityCheckData struct { - ParentName string `json:"parent_name"` - ChildName string `json:"child_name"` - ParentIdAttr string `json:"parent_id_attr"` - ChildIdAttr string `json:"child_id_attr"` - Records []OrphanedRecord `json:"records"` -} - -type IntegrityCheckResult struct { - Data interface{} `json:"data"` - Err error `json:"err"` -} - -func (r *IntegrityCheckResult) UnmarshalJSON(b []byte) error { - var data map[string]interface{} - if err := json.Unmarshal(b, &data); err != nil { - return err - } - if d, ok := data["data"]; ok && d != nil { - var rdata RelationalIntegrityCheckData - m := d.(map[string]interface{}) - rdata.ParentName = m["parent_name"].(string) - rdata.ChildName = m["child_name"].(string) - rdata.ParentIdAttr = m["parent_id_attr"].(string) - rdata.ChildIdAttr = m["child_id_attr"].(string) - for _, recData := range m["records"].([]interface{}) { - var record OrphanedRecord - m := recData.(map[string]interface{}) - if val := m["parent_id"]; val != nil { - record.ParentId = NewString(val.(string)) - } - if val := m["child_id"]; val != nil { - record.ChildId = NewString(val.(string)) - } - rdata.Records = append(rdata.Records, record) - } - r.Data = rdata - } - if err, ok := data["err"]; ok && err != nil { - r.Err = errors.New(data["err"].(string)) - } - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/job.go b/vendor/github.com/mattermost/mattermost-server/v5/model/job.go deleted file mode 100644 index 78d5a4ff..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/job.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" - "time" -) - -const ( - JOB_TYPE_DATA_RETENTION = "data_retention" - JOB_TYPE_MESSAGE_EXPORT = "message_export" - JOB_TYPE_ELASTICSEARCH_POST_INDEXING = "elasticsearch_post_indexing" - JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION = "elasticsearch_post_aggregation" - JOB_TYPE_BLEVE_POST_INDEXING = "bleve_post_indexing" - JOB_TYPE_LDAP_SYNC = "ldap_sync" - JOB_TYPE_MIGRATIONS = "migrations" - JOB_TYPE_PLUGINS = "plugins" - JOB_TYPE_EXPIRY_NOTIFY = "expiry_notify" - JOB_TYPE_PRODUCT_NOTICES = "product_notices" - JOB_TYPE_ACTIVE_USERS = "active_users" - JOB_TYPE_IMPORT_PROCESS = "import_process" - JOB_TYPE_IMPORT_DELETE = "import_delete" - JOB_TYPE_EXPORT_PROCESS = "export_process" - JOB_TYPE_EXPORT_DELETE = "export_delete" - JOB_TYPE_CLOUD = "cloud" - JOB_TYPE_RESEND_INVITATION_EMAIL = "resend_invitation_email" - - JOB_STATUS_PENDING = "pending" - JOB_STATUS_IN_PROGRESS = "in_progress" - JOB_STATUS_SUCCESS = "success" - JOB_STATUS_ERROR = "error" - JOB_STATUS_CANCEL_REQUESTED = "cancel_requested" - JOB_STATUS_CANCELED = "canceled" - JOB_STATUS_WARNING = "warning" -) - -var ALL_JOB_TYPES = [...]string{ - JOB_TYPE_DATA_RETENTION, - JOB_TYPE_MESSAGE_EXPORT, - JOB_TYPE_ELASTICSEARCH_POST_INDEXING, - JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION, - JOB_TYPE_BLEVE_POST_INDEXING, - JOB_TYPE_LDAP_SYNC, - JOB_TYPE_MIGRATIONS, - JOB_TYPE_PLUGINS, - JOB_TYPE_EXPIRY_NOTIFY, - JOB_TYPE_PRODUCT_NOTICES, - JOB_TYPE_ACTIVE_USERS, - JOB_TYPE_IMPORT_PROCESS, - JOB_TYPE_IMPORT_DELETE, - JOB_TYPE_EXPORT_PROCESS, - JOB_TYPE_EXPORT_DELETE, - JOB_TYPE_CLOUD, -} - -type Job struct { - Id string `json:"id"` - Type string `json:"type"` - Priority int64 `json:"priority"` - CreateAt int64 `json:"create_at"` - StartAt int64 `json:"start_at"` - LastActivityAt int64 `json:"last_activity_at"` - Status string `json:"status"` - Progress int64 `json:"progress"` - Data map[string]string `json:"data"` -} - -func (j *Job) IsValid() *AppError { - if !IsValidId(j.Id) { - return NewAppError("Job.IsValid", "model.job.is_valid.id.app_error", nil, "id="+j.Id, http.StatusBadRequest) - } - - if j.CreateAt == 0 { - return NewAppError("Job.IsValid", "model.job.is_valid.create_at.app_error", nil, "id="+j.Id, http.StatusBadRequest) - } - - switch j.Type { - case JOB_TYPE_DATA_RETENTION: - case JOB_TYPE_ELASTICSEARCH_POST_INDEXING: - case JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION: - case JOB_TYPE_BLEVE_POST_INDEXING: - case JOB_TYPE_LDAP_SYNC: - case JOB_TYPE_MESSAGE_EXPORT: - case JOB_TYPE_MIGRATIONS: - case JOB_TYPE_PLUGINS: - case JOB_TYPE_PRODUCT_NOTICES: - case JOB_TYPE_EXPIRY_NOTIFY: - case JOB_TYPE_ACTIVE_USERS: - case JOB_TYPE_IMPORT_PROCESS: - case JOB_TYPE_IMPORT_DELETE: - case JOB_TYPE_EXPORT_PROCESS: - case JOB_TYPE_EXPORT_DELETE: - case JOB_TYPE_CLOUD: - case JOB_TYPE_RESEND_INVITATION_EMAIL: - default: - return NewAppError("Job.IsValid", "model.job.is_valid.type.app_error", nil, "id="+j.Id, http.StatusBadRequest) - } - - switch j.Status { - case JOB_STATUS_PENDING: - case JOB_STATUS_IN_PROGRESS: - case JOB_STATUS_SUCCESS: - case JOB_STATUS_ERROR: - case JOB_STATUS_CANCEL_REQUESTED: - case JOB_STATUS_CANCELED: - default: - return NewAppError("Job.IsValid", "model.job.is_valid.status.app_error", nil, "id="+j.Id, http.StatusBadRequest) - } - - return nil -} - -func (j *Job) ToJson() string { - b, _ := json.Marshal(j) - return string(b) -} - -func JobFromJson(data io.Reader) *Job { - var job Job - if err := json.NewDecoder(data).Decode(&job); err == nil { - return &job - } - return nil -} - -func JobsToJson(jobs []*Job) string { - b, _ := json.Marshal(jobs) - return string(b) -} - -func JobsFromJson(data io.Reader) []*Job { - var jobs []*Job - if err := json.NewDecoder(data).Decode(&jobs); err == nil { - return jobs - } - return nil -} - -func (j *Job) DataToJson() string { - b, _ := json.Marshal(j.Data) - return string(b) -} - -type Worker interface { - Run() - Stop() - JobChannel() chan<- Job -} - -type Scheduler interface { - Name() string - JobType() string - Enabled(cfg *Config) bool - NextScheduleTime(cfg *Config, now time.Time, pendingJobs bool, lastSuccessfulJob *Job) *time.Time - ScheduleJob(cfg *Config, pendingJobs bool, lastSuccessfulJob *Job) (*Job, *AppError) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/ldap.go b/vendor/github.com/mattermost/mattermost-server/v5/model/ldap.go deleted file mode 100644 index 1262dfb8..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/ldap.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -const ( - USER_AUTH_SERVICE_LDAP = "ldap" - LDAP_PUBLIC_CERTIFICATE_NAME = "ldap-public.crt" - LDAP_PRIVATE_KEY_NAME = "ldap-private.key" -) diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/license.go b/vendor/github.com/mattermost/mattermost-server/v5/model/license.go deleted file mode 100644 index ab9e481a..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/license.go +++ /dev/null @@ -1,350 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "time" -) - -const ( - EXPIRED_LICENSE_ERROR = "api.license.add_license.expired.app_error" - INVALID_LICENSE_ERROR = "api.license.add_license.invalid.app_error" - LICENSE_GRACE_PERIOD = 1000 * 60 * 60 * 24 * 10 //10 days - LICENSE_RENEWAL_LINK = "https://mattermost.com/renew/" -) - -const ( - SIXTY_DAYS = 60 - FIFTY_EIGHT = 58 - LICENSE_UP_FOR_RENEWAL_EMAIL_SENT = "LicenseUpForRenewalEmailSent" -) - -var ( - trialDuration = 30*(time.Hour*24) + (time.Hour * 8) // 720 hours (30 days) + 8 hours is trial license duration - adminTrialDuration = 30*(time.Hour*24) + (time.Hour * 23) + (time.Minute * 59) + (time.Second * 59) // 720 hours (30 days) + 23 hours, 59 mins and 59 seconds - - // a sanctioned trial's duration is either more than the upper bound, - // or less than the lower bound - sanctionedTrialDurationLowerBound = 31*(time.Hour*24) + (time.Hour * 23) + (time.Minute * 59) + (time.Second * 59) // 744 hours (31 days) + 23 hours, 59 mins and 59 seconds - sanctionedTrialDurationUpperBound = 29*(time.Hour*24) + (time.Hour * 23) + (time.Minute * 59) + (time.Second * 59) // 696 hours (29 days) + 23 hours, 59 mins and 59 seconds -) - -type LicenseRecord struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at"` - Bytes string `json:"-"` -} - -type License struct { - Id string `json:"id"` - IssuedAt int64 `json:"issued_at"` - StartsAt int64 `json:"starts_at"` - ExpiresAt int64 `json:"expires_at"` - Customer *Customer `json:"customer"` - Features *Features `json:"features"` - SkuName string `json:"sku_name"` - SkuShortName string `json:"sku_short_name"` - IsTrial bool `json:"is_trial"` -} - -type Customer struct { - Id string `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - Company string `json:"company"` -} - -type TrialLicenseRequest struct { - ServerID string `json:"server_id"` - Email string `json:"email"` - Name string `json:"name"` - SiteURL string `json:"site_url"` - SiteName string `json:"site_name"` - Users int `json:"users"` - TermsAccepted bool `json:"terms_accepted"` - ReceiveEmailsAccepted bool `json:"receive_emails_accepted"` -} - -func (tlr *TrialLicenseRequest) ToJson() string { - b, _ := json.Marshal(tlr) - return string(b) -} - -type Features struct { - Users *int `json:"users"` - LDAP *bool `json:"ldap"` - LDAPGroups *bool `json:"ldap_groups"` - MFA *bool `json:"mfa"` - GoogleOAuth *bool `json:"google_oauth"` - Office365OAuth *bool `json:"office365_oauth"` - OpenId *bool `json:"openid"` - Compliance *bool `json:"compliance"` - Cluster *bool `json:"cluster"` - Metrics *bool `json:"metrics"` - MHPNS *bool `json:"mhpns"` - SAML *bool `json:"saml"` - Elasticsearch *bool `json:"elastic_search"` - Announcement *bool `json:"announcement"` - ThemeManagement *bool `json:"theme_management"` - EmailNotificationContents *bool `json:"email_notification_contents"` - DataRetention *bool `json:"data_retention"` - MessageExport *bool `json:"message_export"` - CustomPermissionsSchemes *bool `json:"custom_permissions_schemes"` - CustomTermsOfService *bool `json:"custom_terms_of_service"` - GuestAccounts *bool `json:"guest_accounts"` - GuestAccountsPermissions *bool `json:"guest_accounts_permissions"` - IDLoadedPushNotifications *bool `json:"id_loaded"` - LockTeammateNameDisplay *bool `json:"lock_teammate_name_display"` - EnterprisePlugins *bool `json:"enterprise_plugins"` - AdvancedLogging *bool `json:"advanced_logging"` - Cloud *bool `json:"cloud"` - SharedChannels *bool `json:"shared_channels"` - RemoteClusterService *bool `json:"remote_cluster_service"` - - // after we enabled more features we'll need to control them with this - FutureFeatures *bool `json:"future_features"` -} - -func (f *Features) ToMap() map[string]interface{} { - return map[string]interface{}{ - "ldap": *f.LDAP, - "ldap_groups": *f.LDAPGroups, - "mfa": *f.MFA, - "google": *f.GoogleOAuth, - "office365": *f.Office365OAuth, - "openid": *f.OpenId, - "compliance": *f.Compliance, - "cluster": *f.Cluster, - "metrics": *f.Metrics, - "mhpns": *f.MHPNS, - "saml": *f.SAML, - "elastic_search": *f.Elasticsearch, - "email_notification_contents": *f.EmailNotificationContents, - "data_retention": *f.DataRetention, - "message_export": *f.MessageExport, - "custom_permissions_schemes": *f.CustomPermissionsSchemes, - "guest_accounts": *f.GuestAccounts, - "guest_accounts_permissions": *f.GuestAccountsPermissions, - "id_loaded": *f.IDLoadedPushNotifications, - "lock_teammate_name_display": *f.LockTeammateNameDisplay, - "enterprise_plugins": *f.EnterprisePlugins, - "advanced_logging": *f.AdvancedLogging, - "cloud": *f.Cloud, - "shared_channels": *f.SharedChannels, - "remote_cluster_service": *f.RemoteClusterService, - "future": *f.FutureFeatures, - } -} - -func (f *Features) SetDefaults() { - if f.FutureFeatures == nil { - f.FutureFeatures = NewBool(true) - } - - if f.Users == nil { - f.Users = NewInt(0) - } - - if f.LDAP == nil { - f.LDAP = NewBool(*f.FutureFeatures) - } - - if f.LDAPGroups == nil { - f.LDAPGroups = NewBool(*f.FutureFeatures) - } - - if f.MFA == nil { - f.MFA = NewBool(*f.FutureFeatures) - } - - if f.GoogleOAuth == nil { - f.GoogleOAuth = NewBool(*f.FutureFeatures) - } - - if f.Office365OAuth == nil { - f.Office365OAuth = NewBool(*f.FutureFeatures) - } - - if f.OpenId == nil { - f.OpenId = NewBool(*f.FutureFeatures) - } - - if f.Compliance == nil { - f.Compliance = NewBool(*f.FutureFeatures) - } - - if f.Cluster == nil { - f.Cluster = NewBool(*f.FutureFeatures) - } - - if f.Metrics == nil { - f.Metrics = NewBool(*f.FutureFeatures) - } - - if f.MHPNS == nil { - f.MHPNS = NewBool(*f.FutureFeatures) - } - - if f.SAML == nil { - f.SAML = NewBool(*f.FutureFeatures) - } - - if f.Elasticsearch == nil { - f.Elasticsearch = NewBool(*f.FutureFeatures) - } - - if f.Announcement == nil { - f.Announcement = NewBool(true) - } - - if f.ThemeManagement == nil { - f.ThemeManagement = NewBool(true) - } - - if f.EmailNotificationContents == nil { - f.EmailNotificationContents = NewBool(*f.FutureFeatures) - } - - if f.DataRetention == nil { - f.DataRetention = NewBool(*f.FutureFeatures) - } - - if f.MessageExport == nil { - f.MessageExport = NewBool(*f.FutureFeatures) - } - - if f.CustomPermissionsSchemes == nil { - f.CustomPermissionsSchemes = NewBool(*f.FutureFeatures) - } - - if f.GuestAccounts == nil { - f.GuestAccounts = NewBool(*f.FutureFeatures) - } - - if f.GuestAccountsPermissions == nil { - f.GuestAccountsPermissions = NewBool(*f.FutureFeatures) - } - - if f.CustomTermsOfService == nil { - f.CustomTermsOfService = NewBool(*f.FutureFeatures) - } - - if f.IDLoadedPushNotifications == nil { - f.IDLoadedPushNotifications = NewBool(*f.FutureFeatures) - } - - if f.LockTeammateNameDisplay == nil { - f.LockTeammateNameDisplay = NewBool(*f.FutureFeatures) - } - - if f.EnterprisePlugins == nil { - f.EnterprisePlugins = NewBool(*f.FutureFeatures) - } - - if f.AdvancedLogging == nil { - f.AdvancedLogging = NewBool(*f.FutureFeatures) - } - - if f.Cloud == nil { - f.Cloud = NewBool(false) - } - - if f.SharedChannels == nil { - f.SharedChannels = NewBool(*f.FutureFeatures) - } - - if f.RemoteClusterService == nil { - f.RemoteClusterService = NewBool(*f.FutureFeatures) - } -} - -func (l *License) IsExpired() bool { - return l.ExpiresAt < GetMillis() -} - -func (l *License) IsPastGracePeriod() bool { - timeDiff := GetMillis() - l.ExpiresAt - return timeDiff > LICENSE_GRACE_PERIOD -} - -func (l *License) IsWithinExpirationPeriod() bool { - days := l.DaysToExpiration() - return days <= SIXTY_DAYS && days >= FIFTY_EIGHT -} - -func (l *License) DaysToExpiration() int { - dif := l.ExpiresAt - GetMillis() - d, _ := time.ParseDuration(fmt.Sprint(dif) + "ms") - days := d.Hours() / 24 - return int(days) -} - -func (l *License) IsStarted() bool { - return l.StartsAt < GetMillis() -} - -func (l *License) ToJson() string { - b, _ := json.Marshal(l) - return string(b) -} - -func (l *License) IsTrialLicense() bool { - return l.IsTrial || (l.ExpiresAt-l.StartsAt) == trialDuration.Milliseconds() || (l.ExpiresAt-l.StartsAt) == adminTrialDuration.Milliseconds() -} - -func (l *License) IsSanctionedTrial() bool { - duration := l.ExpiresAt - l.StartsAt - - return l.IsTrialLicense() && - (duration >= sanctionedTrialDurationLowerBound.Milliseconds() || duration <= sanctionedTrialDurationUpperBound.Milliseconds()) -} - -// NewTestLicense returns a license that expires in the future and has the given features. -func NewTestLicense(features ...string) *License { - ret := &License{ - ExpiresAt: GetMillis() + 90*24*60*60*1000, - Customer: &Customer{}, - Features: &Features{}, - } - ret.Features.SetDefaults() - - featureMap := map[string]bool{} - for _, feature := range features { - featureMap[feature] = true - } - featureJson, _ := json.Marshal(featureMap) - json.Unmarshal(featureJson, &ret.Features) - - return ret -} - -func LicenseFromJson(data io.Reader) *License { - var o *License - json.NewDecoder(data).Decode(&o) - return o -} - -func (lr *LicenseRecord) IsValid() *AppError { - if !IsValidId(lr.Id) { - return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.id.app_error", nil, "", http.StatusBadRequest) - } - - if lr.CreateAt == 0 { - return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) - } - - if lr.Bytes == "" || len(lr.Bytes) > 10000 { - return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (lr *LicenseRecord) PreSave() { - lr.CreateAt = GetMillis() -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/link_metadata.go b/vendor/github.com/mattermost/mattermost-server/v5/model/link_metadata.go deleted file mode 100644 index 6c3e0bd8..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/link_metadata.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/binary" - "encoding/json" - "fmt" - "hash/fnv" - "net/http" - "time" - "unicode/utf8" - - "github.com/dyatlov/go-opengraph/opengraph" -) - -const ( - LINK_METADATA_TYPE_IMAGE LinkMetadataType = "image" - LINK_METADATA_TYPE_NONE LinkMetadataType = "none" - LINK_METADATA_TYPE_OPENGRAPH LinkMetadataType = "opengraph" - MAX_IMAGES int = 5 -) - -type LinkMetadataType string - -// LinkMetadata stores arbitrary data about a link posted in a message. This includes dimensions of linked images -// and OpenGraph metadata. -type LinkMetadata struct { - // Hash is a value computed from the URL and Timestamp for use as a primary key in the database. - Hash int64 - - URL string - Timestamp int64 - Type LinkMetadataType - - // Data is the actual metadata for the link. It should contain data of one of the following types: - // - *model.PostImage if the linked content is an image - // - *opengraph.OpenGraph if the linked content is an HTML document - // - nil if the linked content has no metadata - Data interface{} -} - -// truncateText ensure string is 300 chars, truncate and add ellipsis -// if it was bigger. -func truncateText(original string) string { - if utf8.RuneCountInString(original) > 300 { - return fmt.Sprintf("%.300s[...]", original) - } - return original -} - -func firstNImages(images []*opengraph.Image, maxImages int) []*opengraph.Image { - if maxImages < 0 { // dont break stuff, if it's weird, go for sane defaults - maxImages = MAX_IMAGES - } - numImages := len(images) - if numImages > maxImages { - return images[0:maxImages] - } - return images -} - -// TruncateOpenGraph ensure OpenGraph metadata doesn't grow too big by -// shortening strings, trimming fields and reducing the number of -// images. -func TruncateOpenGraph(ogdata *opengraph.OpenGraph) *opengraph.OpenGraph { - if ogdata != nil { - empty := &opengraph.OpenGraph{} - ogdata.Title = truncateText(ogdata.Title) - ogdata.Description = truncateText(ogdata.Description) - ogdata.SiteName = truncateText(ogdata.SiteName) - ogdata.Article = empty.Article - ogdata.Book = empty.Book - ogdata.Profile = empty.Profile - ogdata.Determiner = empty.Determiner - ogdata.Locale = empty.Locale - ogdata.LocalesAlternate = empty.LocalesAlternate - ogdata.Images = firstNImages(ogdata.Images, MAX_IMAGES) - ogdata.Audios = empty.Audios - ogdata.Videos = empty.Videos - } - return ogdata -} - -func (o *LinkMetadata) PreSave() { - o.Hash = GenerateLinkMetadataHash(o.URL, o.Timestamp) -} - -func (o *LinkMetadata) IsValid() *AppError { - if o.URL == "" { - return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.url.app_error", nil, "", http.StatusBadRequest) - } - - if o.Timestamp == 0 || !isRoundedToNearestHour(o.Timestamp) { - return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.timestamp.app_error", nil, "", http.StatusBadRequest) - } - - switch o.Type { - case LINK_METADATA_TYPE_IMAGE: - if o.Data == nil { - return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.data.app_error", nil, "", http.StatusBadRequest) - } - - if _, ok := o.Data.(*PostImage); !ok { - return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.data_type.app_error", nil, "", http.StatusBadRequest) - } - case LINK_METADATA_TYPE_NONE: - if o.Data != nil { - return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.data_type.app_error", nil, "", http.StatusBadRequest) - } - case LINK_METADATA_TYPE_OPENGRAPH: - if o.Data == nil { - return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.data.app_error", nil, "", http.StatusBadRequest) - } - - if _, ok := o.Data.(*opengraph.OpenGraph); !ok { - return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.data_type.app_error", nil, "", http.StatusBadRequest) - } - default: - return NewAppError("LinkMetadata.IsValid", "model.link_metadata.is_valid.type.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -// DeserializeDataToConcreteType converts o.Data from JSON into properly structured data. This is intended to be used -// after getting a LinkMetadata object that has been stored in the database. -func (o *LinkMetadata) DeserializeDataToConcreteType() error { - var b []byte - switch t := o.Data.(type) { - case []byte: - // MySQL uses a byte slice for JSON - b = t - case string: - // Postgres uses a string for JSON - b = []byte(t) - } - - if b == nil { - // Data doesn't need to be fixed - return nil - } - - var data interface{} - var err error - - switch o.Type { - case LINK_METADATA_TYPE_IMAGE: - image := &PostImage{} - - err = json.Unmarshal(b, &image) - - data = image - case LINK_METADATA_TYPE_OPENGRAPH: - og := &opengraph.OpenGraph{} - - json.Unmarshal(b, &og) - - data = og - } - - if err != nil { - return err - } - - o.Data = data - - return nil -} - -// FloorToNearestHour takes a timestamp (in milliseconds) and returns it rounded to the previous hour in UTC. -func FloorToNearestHour(ms int64) int64 { - t := time.Unix(0, ms*int64(1000*1000)).UTC() - - return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 0, 0, 0, time.UTC).UnixNano() / int64(time.Millisecond) -} - -// isRoundedToNearestHour returns true if the given timestamp (in milliseconds) has been rounded to the nearest hour in UTC. -func isRoundedToNearestHour(ms int64) bool { - return FloorToNearestHour(ms) == ms -} - -// GenerateLinkMetadataHash generates a unique hash for a given URL and timestamp for use as a database key. -func GenerateLinkMetadataHash(url string, timestamp int64) int64 { - hash := fnv.New32() - - // Note that we ignore write errors here because the Hash interface says that its Write will never return an error - binary.Write(hash, binary.LittleEndian, timestamp) - hash.Write([]byte(url)) - - return int64(hash.Sum32()) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/manifest.go b/vendor/github.com/mattermost/mattermost-server/v5/model/manifest.go deleted file mode 100644 index 3fba0890..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/manifest.go +++ /dev/null @@ -1,570 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - - "github.com/blang/semver" - "github.com/pkg/errors" - "gopkg.in/yaml.v2" -) - -type PluginOption struct { - // The display name for the option. - DisplayName string `json:"display_name" yaml:"display_name"` - - // The string value for the option. - Value string `json:"value" yaml:"value"` -} - -type PluginSettingType int - -const ( - Bool PluginSettingType = iota - Dropdown - Generated - Radio - Text - LongText - Number - Username - Custom -) - -type PluginSetting struct { - // The key that the setting will be assigned to in the configuration file. - Key string `json:"key" yaml:"key"` - - // The display name for the setting. - DisplayName string `json:"display_name" yaml:"display_name"` - - // The type of the setting. - // - // "bool" will result in a boolean true or false setting. - // - // "dropdown" will result in a string setting that allows the user to select from a list of - // pre-defined options. - // - // "generated" will result in a string setting that is set to a random, cryptographically secure - // string. - // - // "radio" will result in a string setting that allows the user to select from a short selection - // of pre-defined options. - // - // "text" will result in a string setting that can be typed in manually. - // - // "longtext" will result in a multi line string that can be typed in manually. - // - // "number" will result in in integer setting that can be typed in manually. - // - // "username" will result in a text setting that will autocomplete to a username. - // - // "custom" will result in a custom defined setting and will load the custom component registered for the Web App System Console. - Type string `json:"type" yaml:"type"` - - // The help text to display to the user. Supports Markdown formatting. - HelpText string `json:"help_text" yaml:"help_text"` - - // The help text to display alongside the "Regenerate" button for settings of the "generated" type. - RegenerateHelpText string `json:"regenerate_help_text,omitempty" yaml:"regenerate_help_text,omitempty"` - - // The placeholder to display for "generated", "text", "longtext", "number" and "username" types when blank. - Placeholder string `json:"placeholder" yaml:"placeholder"` - - // The default value of the setting. - Default interface{} `json:"default" yaml:"default"` - - // For "radio" or "dropdown" settings, this is the list of pre-defined options that the user can choose - // from. - Options []*PluginOption `json:"options,omitempty" yaml:"options,omitempty"` -} - -type PluginSettingsSchema struct { - // Optional text to display above the settings. Supports Markdown formatting. - Header string `json:"header" yaml:"header"` - - // Optional text to display below the settings. Supports Markdown formatting. - Footer string `json:"footer" yaml:"footer"` - - // A list of setting definitions. - Settings []*PluginSetting `json:"settings" yaml:"settings"` -} - -// The plugin manifest defines the metadata required to load and present your plugin. The manifest -// file should be named plugin.json or plugin.yaml and placed in the top of your -// plugin bundle. -// -// Example plugin.json: -// -// -// { -// "id": "com.mycompany.myplugin", -// "name": "My Plugin", -// "description": "This is my plugin", -// "homepage_url": "https://example.com", -// "support_url": "https://example.com/support", -// "release_notes_url": "https://example.com/releases/v0.0.1", -// "icon_path": "assets/logo.svg", -// "version": "0.1.0", -// "min_server_version": "5.6.0", -// "server": { -// "executables": { -// "linux-amd64": "server/dist/plugin-linux-amd64", -// "darwin-amd64": "server/dist/plugin-darwin-amd64", -// "windows-amd64": "server/dist/plugin-windows-amd64.exe" -// } -// }, -// "webapp": { -// "bundle_path": "webapp/dist/main.js" -// }, -// "settings_schema": { -// "header": "Some header text", -// "footer": "Some footer text", -// "settings": [{ -// "key": "someKey", -// "display_name": "Enable Extra Feature", -// "type": "bool", -// "help_text": "When true, an extra feature will be enabled!", -// "default": "false" -// }] -// }, -// "props": { -// "someKey": "someData" -// } -// } -type Manifest struct { - // The id is a globally unique identifier that represents your plugin. Ids must be at least - // 3 characters, at most 190 characters and must match ^[a-zA-Z0-9-_\.]+$. - // Reverse-DNS notation using a name you control is a good option, e.g. "com.mycompany.myplugin". - Id string `json:"id" yaml:"id"` - - // The name to be displayed for the plugin. - Name string `json:"name" yaml:"name"` - - // A description of what your plugin is and does. - Description string `json:"description,omitempty" yaml:"description,omitempty"` - - // HomepageURL is an optional link to learn more about the plugin. - HomepageURL string `json:"homepage_url,omitempty" yaml:"homepage_url,omitempty"` - - // SupportURL is an optional URL where plugin issues can be reported. - SupportURL string `json:"support_url,omitempty" yaml:"support_url,omitempty"` - - // ReleaseNotesURL is an optional URL where a changelog for the release can be found. - ReleaseNotesURL string `json:"release_notes_url,omitempty" yaml:"release_notes_url,omitempty"` - - // A relative file path in the bundle that points to the plugins svg icon for use with the Plugin Marketplace. - // This should be relative to the root of your bundle and the location of the manifest file. Bitmap image formats are not supported. - IconPath string `json:"icon_path,omitempty" yaml:"icon_path,omitempty"` - - // A version number for your plugin. Semantic versioning is recommended: http://semver.org - Version string `json:"version" yaml:"version"` - - // The minimum Mattermost server version required for your plugin. - // - // Minimum server version: 5.6 - MinServerVersion string `json:"min_server_version,omitempty" yaml:"min_server_version,omitempty"` - - // Server defines the server-side portion of your plugin. - Server *ManifestServer `json:"server,omitempty" yaml:"server,omitempty"` - - // Backend is a deprecated flag for defining the server-side portion of your plugin. Going forward, use Server instead. - Backend *ManifestServer `json:"backend,omitempty" yaml:"backend,omitempty"` - - // If your plugin extends the web app, you'll need to define webapp. - Webapp *ManifestWebapp `json:"webapp,omitempty" yaml:"webapp,omitempty"` - - // To allow administrators to configure your plugin via the Mattermost system console, you can - // provide your settings schema. - SettingsSchema *PluginSettingsSchema `json:"settings_schema,omitempty" yaml:"settings_schema,omitempty"` - - // Plugins can store any kind of data in Props to allow other plugins to use it. - Props map[string]interface{} `json:"props,omitempty" yaml:"props,omitempty"` - - // RequiredConfig defines any required server configuration fields for the plugin to function properly. - // - // Use the plugin helpers CheckRequiredServerConfiguration method to enforce this. - RequiredConfig *Config `json:"required_configuration,omitempty" yaml:"required_configuration,omitempty"` -} - -type ManifestServer struct { - // AllExecutables are the paths to your executable binaries, specifying multiple entry - // points for different platforms when bundled together in a single plugin. - AllExecutables map[string]string `json:"executables,omitempty" yaml:"executables,omitempty"` - - // Executables is a legacy field populated with a subset of supported platform executables. - // When unmarshalling, Executables is authoritative for the platform executable paths it - // contains, overriding any values in AllExecutables. When marshalling, AllExecutables - // is authoritative. - // - // Code duplication is avoided when (un)marshalling by leveraging type aliases in the - // various (Un)Marshal(JSON|YAML) methods, since aliases don't inherit the aliased type's - // methods. - // - // In v6.0, we should remove this field and rename AllExecutables back to Executables. - Executables *ManifestExecutables `json:"-" yaml:"-"` - - // Executable is the path to your executable binary. This should be relative to the root - // of your bundle and the location of the manifest file. - // - // On Windows, this file must have a ".exe" extension. - // - // If your plugin is compiled for multiple platforms, consider bundling them together - // and using the Executables field instead. - Executable string `json:"executable" yaml:"executable"` -} - -func (ms *ManifestServer) MarshalJSON() ([]byte, error) { - type auxManifestServer ManifestServer - - // Populate AllExecutables from Executables, if it exists. - if ms.Executables != nil { - if ms.AllExecutables == nil { - ms.AllExecutables = make(map[string]string) - } - - ms.AllExecutables["linux-amd64"] = ms.Executables.LinuxAmd64 - ms.AllExecutables["darwin-amd64"] = ms.Executables.DarwinAmd64 - ms.AllExecutables["windows-amd64"] = ms.Executables.WindowsAmd64 - } - - return json.Marshal((*auxManifestServer)(ms)) -} - -func (ms *ManifestServer) UnmarshalJSON(data []byte) error { - type auxManifestServer ManifestServer - - aux := (*auxManifestServer)(ms) - if err := json.Unmarshal(data, aux); err != nil { - return err - } - - if len(aux.AllExecutables) > 0 { - ms.Executables = &ManifestExecutables{ - LinuxAmd64: aux.AllExecutables["linux-amd64"], - DarwinAmd64: aux.AllExecutables["darwin-amd64"], - WindowsAmd64: aux.AllExecutables["windows-amd64"], - } - } - - return nil -} - -func (ms *ManifestServer) MarshalYAML() ([]byte, error) { - type auxManifestServer ManifestServer - - // Populate AllExecutables from Executables, if it exists. - if ms.Executables != nil { - if ms.AllExecutables == nil { - ms.AllExecutables = make(map[string]string) - } - - ms.AllExecutables["linux-amd64"] = ms.Executables.LinuxAmd64 - ms.AllExecutables["darwin-amd64"] = ms.Executables.DarwinAmd64 - ms.AllExecutables["windows-amd64"] = ms.Executables.WindowsAmd64 - } - - return yaml.Marshal((*auxManifestServer)(ms)) -} - -func (ms *ManifestServer) UnmarshalYAML(unmarshal func(interface{}) error) error { - type auxManifestServer ManifestServer - - aux := (*auxManifestServer)(ms) - if err := unmarshal(&aux); err != nil { - return err - } - - if len(aux.AllExecutables) > 0 { - ms.Executables = &ManifestExecutables{ - LinuxAmd64: aux.AllExecutables["linux-amd64"], - DarwinAmd64: aux.AllExecutables["darwin-amd64"], - WindowsAmd64: aux.AllExecutables["windows-amd64"], - } - } - - return nil -} - -// ManifestExecutables is a legacy structure capturing a subet of the known platform executables. -type ManifestExecutables struct { - // LinuxAmd64 is the path to your executable binary for the corresponding platform - LinuxAmd64 string `json:"linux-amd64,omitempty" yaml:"linux-amd64,omitempty"` - // DarwinAmd64 is the path to your executable binary for the corresponding platform - DarwinAmd64 string `json:"darwin-amd64,omitempty" yaml:"darwin-amd64,omitempty"` - // WindowsAmd64 is the path to your executable binary for the corresponding platform - // This file must have a ".exe" extension - WindowsAmd64 string `json:"windows-amd64,omitempty" yaml:"windows-amd64,omitempty"` -} - -type ManifestWebapp struct { - // The path to your webapp bundle. This should be relative to the root of your bundle and the - // location of the manifest file. - BundlePath string `json:"bundle_path" yaml:"bundle_path"` - - // BundleHash is the 64-bit FNV-1a hash of the webapp bundle, computed when the plugin is loaded - BundleHash []byte `json:"-"` -} - -func (m *Manifest) ToJson() string { - b, _ := json.Marshal(m) - return string(b) -} - -func ManifestListToJson(m []*Manifest) string { - b, _ := json.Marshal(m) - return string(b) -} - -func ManifestFromJson(data io.Reader) *Manifest { - var m *Manifest - json.NewDecoder(data).Decode(&m) - return m -} - -func ManifestListFromJson(data io.Reader) []*Manifest { - var manifests []*Manifest - json.NewDecoder(data).Decode(&manifests) - return manifests -} - -func (m *Manifest) HasClient() bool { - return m.Webapp != nil -} - -func (m *Manifest) ClientManifest() *Manifest { - cm := new(Manifest) - *cm = *m - cm.Name = "" - cm.Description = "" - cm.Server = nil - if cm.Webapp != nil { - cm.Webapp = new(ManifestWebapp) - *cm.Webapp = *m.Webapp - cm.Webapp.BundlePath = "/static/" + m.Id + "/" + fmt.Sprintf("%s_%x_bundle.js", m.Id, m.Webapp.BundleHash) - } - return cm -} - -// GetExecutableForRuntime returns the path to the executable for the given runtime architecture. -// -// If the manifest defines multiple executables, but none match, or if only a single executable -// is defined, the Executable field will be returned. This method does not guarantee that the -// resulting binary can actually execute on the given platform. -func (m *Manifest) GetExecutableForRuntime(goOs, goArch string) string { - server := m.Server - - // Support the deprecated backend parameter. - if server == nil { - server = m.Backend - } - - if server == nil { - return "" - } - - var executable string - if len(server.AllExecutables) > 0 { - osArch := fmt.Sprintf("%s-%s", goOs, goArch) - executable = server.AllExecutables[osArch] - } - - if executable == "" { - executable = server.Executable - } - - return executable -} - -func (m *Manifest) HasServer() bool { - return m.Server != nil || m.Backend != nil -} - -func (m *Manifest) HasWebapp() bool { - return m.Webapp != nil -} - -func (m *Manifest) MeetMinServerVersion(serverVersion string) (bool, error) { - minServerVersion, err := semver.Parse(m.MinServerVersion) - if err != nil { - return false, errors.New("failed to parse MinServerVersion") - } - sv := semver.MustParse(serverVersion) - if sv.LT(minServerVersion) { - return false, nil - } - return true, nil -} - -func (m *Manifest) IsValid() error { - if !IsValidPluginId(m.Id) { - return errors.New("invalid plugin ID") - } - - if strings.TrimSpace(m.Name) == "" { - return errors.New("a plugin name is needed") - } - - if m.HomepageURL != "" && !IsValidHttpUrl(m.HomepageURL) { - return errors.New("invalid HomepageURL") - } - - if m.SupportURL != "" && !IsValidHttpUrl(m.SupportURL) { - return errors.New("invalid SupportURL") - } - - if m.ReleaseNotesURL != "" && !IsValidHttpUrl(m.ReleaseNotesURL) { - return errors.New("invalid ReleaseNotesURL") - } - - if m.Version != "" { - _, err := semver.Parse(m.Version) - if err != nil { - return errors.Wrap(err, "failed to parse Version") - } - } - - if m.MinServerVersion != "" { - _, err := semver.Parse(m.MinServerVersion) - if err != nil { - return errors.Wrap(err, "failed to parse MinServerVersion") - } - } - - if m.SettingsSchema != nil { - err := m.SettingsSchema.isValid() - if err != nil { - return errors.Wrap(err, "invalid settings schema") - } - } - - return nil -} - -func (s *PluginSettingsSchema) isValid() error { - for _, setting := range s.Settings { - err := setting.isValid() - if err != nil { - return err - } - } - - return nil -} - -func (s *PluginSetting) isValid() error { - pluginSettingType, err := convertTypeToPluginSettingType(s.Type) - if err != nil { - return err - } - - if s.RegenerateHelpText != "" && pluginSettingType != Generated { - return errors.New("should not set RegenerateHelpText for setting type that is not generated") - } - - if s.Placeholder != "" && !(pluginSettingType == Generated || - pluginSettingType == Text || - pluginSettingType == LongText || - pluginSettingType == Number || - pluginSettingType == Username) { - return errors.New("should not set Placeholder for setting type not in text, generated or username") - } - - if s.Options != nil { - if pluginSettingType != Radio && pluginSettingType != Dropdown { - return errors.New("should not set Options for setting type not in radio or dropdown") - } - - for _, option := range s.Options { - if option.DisplayName == "" || option.Value == "" { - return errors.New("should not have empty Displayname or Value for any option") - } - } - } - - return nil -} - -func convertTypeToPluginSettingType(t string) (PluginSettingType, error) { - var settingType PluginSettingType - switch t { - case "bool": - return Bool, nil - case "dropdown": - return Dropdown, nil - case "generated": - return Generated, nil - case "radio": - return Radio, nil - case "text": - return Text, nil - case "number": - return Number, nil - case "longtext": - return LongText, nil - case "username": - return Username, nil - case "custom": - return Custom, nil - default: - return settingType, errors.New("invalid setting type: " + t) - } -} - -// FindManifest will find and parse the manifest in a given directory. -// -// In all cases other than a does-not-exist error, path is set to the path of the manifest file that was -// found. -// -// Manifests are JSON or YAML files named plugin.json, plugin.yaml, or plugin.yml. -func FindManifest(dir string) (manifest *Manifest, path string, err error) { - for _, name := range []string{"plugin.yml", "plugin.yaml"} { - path = filepath.Join(dir, name) - f, ferr := os.Open(path) - if ferr != nil { - if !os.IsNotExist(ferr) { - return nil, "", ferr - } - continue - } - b, ioerr := ioutil.ReadAll(f) - f.Close() - if ioerr != nil { - return nil, path, ioerr - } - var parsed Manifest - err = yaml.Unmarshal(b, &parsed) - if err != nil { - return nil, path, err - } - manifest = &parsed - manifest.Id = strings.ToLower(manifest.Id) - return manifest, path, nil - } - - path = filepath.Join(dir, "plugin.json") - f, ferr := os.Open(path) - if ferr != nil { - if os.IsNotExist(ferr) { - path = "" - } - return nil, path, ferr - } - defer f.Close() - var parsed Manifest - err = json.NewDecoder(f).Decode(&parsed) - if err != nil { - return nil, path, err - } - manifest = &parsed - manifest.Id = strings.ToLower(manifest.Id) - return manifest, path, nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/marketplace_plugin.go b/vendor/github.com/mattermost/mattermost-server/v5/model/marketplace_plugin.go deleted file mode 100644 index cad93dfb..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/marketplace_plugin.go +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "bytes" - "encoding/base64" - "encoding/json" - "io" - "net/url" - "strconv" - - "github.com/pkg/errors" -) - -// BaseMarketplacePlugin is a Mattermost plugin received from the Marketplace server. -type BaseMarketplacePlugin struct { - HomepageURL string `json:"homepage_url"` - IconData string `json:"icon_data"` - DownloadURL string `json:"download_url"` - ReleaseNotesURL string `json:"release_notes_url"` - Labels []MarketplaceLabel `json:"labels,omitempty"` - Hosting string `json:"hosting"` // Indicated if the plugin is limited to a certain hosting type - AuthorType string `json:"author_type"` // The maintainer of the plugin - ReleaseStage string `json:"release_stage"` // The stage in the software release cycle that the plugin is in - Enterprise bool `json:"enterprise"` // Indicated if the plugin is an enterprise plugin - Signature string `json:"signature"` // Signature represents a signature of a plugin saved in base64 encoding. - Manifest *Manifest `json:"manifest"` -} - -// MarketplaceLabel represents a label shown in the Marketplace UI. -type MarketplaceLabel struct { - Name string `json:"name"` - Description string `json:"description"` - URL string `json:"url"` - Color string `json:"color"` -} - -// MarketplacePlugin is a state aware Marketplace plugin. -type MarketplacePlugin struct { - *BaseMarketplacePlugin - InstalledVersion string `json:"installed_version"` -} - -// BaseMarketplacePluginsFromReader decodes a json-encoded list of plugins from the given io.Reader. -func BaseMarketplacePluginsFromReader(reader io.Reader) ([]*BaseMarketplacePlugin, error) { - plugins := []*BaseMarketplacePlugin{} - decoder := json.NewDecoder(reader) - - if err := decoder.Decode(&plugins); err != nil && err != io.EOF { - return nil, err - } - - return plugins, nil -} - -// MarketplacePluginsFromReader decodes a json-encoded list of plugins from the given io.Reader. -func MarketplacePluginsFromReader(reader io.Reader) ([]*MarketplacePlugin, error) { - plugins := []*MarketplacePlugin{} - decoder := json.NewDecoder(reader) - - if err := decoder.Decode(&plugins); err != nil && err != io.EOF { - return nil, err - } - - return plugins, nil -} - -// DecodeSignature Decodes signature and returns ReadSeeker. -func (plugin *BaseMarketplacePlugin) DecodeSignature() (io.ReadSeeker, error) { - signatureBytes, err := base64.StdEncoding.DecodeString(plugin.Signature) - if err != nil { - return nil, errors.Wrap(err, "Unable to decode base64 signature.") - } - return bytes.NewReader(signatureBytes), nil -} - -// MarketplacePluginFilter describes the parameters to request a list of plugins. -type MarketplacePluginFilter struct { - Page int - PerPage int - Filter string - ServerVersion string - BuildEnterpriseReady bool - EnterprisePlugins bool - Cloud bool - LocalOnly bool - Platform string - PluginId string - ReturnAllVersions bool -} - -// ApplyToURL modifies the given url to include query string parameters for the request. -func (filter *MarketplacePluginFilter) ApplyToURL(u *url.URL) { - q := u.Query() - q.Add("page", strconv.Itoa(filter.Page)) - if filter.PerPage > 0 { - q.Add("per_page", strconv.Itoa(filter.PerPage)) - } - q.Add("filter", filter.Filter) - q.Add("server_version", filter.ServerVersion) - q.Add("build_enterprise_ready", strconv.FormatBool(filter.BuildEnterpriseReady)) - q.Add("enterprise_plugins", strconv.FormatBool(filter.EnterprisePlugins)) - q.Add("cloud", strconv.FormatBool(filter.Cloud)) - q.Add("local_only", strconv.FormatBool(filter.LocalOnly)) - q.Add("platform", filter.Platform) - q.Add("plugin_id", filter.PluginId) - q.Add("return_all_versions", strconv.FormatBool(filter.ReturnAllVersions)) - u.RawQuery = q.Encode() -} - -// InstallMarketplacePluginRequest struct describes parameters of the requested plugin. -type InstallMarketplacePluginRequest struct { - Id string `json:"id"` - Version string `json:"version"` -} - -// PluginRequestFromReader decodes a json-encoded plugin request from the given io.Reader. -func PluginRequestFromReader(reader io.Reader) (*InstallMarketplacePluginRequest, error) { - var r *InstallMarketplacePluginRequest - err := json.NewDecoder(reader).Decode(&r) - if err != nil { - return nil, err - } - return r, nil -} - -// ToJson method will return json from plugin request. -func (r *InstallMarketplacePluginRequest) ToJson() (string, error) { - b, err := json.Marshal(r) - if err != nil { - return "", err - } - return string(b), nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/mention_map.go b/vendor/github.com/mattermost/mattermost-server/v5/model/mention_map.go deleted file mode 100644 index 2f3444dd..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/mention_map.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "fmt" - "net/url" -) - -type UserMentionMap map[string]string -type ChannelMentionMap map[string]string - -const ( - userMentionsKey = "user_mentions" - userMentionsIdsKey = "user_mentions_ids" - channelMentionsKey = "channel_mentions" - channelMentionsIdsKey = "channel_mentions_ids" -) - -func UserMentionMapFromURLValues(values url.Values) (UserMentionMap, error) { - return mentionsFromURLValues(values, userMentionsKey, userMentionsIdsKey) -} - -func (m UserMentionMap) ToURLValues() url.Values { - return mentionsToURLValues(m, userMentionsKey, userMentionsIdsKey) -} - -func ChannelMentionMapFromURLValues(values url.Values) (ChannelMentionMap, error) { - return mentionsFromURLValues(values, channelMentionsKey, channelMentionsIdsKey) -} - -func (m ChannelMentionMap) ToURLValues() url.Values { - return mentionsToURLValues(m, channelMentionsKey, channelMentionsIdsKey) -} - -func mentionsFromURLValues(values url.Values, mentionKey, idKey string) (map[string]string, error) { - mentions, mentionsOk := values[mentionKey] - ids, idsOk := values[idKey] - - if !mentionsOk && !idsOk { - return map[string]string{}, nil - } - - if !mentionsOk { - return nil, fmt.Errorf("%s key not found", mentionKey) - } - - if !idsOk { - return nil, fmt.Errorf("%s key not found", idKey) - } - - if len(mentions) != len(ids) { - return nil, fmt.Errorf("keys %s and %s have different length", mentionKey, idKey) - } - - mentionsMap := make(map[string]string) - for i, mention := range mentions { - id := ids[i] - - if oldId, ok := mentionsMap[mention]; ok && oldId != id { - return nil, fmt.Errorf("key %s has two different values: %s and %s", mention, oldId, id) - } - - mentionsMap[mention] = id - } - - return mentionsMap, nil -} - -func mentionsToURLValues(mentions map[string]string, mentionKey, idKey string) url.Values { - values := url.Values{} - - for mention, id := range mentions { - values.Add(mentionKey, mention) - values.Add(idKey, id) - } - - return values -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/message_export.go b/vendor/github.com/mattermost/mattermost-server/v5/model/message_export.go deleted file mode 100644 index f94d861f..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/message_export.go +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -type MessageExport struct { - TeamId *string - TeamName *string - TeamDisplayName *string - - ChannelId *string - ChannelName *string - ChannelDisplayName *string - ChannelType *string - - UserId *string - UserEmail *string - Username *string - IsBot bool - - PostId *string - PostCreateAt *int64 - PostUpdateAt *int64 - PostDeleteAt *int64 - PostMessage *string - PostType *string - PostRootId *string - PostProps *string - PostOriginalId *string - PostFileIds StringArray -} - -type MessageExportCursor struct { - LastPostUpdateAt int64 - LastPostId string -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/mfa_secret.go b/vendor/github.com/mattermost/mattermost-server/v5/model/mfa_secret.go deleted file mode 100644 index b2293566..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/mfa_secret.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type MfaSecret struct { - Secret string `json:"secret"` - QRCode string `json:"qr_code"` -} - -func (mfa *MfaSecret) ToJson() string { - b, _ := json.Marshal(mfa) - return string(b) -} - -func MfaSecretFromJson(data io.Reader) *MfaSecret { - var mfa *MfaSecret - json.NewDecoder(data).Decode(&mfa) - return mfa -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/migration.go b/vendor/github.com/mattermost/mattermost-server/v5/model/migration.go deleted file mode 100644 index 019ca7b5..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/migration.go +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -const ( - ADVANCED_PERMISSIONS_MIGRATION_KEY = "AdvancedPermissionsMigrationComplete" - MIGRATION_KEY_ADVANCED_PERMISSIONS_PHASE_2 = "migration_advanced_permissions_phase_2" - - MIGRATION_KEY_EMOJI_PERMISSIONS_SPLIT = "emoji_permissions_split" - MIGRATION_KEY_WEBHOOK_PERMISSIONS_SPLIT = "webhook_permissions_split" - MIGRATION_KEY_LIST_JOIN_PUBLIC_PRIVATE_TEAMS = "list_join_public_private_teams" - MIGRATION_KEY_REMOVE_PERMANENT_DELETE_USER = "remove_permanent_delete_user" - MIGRATION_KEY_ADD_BOT_PERMISSIONS = "add_bot_permissions" - MIGRATION_KEY_APPLY_CHANNEL_MANAGE_DELETE_TO_CHANNEL_USER = "apply_channel_manage_delete_to_channel_user" - MIGRATION_KEY_REMOVE_CHANNEL_MANAGE_DELETE_FROM_TEAM_USER = "remove_channel_manage_delete_from_team_user" - MIGRATION_KEY_VIEW_MEMBERS_NEW_PERMISSION = "view_members_new_permission" - MIGRATION_KEY_ADD_MANAGE_GUESTS_PERMISSIONS = "add_manage_guests_permissions" - MIGRATION_KEY_CHANNEL_MODERATIONS_PERMISSIONS = "channel_moderations_permissions" - MIGRATION_KEY_ADD_USE_GROUP_MENTIONS_PERMISSION = "add_use_group_mentions_permission" - MIGRATION_KEY_ADD_SYSTEM_CONSOLE_PERMISSIONS = "add_system_console_permissions" - MIGRATION_KEY_SIDEBAR_CATEGORIES_PHASE_2 = "migration_sidebar_categories_phase_2" - MIGRATION_KEY_ADD_CONVERT_CHANNEL_PERMISSIONS = "add_convert_channel_permissions" - MIGRATION_KEY_ADD_SYSTEM_ROLES_PERMISSIONS = "add_system_roles_permissions" - MIGRATION_KEY_ADD_BILLING_PERMISSIONS = "add_billing_permissions" - MIGRATION_KEY_ADD_MANAGE_SHARED_CHANNEL_PERMISSIONS = "manage_shared_channel_permissions" - MIGRATION_KEY_ADD_MANAGE_SECURE_CONNECTIONS_PERMISSIONS = "manage_secure_connections_permissions" - MIGRATION_KEY_ADD_DOWNLOAD_COMPLIANCE_EXPORT_RESULTS = "download_compliance_export_results" - MIGRATION_KEY_ADD_COMPLIANCE_SUBSECTION_PERMISSIONS = "compliance_subsection_permissions" - MIGRATION_KEY_ADD_EXPERIMENTAL_SUBSECTION_PERMISSIONS = "experimental_subsection_permissions" - MIGRATION_KEY_ADD_AUTHENTICATION_SUBSECTION_PERMISSIONS = "authentication_subsection_permissions" - MIGRATION_KEY_ADD_SITE_SUBSECTION_PERMISSIONS = "site_subsection_permissions" - MIGRATION_KEY_ADD_ENVIRONMENT_SUBSECTION_PERMISSIONS = "environment_subsection_permissions" - MIGRATION_KEY_ADD_REPORTING_SUBSECTION_PERMISSIONS = "reporting_subsection_permissions" - MIGRATION_KEY_ADD_TEST_EMAIL_ANCILLARY_PERMISSION = "test_email_ancillary_permission" - MIGRATION_KEY_ADD_ABOUT_SUBSECTION_PERMISSIONS = "about_subsection_permissions" - MIGRATION_KEY_ADD_INTEGRATIONS_SUBSECTION_PERMISSIONS = "integrations_subsection_permissions" -) diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/oauth.go b/vendor/github.com/mattermost/mattermost-server/v5/model/oauth.go deleted file mode 100644 index 07198116..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/oauth.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "unicode/utf8" -) - -const ( - OAUTH_ACTION_SIGNUP = "signup" - OAUTH_ACTION_LOGIN = "login" - OAUTH_ACTION_EMAIL_TO_SSO = "email_to_sso" - OAUTH_ACTION_SSO_TO_EMAIL = "sso_to_email" - OAUTH_ACTION_MOBILE = "mobile" -) - -type OAuthApp struct { - Id string `json:"id"` - CreatorId string `json:"creator_id"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - ClientSecret string `json:"client_secret"` - Name string `json:"name"` - Description string `json:"description"` - IconURL string `json:"icon_url"` - CallbackUrls StringArray `json:"callback_urls"` - Homepage string `json:"homepage"` - IsTrusted bool `json:"is_trusted"` -} - -// IsValid validates the app and returns an error if it isn't configured -// correctly. -func (a *OAuthApp) IsValid() *AppError { - - if !IsValidId(a.Id) { - return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.app_id.app_error", nil, "", http.StatusBadRequest) - } - - if a.CreateAt == 0 { - return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.create_at.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) - } - - if a.UpdateAt == 0 { - return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.update_at.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) - } - - if !IsValidId(a.CreatorId) { - return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.creator_id.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) - } - - if a.ClientSecret == "" || len(a.ClientSecret) > 128 { - return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.client_secret.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) - } - - if a.Name == "" || len(a.Name) > 64 { - return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.name.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) - } - - if len(a.CallbackUrls) == 0 || len(fmt.Sprintf("%s", a.CallbackUrls)) > 1024 { - return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) - } - - for _, callback := range a.CallbackUrls { - if !IsValidHttpUrl(callback) { - return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "", http.StatusBadRequest) - } - } - - if a.Homepage == "" || len(a.Homepage) > 256 || !IsValidHttpUrl(a.Homepage) { - return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.homepage.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) - } - - if utf8.RuneCountInString(a.Description) > 512 { - return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.description.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) - } - - if a.IconURL != "" { - if len(a.IconURL) > 512 || !IsValidHttpUrl(a.IconURL) { - return NewAppError("OAuthApp.IsValid", "model.oauth.is_valid.icon_url.app_error", nil, "app_id="+a.Id, http.StatusBadRequest) - } - } - - return nil -} - -// PreSave will set the Id and ClientSecret if missing. It will also fill -// in the CreateAt, UpdateAt times. It should be run before saving the app to the db. -func (a *OAuthApp) PreSave() { - if a.Id == "" { - a.Id = NewId() - } - - if a.ClientSecret == "" { - a.ClientSecret = NewId() - } - - a.CreateAt = GetMillis() - a.UpdateAt = a.CreateAt -} - -// PreUpdate should be run before updating the app in the db. -func (a *OAuthApp) PreUpdate() { - a.UpdateAt = GetMillis() -} - -func (a *OAuthApp) ToJson() string { - b, _ := json.Marshal(a) - return string(b) -} - -// Generate a valid strong etag so the browser can cache the results -func (a *OAuthApp) Etag() string { - return Etag(a.Id, a.UpdateAt) -} - -// Remove any private data from the app object -func (a *OAuthApp) Sanitize() { - a.ClientSecret = "" -} - -func (a *OAuthApp) IsValidRedirectURL(url string) bool { - for _, u := range a.CallbackUrls { - if u == url { - return true - } - } - - return false -} - -func OAuthAppFromJson(data io.Reader) *OAuthApp { - var app *OAuthApp - json.NewDecoder(data).Decode(&app) - return app -} - -func OAuthAppListToJson(l []*OAuthApp) string { - b, _ := json.Marshal(l) - return string(b) -} - -func OAuthAppListFromJson(data io.Reader) []*OAuthApp { - var o []*OAuthApp - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/outgoing_webhook.go b/vendor/github.com/mattermost/mattermost-server/v5/model/outgoing_webhook.go deleted file mode 100644 index 0d7a88fb..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/outgoing_webhook.go +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "net/url" - "strconv" - "strings" -) - -type OutgoingWebhook struct { - Id string `json:"id"` - Token string `json:"token"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - CreatorId string `json:"creator_id"` - ChannelId string `json:"channel_id"` - TeamId string `json:"team_id"` - TriggerWords StringArray `json:"trigger_words"` - TriggerWhen int `json:"trigger_when"` - CallbackURLs StringArray `json:"callback_urls"` - DisplayName string `json:"display_name"` - Description string `json:"description"` - ContentType string `json:"content_type"` - Username string `json:"username"` - IconURL string `json:"icon_url"` -} - -type OutgoingWebhookPayload struct { - Token string `json:"token"` - TeamId string `json:"team_id"` - TeamDomain string `json:"team_domain"` - ChannelId string `json:"channel_id"` - ChannelName string `json:"channel_name"` - Timestamp int64 `json:"timestamp"` - UserId string `json:"user_id"` - UserName string `json:"user_name"` - PostId string `json:"post_id"` - Text string `json:"text"` - TriggerWord string `json:"trigger_word"` - FileIds string `json:"file_ids"` -} - -type OutgoingWebhookResponse struct { - Text *string `json:"text"` - Username string `json:"username"` - IconURL string `json:"icon_url"` - Props StringInterface `json:"props"` - Attachments []*SlackAttachment `json:"attachments"` - Type string `json:"type"` - ResponseType string `json:"response_type"` -} - -const OUTGOING_HOOK_RESPONSE_TYPE_COMMENT = "comment" - -func (o *OutgoingWebhookPayload) ToJSON() string { - b, _ := json.Marshal(o) - return string(b) -} - -func (o *OutgoingWebhookPayload) ToFormValues() string { - v := url.Values{} - v.Set("token", o.Token) - v.Set("team_id", o.TeamId) - v.Set("team_domain", o.TeamDomain) - v.Set("channel_id", o.ChannelId) - v.Set("channel_name", o.ChannelName) - v.Set("timestamp", strconv.FormatInt(o.Timestamp/1000, 10)) - v.Set("user_id", o.UserId) - v.Set("user_name", o.UserName) - v.Set("post_id", o.PostId) - v.Set("text", o.Text) - v.Set("trigger_word", o.TriggerWord) - v.Set("file_ids", o.FileIds) - - return v.Encode() -} - -func (o *OutgoingWebhook) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func OutgoingWebhookFromJson(data io.Reader) *OutgoingWebhook { - var o *OutgoingWebhook - json.NewDecoder(data).Decode(&o) - return o -} - -func OutgoingWebhookListToJson(l []*OutgoingWebhook) string { - b, _ := json.Marshal(l) - return string(b) -} - -func OutgoingWebhookListFromJson(data io.Reader) []*OutgoingWebhook { - var o []*OutgoingWebhook - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *OutgoingWebhookResponse) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func OutgoingWebhookResponseFromJson(data io.Reader) (*OutgoingWebhookResponse, error) { - var o *OutgoingWebhookResponse - err := json.NewDecoder(data).Decode(&o) - if err == io.EOF { - return nil, nil - } - return o, err -} - -func (o *OutgoingWebhook) IsValid() *AppError { - - if !IsValidId(o.Id) { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.id.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.Token) != 26 { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.token.app_error", nil, "", http.StatusBadRequest) - } - - if o.CreateAt == 0 { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if o.UpdateAt == 0 { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if !IsValidId(o.CreatorId) { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) - } - - if o.ChannelId != "" && !IsValidId(o.ChannelId) { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidId(o.TeamId) { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.team_id.app_error", nil, "", http.StatusBadRequest) - } - - if len(fmt.Sprintf("%s", o.TriggerWords)) > 1024 { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.words.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.TriggerWords) != 0 { - for _, triggerWord := range o.TriggerWords { - if triggerWord == "" { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.trigger_words.app_error", nil, "", http.StatusBadRequest) - } - } - } - - if len(o.CallbackURLs) == 0 || len(fmt.Sprintf("%s", o.CallbackURLs)) > 1024 { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.callback.app_error", nil, "", http.StatusBadRequest) - } - - for _, callback := range o.CallbackURLs { - if !IsValidHttpUrl(callback) { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.url.app_error", nil, "", http.StatusBadRequest) - } - } - - if len(o.DisplayName) > 64 { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.display_name.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.Description) > 500 { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.description.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.ContentType) > 128 { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "", http.StatusBadRequest) - } - - if o.TriggerWhen > 1 { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.Username) > 64 { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.username.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.IconURL) > 1024 { - return NewAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.icon_url.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (o *OutgoingWebhook) PreSave() { - if o.Id == "" { - o.Id = NewId() - } - - if o.Token == "" { - o.Token = NewId() - } - - o.CreateAt = GetMillis() - o.UpdateAt = o.CreateAt -} - -func (o *OutgoingWebhook) PreUpdate() { - o.UpdateAt = GetMillis() -} - -func (o *OutgoingWebhook) TriggerWordExactMatch(word string) bool { - if word == "" { - return false - } - - for _, trigger := range o.TriggerWords { - if trigger == word { - return true - } - } - - return false -} - -func (o *OutgoingWebhook) TriggerWordStartsWith(word string) bool { - if word == "" { - return false - } - - for _, trigger := range o.TriggerWords { - if strings.HasPrefix(word, trigger) { - return true - } - } - - return false -} - -func (o *OutgoingWebhook) GetTriggerWord(word string, isExactMatch bool) (triggerWord string) { - if word == "" { - return - } - - if isExactMatch { - for _, trigger := range o.TriggerWords { - if trigger == word { - triggerWord = trigger - break - } - } - } else { - for _, trigger := range o.TriggerWords { - if strings.HasPrefix(word, trigger) { - triggerWord = trigger - break - } - } - } - - return triggerWord -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/permission.go b/vendor/github.com/mattermost/mattermost-server/v5/model/permission.go deleted file mode 100644 index bc4de236..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/permission.go +++ /dev/null @@ -1,2192 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -const ( - PermissionScopeSystem = "system_scope" - PermissionScopeTeam = "team_scope" - PermissionScopeChannel = "channel_scope" -) - -type Permission struct { - Id string `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Scope string `json:"scope"` -} - -var PERMISSION_INVITE_USER *Permission -var PERMISSION_ADD_USER_TO_TEAM *Permission -var PERMISSION_USE_SLASH_COMMANDS *Permission -var PERMISSION_MANAGE_SLASH_COMMANDS *Permission -var PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS *Permission -var PERMISSION_CREATE_PUBLIC_CHANNEL *Permission -var PERMISSION_CREATE_PRIVATE_CHANNEL *Permission -var PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS *Permission -var PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS *Permission -var PERMISSION_CONVERT_PUBLIC_CHANNEL_TO_PRIVATE *Permission -var PERMISSION_CONVERT_PRIVATE_CHANNEL_TO_PUBLIC *Permission -var PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE *Permission -var PERMISSION_MANAGE_ROLES *Permission -var PERMISSION_MANAGE_TEAM_ROLES *Permission -var PERMISSION_MANAGE_CHANNEL_ROLES *Permission -var PERMISSION_CREATE_DIRECT_CHANNEL *Permission -var PERMISSION_CREATE_GROUP_CHANNEL *Permission -var PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES *Permission -var PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES *Permission -var PERMISSION_LIST_PUBLIC_TEAMS *Permission -var PERMISSION_JOIN_PUBLIC_TEAMS *Permission -var PERMISSION_LIST_PRIVATE_TEAMS *Permission -var PERMISSION_JOIN_PRIVATE_TEAMS *Permission -var PERMISSION_LIST_TEAM_CHANNELS *Permission -var PERMISSION_JOIN_PUBLIC_CHANNELS *Permission -var PERMISSION_DELETE_PUBLIC_CHANNEL *Permission -var PERMISSION_DELETE_PRIVATE_CHANNEL *Permission -var PERMISSION_EDIT_OTHER_USERS *Permission -var PERMISSION_READ_CHANNEL *Permission -var PERMISSION_READ_PUBLIC_CHANNEL_GROUPS *Permission -var PERMISSION_READ_PRIVATE_CHANNEL_GROUPS *Permission -var PERMISSION_READ_PUBLIC_CHANNEL *Permission -var PERMISSION_ADD_REACTION *Permission -var PERMISSION_REMOVE_REACTION *Permission -var PERMISSION_REMOVE_OTHERS_REACTIONS *Permission -var PERMISSION_PERMANENT_DELETE_USER *Permission -var PERMISSION_UPLOAD_FILE *Permission -var PERMISSION_GET_PUBLIC_LINK *Permission -var PERMISSION_MANAGE_WEBHOOKS *Permission -var PERMISSION_MANAGE_OTHERS_WEBHOOKS *Permission -var PERMISSION_MANAGE_INCOMING_WEBHOOKS *Permission -var PERMISSION_MANAGE_OUTGOING_WEBHOOKS *Permission -var PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS *Permission -var PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS *Permission -var PERMISSION_MANAGE_OAUTH *Permission -var PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH *Permission -var PERMISSION_MANAGE_EMOJIS *Permission -var PERMISSION_MANAGE_OTHERS_EMOJIS *Permission -var PERMISSION_CREATE_EMOJIS *Permission -var PERMISSION_DELETE_EMOJIS *Permission -var PERMISSION_DELETE_OTHERS_EMOJIS *Permission -var PERMISSION_CREATE_POST *Permission -var PERMISSION_CREATE_POST_PUBLIC *Permission -var PERMISSION_CREATE_POST_EPHEMERAL *Permission -var PERMISSION_EDIT_POST *Permission -var PERMISSION_EDIT_OTHERS_POSTS *Permission -var PERMISSION_DELETE_POST *Permission -var PERMISSION_DELETE_OTHERS_POSTS *Permission -var PERMISSION_REMOVE_USER_FROM_TEAM *Permission -var PERMISSION_CREATE_TEAM *Permission -var PERMISSION_MANAGE_TEAM *Permission -var PERMISSION_IMPORT_TEAM *Permission -var PERMISSION_VIEW_TEAM *Permission -var PERMISSION_LIST_USERS_WITHOUT_TEAM *Permission -var PERMISSION_READ_JOBS *Permission -var PERMISSION_MANAGE_JOBS *Permission -var PERMISSION_CREATE_USER_ACCESS_TOKEN *Permission -var PERMISSION_READ_USER_ACCESS_TOKEN *Permission -var PERMISSION_REVOKE_USER_ACCESS_TOKEN *Permission -var PERMISSION_CREATE_BOT *Permission -var PERMISSION_ASSIGN_BOT *Permission -var PERMISSION_READ_BOTS *Permission -var PERMISSION_READ_OTHERS_BOTS *Permission -var PERMISSION_MANAGE_BOTS *Permission -var PERMISSION_MANAGE_OTHERS_BOTS *Permission -var PERMISSION_VIEW_MEMBERS *Permission -var PERMISSION_INVITE_GUEST *Permission -var PERMISSION_PROMOTE_GUEST *Permission -var PERMISSION_DEMOTE_TO_GUEST *Permission -var PERMISSION_USE_CHANNEL_MENTIONS *Permission -var PERMISSION_USE_GROUP_MENTIONS *Permission -var PERMISSION_READ_OTHER_USERS_TEAMS *Permission -var PERMISSION_EDIT_BRAND *Permission -var PERMISSION_MANAGE_SHARED_CHANNELS *Permission -var PERMISSION_MANAGE_SECURE_CONNECTIONS *Permission -var PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT *Permission -var PERMISSION_CREATE_DATA_RETENTION_JOB *Permission -var PERMISSION_READ_DATA_RETENTION_JOB *Permission -var PERMISSION_CREATE_COMPLIANCE_EXPORT_JOB *Permission -var PERMISSION_READ_COMPLIANCE_EXPORT_JOB *Permission -var PERMISSION_READ_AUDITS *Permission -var PERMISSION_TEST_ELASTICSEARCH *Permission -var PERMISSION_TEST_SITE_URL *Permission -var PERMISSION_TEST_S3 *Permission -var PERMISSION_RELOAD_CONFIG *Permission -var PERMISSION_INVALIDATE_CACHES *Permission -var PERMISSION_RECYCLE_DATABASE_CONNECTIONS *Permission -var PERMISSION_PURGE_ELASTICSEARCH_INDEXES *Permission -var PERMISSION_TEST_EMAIL *Permission -var PERMISSION_CREATE_ELASTICSEARCH_POST_INDEXING_JOB *Permission -var PERMISSION_CREATE_ELASTICSEARCH_POST_AGGREGATION_JOB *Permission -var PERMISSION_READ_ELASTICSEARCH_POST_INDEXING_JOB *Permission -var PERMISSION_READ_ELASTICSEARCH_POST_AGGREGATION_JOB *Permission -var PERMISSION_PURGE_BLEVE_INDEXES *Permission -var PERMISSION_CREATE_POST_BLEVE_INDEXES_JOB *Permission -var PERMISSION_CREATE_LDAP_SYNC_JOB *Permission -var PERMISSION_READ_LDAP_SYNC_JOB *Permission -var PERMISSION_TEST_LDAP *Permission -var PERMISSION_INVALIDATE_EMAIL_INVITE *Permission -var PERMISSION_GET_SAML_METADATA_FROM_IDP *Permission -var PERMISSION_ADD_SAML_PUBLIC_CERT *Permission -var PERMISSION_ADD_SAML_PRIVATE_CERT *Permission -var PERMISSION_ADD_SAML_IDP_CERT *Permission -var PERMISSION_REMOVE_SAML_PUBLIC_CERT *Permission -var PERMISSION_REMOVE_SAML_PRIVATE_CERT *Permission -var PERMISSION_REMOVE_SAML_IDP_CERT *Permission -var PERMISSION_GET_SAML_CERT_STATUS *Permission -var PERMISSION_ADD_LDAP_PUBLIC_CERT *Permission -var PERMISSION_ADD_LDAP_PRIVATE_CERT *Permission -var PERMISSION_REMOVE_LDAP_PUBLIC_CERT *Permission -var PERMISSION_REMOVE_LDAP_PRIVATE_CERT *Permission -var PERMISSION_GET_LOGS *Permission -var PERMISSION_GET_ANALYTICS *Permission -var PERMISSION_READ_LICENSE_INFORMATION *Permission -var PERMISSION_MANAGE_LICENSE_INFORMATION *Permission - -var PERMISSION_SYSCONSOLE_READ_ABOUT *Permission -var PERMISSION_SYSCONSOLE_WRITE_ABOUT *Permission - -var PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE *Permission -var PERMISSION_SYSCONSOLE_WRITE_ABOUT_EDITION_AND_LICENSE *Permission - -var PERMISSION_SYSCONSOLE_READ_BILLING *Permission -var PERMISSION_SYSCONSOLE_WRITE_BILLING *Permission - -var PERMISSION_SYSCONSOLE_READ_REPORTING *Permission -var PERMISSION_SYSCONSOLE_WRITE_REPORTING *Permission - -var PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS *Permission -var PERMISSION_SYSCONSOLE_WRITE_REPORTING_SITE_STATISTICS *Permission - -var PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS *Permission -var PERMISSION_SYSCONSOLE_WRITE_REPORTING_TEAM_STATISTICS *Permission - -var PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS *Permission -var PERMISSION_SYSCONSOLE_WRITE_REPORTING_SERVER_LOGS *Permission - -var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS *Permission -var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_USERS *Permission - -var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS *Permission -var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS *Permission - -var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS *Permission -var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS *Permission - -var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS *Permission -var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS *Permission - -var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS *Permission -var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS *Permission - -var PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_SYSTEM_ROLES *Permission -var PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_SYSTEM_ROLES *Permission - -// DEPRECATED -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT *Permission - -// DEPRECATED -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_WEB_SERVER *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_WEB_SERVER *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DATABASE *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DATABASE *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_ELASTICSEARCH *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_FILE_STORAGE *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_FILE_STORAGE *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_IMAGE_PROXY *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_IMAGE_PROXY *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SMTP *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SMTP *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PUSH_NOTIFICATION_SERVER *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PUSH_NOTIFICATION_SERVER *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_HIGH_AVAILABILITY *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_HIGH_AVAILABILITY *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_RATE_LIMITING *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_RATE_LIMITING *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_LOGGING *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_LOGGING *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SESSION_LENGTHS *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PERFORMANCE_MONITORING *Permission - -var PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER *Permission -var PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DEVELOPER *Permission - -var PERMISSION_SYSCONSOLE_READ_SITE *Permission -var PERMISSION_SYSCONSOLE_WRITE_SITE *Permission - -var PERMISSION_SYSCONSOLE_READ_SITE_CUSTOMIZATION *Permission -var PERMISSION_SYSCONSOLE_WRITE_SITE_CUSTOMIZATION *Permission - -var PERMISSION_SYSCONSOLE_READ_SITE_LOCALIZATION *Permission -var PERMISSION_SYSCONSOLE_WRITE_SITE_LOCALIZATION *Permission - -var PERMISSION_SYSCONSOLE_READ_SITE_USERS_AND_TEAMS *Permission -var PERMISSION_SYSCONSOLE_WRITE_SITE_USERS_AND_TEAMS *Permission - -var PERMISSION_SYSCONSOLE_READ_SITE_NOTIFICATIONS *Permission -var PERMISSION_SYSCONSOLE_WRITE_SITE_NOTIFICATIONS *Permission - -var PERMISSION_SYSCONSOLE_READ_SITE_ANNOUNCEMENT_BANNER *Permission -var PERMISSION_SYSCONSOLE_WRITE_SITE_ANNOUNCEMENT_BANNER *Permission - -var PERMISSION_SYSCONSOLE_READ_SITE_EMOJI *Permission -var PERMISSION_SYSCONSOLE_WRITE_SITE_EMOJI *Permission - -var PERMISSION_SYSCONSOLE_READ_SITE_POSTS *Permission -var PERMISSION_SYSCONSOLE_WRITE_SITE_POSTS *Permission - -var PERMISSION_SYSCONSOLE_READ_SITE_FILE_SHARING_AND_DOWNLOADS *Permission -var PERMISSION_SYSCONSOLE_WRITE_SITE_FILE_SHARING_AND_DOWNLOADS *Permission - -var PERMISSION_SYSCONSOLE_READ_SITE_PUBLIC_LINKS *Permission -var PERMISSION_SYSCONSOLE_WRITE_SITE_PUBLIC_LINKS *Permission - -var PERMISSION_SYSCONSOLE_READ_SITE_NOTICES *Permission -var PERMISSION_SYSCONSOLE_WRITE_SITE_NOTICES *Permission - -var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION *Permission -var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION *Permission - -var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP *Permission -var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SIGNUP *Permission - -var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL *Permission -var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_EMAIL *Permission - -var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD *Permission -var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_PASSWORD *Permission - -var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA *Permission -var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_MFA *Permission - -var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP *Permission -var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_LDAP *Permission - -var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML *Permission -var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SAML *Permission - -var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID *Permission -var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_OPENID *Permission - -var PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS *Permission -var PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_GUEST_ACCESS *Permission - -var PERMISSION_SYSCONSOLE_READ_PLUGINS *Permission -var PERMISSION_SYSCONSOLE_WRITE_PLUGINS *Permission - -var PERMISSION_SYSCONSOLE_READ_INTEGRATIONS *Permission -var PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS *Permission - -var PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_INTEGRATION_MANAGEMENT *Permission -var PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_INTEGRATION_MANAGEMENT *Permission - -var PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_BOT_ACCOUNTS *Permission -var PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_BOT_ACCOUNTS *Permission - -var PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_GIF *Permission -var PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_GIF *Permission - -var PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_CORS *Permission -var PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_CORS *Permission - -var PERMISSION_SYSCONSOLE_READ_COMPLIANCE *Permission -var PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE *Permission - -var PERMISSION_SYSCONSOLE_READ_COMPLIANCE_DATA_RETENTION_POLICY *Permission -var PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_DATA_RETENTION_POLICY *Permission - -var PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_EXPORT *Permission -var PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_EXPORT *Permission - -var PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_MONITORING *Permission -var PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_MONITORING *Permission - -var PERMISSION_SYSCONSOLE_READ_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE *Permission -var PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE *Permission - -var PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL *Permission -var PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL *Permission - -var PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURES *Permission -var PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURES *Permission - -var PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURE_FLAGS *Permission -var PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURE_FLAGS *Permission - -var PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_BLEVE *Permission -var PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_BLEVE *Permission - -// General permission that encompasses all system admin functions -// in the future this could be broken up to allow access to some -// admin functions but not others -var PERMISSION_MANAGE_SYSTEM *Permission - -var AllPermissions []*Permission -var DeprecatedPermissions []*Permission - -var ChannelModeratedPermissions []string -var ChannelModeratedPermissionsMap map[string]string - -var SysconsoleReadPermissions []*Permission -var SysconsoleWritePermissions []*Permission - -func initializePermissions() { - PERMISSION_INVITE_USER = &Permission{ - "invite_user", - "authentication.permissions.team_invite_user.name", - "authentication.permissions.team_invite_user.description", - PermissionScopeTeam, - } - PERMISSION_ADD_USER_TO_TEAM = &Permission{ - "add_user_to_team", - "authentication.permissions.add_user_to_team.name", - "authentication.permissions.add_user_to_team.description", - PermissionScopeTeam, - } - PERMISSION_USE_SLASH_COMMANDS = &Permission{ - "use_slash_commands", - "authentication.permissions.team_use_slash_commands.name", - "authentication.permissions.team_use_slash_commands.description", - PermissionScopeChannel, - } - PERMISSION_MANAGE_SLASH_COMMANDS = &Permission{ - "manage_slash_commands", - "authentication.permissions.manage_slash_commands.name", - "authentication.permissions.manage_slash_commands.description", - PermissionScopeTeam, - } - PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS = &Permission{ - "manage_others_slash_commands", - "authentication.permissions.manage_others_slash_commands.name", - "authentication.permissions.manage_others_slash_commands.description", - PermissionScopeTeam, - } - PERMISSION_CREATE_PUBLIC_CHANNEL = &Permission{ - "create_public_channel", - "authentication.permissions.create_public_channel.name", - "authentication.permissions.create_public_channel.description", - PermissionScopeTeam, - } - PERMISSION_CREATE_PRIVATE_CHANNEL = &Permission{ - "create_private_channel", - "authentication.permissions.create_private_channel.name", - "authentication.permissions.create_private_channel.description", - PermissionScopeTeam, - } - PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS = &Permission{ - "manage_public_channel_members", - "authentication.permissions.manage_public_channel_members.name", - "authentication.permissions.manage_public_channel_members.description", - PermissionScopeChannel, - } - PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS = &Permission{ - "manage_private_channel_members", - "authentication.permissions.manage_private_channel_members.name", - "authentication.permissions.manage_private_channel_members.description", - PermissionScopeChannel, - } - PERMISSION_CONVERT_PUBLIC_CHANNEL_TO_PRIVATE = &Permission{ - "convert_public_channel_to_private", - "authentication.permissions.convert_public_channel_to_private.name", - "authentication.permissions.convert_public_channel_to_private.description", - PermissionScopeChannel, - } - PERMISSION_CONVERT_PRIVATE_CHANNEL_TO_PUBLIC = &Permission{ - "convert_private_channel_to_public", - "authentication.permissions.convert_private_channel_to_public.name", - "authentication.permissions.convert_private_channel_to_public.description", - PermissionScopeChannel, - } - PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE = &Permission{ - "assign_system_admin_role", - "authentication.permissions.assign_system_admin_role.name", - "authentication.permissions.assign_system_admin_role.description", - PermissionScopeSystem, - } - PERMISSION_MANAGE_ROLES = &Permission{ - "manage_roles", - "authentication.permissions.manage_roles.name", - "authentication.permissions.manage_roles.description", - PermissionScopeSystem, - } - PERMISSION_MANAGE_TEAM_ROLES = &Permission{ - "manage_team_roles", - "authentication.permissions.manage_team_roles.name", - "authentication.permissions.manage_team_roles.description", - PermissionScopeTeam, - } - PERMISSION_MANAGE_CHANNEL_ROLES = &Permission{ - "manage_channel_roles", - "authentication.permissions.manage_channel_roles.name", - "authentication.permissions.manage_channel_roles.description", - PermissionScopeChannel, - } - PERMISSION_MANAGE_SYSTEM = &Permission{ - "manage_system", - "authentication.permissions.manage_system.name", - "authentication.permissions.manage_system.description", - PermissionScopeSystem, - } - PERMISSION_CREATE_DIRECT_CHANNEL = &Permission{ - "create_direct_channel", - "authentication.permissions.create_direct_channel.name", - "authentication.permissions.create_direct_channel.description", - PermissionScopeSystem, - } - PERMISSION_CREATE_GROUP_CHANNEL = &Permission{ - "create_group_channel", - "authentication.permissions.create_group_channel.name", - "authentication.permissions.create_group_channel.description", - PermissionScopeSystem, - } - PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES = &Permission{ - "manage_public_channel_properties", - "authentication.permissions.manage_public_channel_properties.name", - "authentication.permissions.manage_public_channel_properties.description", - PermissionScopeChannel, - } - PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES = &Permission{ - "manage_private_channel_properties", - "authentication.permissions.manage_private_channel_properties.name", - "authentication.permissions.manage_private_channel_properties.description", - PermissionScopeChannel, - } - PERMISSION_LIST_PUBLIC_TEAMS = &Permission{ - "list_public_teams", - "authentication.permissions.list_public_teams.name", - "authentication.permissions.list_public_teams.description", - PermissionScopeSystem, - } - PERMISSION_JOIN_PUBLIC_TEAMS = &Permission{ - "join_public_teams", - "authentication.permissions.join_public_teams.name", - "authentication.permissions.join_public_teams.description", - PermissionScopeSystem, - } - PERMISSION_LIST_PRIVATE_TEAMS = &Permission{ - "list_private_teams", - "authentication.permissions.list_private_teams.name", - "authentication.permissions.list_private_teams.description", - PermissionScopeSystem, - } - PERMISSION_JOIN_PRIVATE_TEAMS = &Permission{ - "join_private_teams", - "authentication.permissions.join_private_teams.name", - "authentication.permissions.join_private_teams.description", - PermissionScopeSystem, - } - PERMISSION_LIST_TEAM_CHANNELS = &Permission{ - "list_team_channels", - "authentication.permissions.list_team_channels.name", - "authentication.permissions.list_team_channels.description", - PermissionScopeTeam, - } - PERMISSION_JOIN_PUBLIC_CHANNELS = &Permission{ - "join_public_channels", - "authentication.permissions.join_public_channels.name", - "authentication.permissions.join_public_channels.description", - PermissionScopeTeam, - } - PERMISSION_DELETE_PUBLIC_CHANNEL = &Permission{ - "delete_public_channel", - "authentication.permissions.delete_public_channel.name", - "authentication.permissions.delete_public_channel.description", - PermissionScopeChannel, - } - PERMISSION_DELETE_PRIVATE_CHANNEL = &Permission{ - "delete_private_channel", - "authentication.permissions.delete_private_channel.name", - "authentication.permissions.delete_private_channel.description", - PermissionScopeChannel, - } - PERMISSION_EDIT_OTHER_USERS = &Permission{ - "edit_other_users", - "authentication.permissions.edit_other_users.name", - "authentication.permissions.edit_other_users.description", - PermissionScopeSystem, - } - PERMISSION_READ_CHANNEL = &Permission{ - "read_channel", - "authentication.permissions.read_channel.name", - "authentication.permissions.read_channel.description", - PermissionScopeChannel, - } - PERMISSION_READ_PUBLIC_CHANNEL_GROUPS = &Permission{ - "read_public_channel_groups", - "authentication.permissions.read_public_channel_groups.name", - "authentication.permissions.read_public_channel_groups.description", - PermissionScopeChannel, - } - PERMISSION_READ_PRIVATE_CHANNEL_GROUPS = &Permission{ - "read_private_channel_groups", - "authentication.permissions.read_private_channel_groups.name", - "authentication.permissions.read_private_channel_groups.description", - PermissionScopeChannel, - } - PERMISSION_READ_PUBLIC_CHANNEL = &Permission{ - "read_public_channel", - "authentication.permissions.read_public_channel.name", - "authentication.permissions.read_public_channel.description", - PermissionScopeTeam, - } - PERMISSION_ADD_REACTION = &Permission{ - "add_reaction", - "authentication.permissions.add_reaction.name", - "authentication.permissions.add_reaction.description", - PermissionScopeChannel, - } - PERMISSION_REMOVE_REACTION = &Permission{ - "remove_reaction", - "authentication.permissions.remove_reaction.name", - "authentication.permissions.remove_reaction.description", - PermissionScopeChannel, - } - PERMISSION_REMOVE_OTHERS_REACTIONS = &Permission{ - "remove_others_reactions", - "authentication.permissions.remove_others_reactions.name", - "authentication.permissions.remove_others_reactions.description", - PermissionScopeChannel, - } - // DEPRECATED - PERMISSION_PERMANENT_DELETE_USER = &Permission{ - "permanent_delete_user", - "authentication.permissions.permanent_delete_user.name", - "authentication.permissions.permanent_delete_user.description", - PermissionScopeSystem, - } - PERMISSION_UPLOAD_FILE = &Permission{ - "upload_file", - "authentication.permissions.upload_file.name", - "authentication.permissions.upload_file.description", - PermissionScopeChannel, - } - PERMISSION_GET_PUBLIC_LINK = &Permission{ - "get_public_link", - "authentication.permissions.get_public_link.name", - "authentication.permissions.get_public_link.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_MANAGE_WEBHOOKS = &Permission{ - "manage_webhooks", - "authentication.permissions.manage_webhooks.name", - "authentication.permissions.manage_webhooks.description", - PermissionScopeTeam, - } - // DEPRECATED - PERMISSION_MANAGE_OTHERS_WEBHOOKS = &Permission{ - "manage_others_webhooks", - "authentication.permissions.manage_others_webhooks.name", - "authentication.permissions.manage_others_webhooks.description", - PermissionScopeTeam, - } - PERMISSION_MANAGE_INCOMING_WEBHOOKS = &Permission{ - "manage_incoming_webhooks", - "authentication.permissions.manage_incoming_webhooks.name", - "authentication.permissions.manage_incoming_webhooks.description", - PermissionScopeTeam, - } - PERMISSION_MANAGE_OUTGOING_WEBHOOKS = &Permission{ - "manage_outgoing_webhooks", - "authentication.permissions.manage_outgoing_webhooks.name", - "authentication.permissions.manage_outgoing_webhooks.description", - PermissionScopeTeam, - } - PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS = &Permission{ - "manage_others_incoming_webhooks", - "authentication.permissions.manage_others_incoming_webhooks.name", - "authentication.permissions.manage_others_incoming_webhooks.description", - PermissionScopeTeam, - } - PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS = &Permission{ - "manage_others_outgoing_webhooks", - "authentication.permissions.manage_others_outgoing_webhooks.name", - "authentication.permissions.manage_others_outgoing_webhooks.description", - PermissionScopeTeam, - } - PERMISSION_MANAGE_OAUTH = &Permission{ - "manage_oauth", - "authentication.permissions.manage_oauth.name", - "authentication.permissions.manage_oauth.description", - PermissionScopeSystem, - } - PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH = &Permission{ - "manage_system_wide_oauth", - "authentication.permissions.manage_system_wide_oauth.name", - "authentication.permissions.manage_system_wide_oauth.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_MANAGE_EMOJIS = &Permission{ - "manage_emojis", - "authentication.permissions.manage_emojis.name", - "authentication.permissions.manage_emojis.description", - PermissionScopeTeam, - } - // DEPRECATED - PERMISSION_MANAGE_OTHERS_EMOJIS = &Permission{ - "manage_others_emojis", - "authentication.permissions.manage_others_emojis.name", - "authentication.permissions.manage_others_emojis.description", - PermissionScopeTeam, - } - PERMISSION_CREATE_EMOJIS = &Permission{ - "create_emojis", - "authentication.permissions.create_emojis.name", - "authentication.permissions.create_emojis.description", - PermissionScopeTeam, - } - PERMISSION_DELETE_EMOJIS = &Permission{ - "delete_emojis", - "authentication.permissions.delete_emojis.name", - "authentication.permissions.delete_emojis.description", - PermissionScopeTeam, - } - PERMISSION_DELETE_OTHERS_EMOJIS = &Permission{ - "delete_others_emojis", - "authentication.permissions.delete_others_emojis.name", - "authentication.permissions.delete_others_emojis.description", - PermissionScopeTeam, - } - PERMISSION_CREATE_POST = &Permission{ - "create_post", - "authentication.permissions.create_post.name", - "authentication.permissions.create_post.description", - PermissionScopeChannel, - } - PERMISSION_CREATE_POST_PUBLIC = &Permission{ - "create_post_public", - "authentication.permissions.create_post_public.name", - "authentication.permissions.create_post_public.description", - PermissionScopeChannel, - } - PERMISSION_CREATE_POST_EPHEMERAL = &Permission{ - "create_post_ephemeral", - "authentication.permissions.create_post_ephemeral.name", - "authentication.permissions.create_post_ephemeral.description", - PermissionScopeChannel, - } - PERMISSION_EDIT_POST = &Permission{ - "edit_post", - "authentication.permissions.edit_post.name", - "authentication.permissions.edit_post.description", - PermissionScopeChannel, - } - PERMISSION_EDIT_OTHERS_POSTS = &Permission{ - "edit_others_posts", - "authentication.permissions.edit_others_posts.name", - "authentication.permissions.edit_others_posts.description", - PermissionScopeChannel, - } - PERMISSION_DELETE_POST = &Permission{ - "delete_post", - "authentication.permissions.delete_post.name", - "authentication.permissions.delete_post.description", - PermissionScopeChannel, - } - PERMISSION_DELETE_OTHERS_POSTS = &Permission{ - "delete_others_posts", - "authentication.permissions.delete_others_posts.name", - "authentication.permissions.delete_others_posts.description", - PermissionScopeChannel, - } - PERMISSION_MANAGE_SHARED_CHANNELS = &Permission{ - "manage_shared_channels", - "authentication.permissions.manage_shared_channels.name", - "authentication.permissions.manage_shared_channels.description", - PermissionScopeSystem, - } - PERMISSION_MANAGE_SECURE_CONNECTIONS = &Permission{ - "manage_secure_connections", - "authentication.permissions.manage_secure_connections.name", - "authentication.permissions.manage_secure_connections.description", - PermissionScopeSystem, - } - - PERMISSION_CREATE_DATA_RETENTION_JOB = &Permission{ - "create_data_retention_job", - "", - "", - PermissionScopeSystem, - } - PERMISSION_READ_DATA_RETENTION_JOB = &Permission{ - "read_data_retention_job", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_CREATE_COMPLIANCE_EXPORT_JOB = &Permission{ - "create_compliance_export_job", - "", - "", - PermissionScopeSystem, - } - PERMISSION_READ_COMPLIANCE_EXPORT_JOB = &Permission{ - "read_compliance_export_job", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_READ_AUDITS = &Permission{ - "read_audits", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_PURGE_BLEVE_INDEXES = &Permission{ - "purge_bleve_indexes", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_CREATE_POST_BLEVE_INDEXES_JOB = &Permission{ - "create_post_bleve_indexes_job", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_CREATE_LDAP_SYNC_JOB = &Permission{ - "create_ldap_sync_job", - "", - "", - PermissionScopeSystem, - } - PERMISSION_READ_LDAP_SYNC_JOB = &Permission{ - "read_ldap_sync_job", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_TEST_LDAP = &Permission{ - "test_ldap", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_INVALIDATE_EMAIL_INVITE = &Permission{ - "invalidate_email_invite", - "", - "", - PermissionScopeSystem, - } - PERMISSION_GET_SAML_METADATA_FROM_IDP = &Permission{ - "get_saml_metadata_from_idp", - "", - "", - PermissionScopeSystem, - } - PERMISSION_ADD_SAML_PUBLIC_CERT = &Permission{ - "add_saml_public_cert", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_ADD_SAML_PRIVATE_CERT = &Permission{ - "add_saml_private_cert", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_ADD_SAML_IDP_CERT = &Permission{ - "add_saml_idp_cert", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_REMOVE_SAML_PUBLIC_CERT = &Permission{ - "remove_saml_public_cert", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_REMOVE_SAML_PRIVATE_CERT = &Permission{ - "remove_saml_private_cert", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_REMOVE_SAML_IDP_CERT = &Permission{ - "remove_saml_idp_cert", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_GET_SAML_CERT_STATUS = &Permission{ - "get_saml_cert_status", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_ADD_LDAP_PUBLIC_CERT = &Permission{ - "add_ldap_public_cert", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_ADD_LDAP_PRIVATE_CERT = &Permission{ - "add_ldap_private_cert", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_REMOVE_LDAP_PUBLIC_CERT = &Permission{ - "remove_ldap_public_cert", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_REMOVE_LDAP_PRIVATE_CERT = &Permission{ - "remove_ldap_private_cert", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_GET_LOGS = &Permission{ - "get_logs", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_READ_LICENSE_INFORMATION = &Permission{ - "read_license_information", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_GET_ANALYTICS = &Permission{ - "get_analytics", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_MANAGE_LICENSE_INFORMATION = &Permission{ - "manage_license_information", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT = &Permission{ - "download_compliance_export_result", - "authentication.permissions.download_compliance_export_result.name", - "authentication.permissions.download_compliance_export_result.description", - PermissionScopeSystem, - } - - PERMISSION_TEST_SITE_URL = &Permission{ - "test_site_url", - "", - "", - PermissionScopeSystem, - } - PERMISSION_TEST_ELASTICSEARCH = &Permission{ - "test_elasticsearch", - "", - "", - PermissionScopeSystem, - } - PERMISSION_TEST_S3 = &Permission{ - "test_s3", - "", - "", - PermissionScopeSystem, - } - PERMISSION_RELOAD_CONFIG = &Permission{ - "reload_config", - "", - "", - PermissionScopeSystem, - } - PERMISSION_INVALIDATE_CACHES = &Permission{ - "invalidate_caches", - "", - "", - PermissionScopeSystem, - } - PERMISSION_RECYCLE_DATABASE_CONNECTIONS = &Permission{ - "recycle_database_connections", - "", - "", - PermissionScopeSystem, - } - PERMISSION_PURGE_ELASTICSEARCH_INDEXES = &Permission{ - "purge_elasticsearch_indexes", - "", - "", - PermissionScopeSystem, - } - PERMISSION_TEST_EMAIL = &Permission{ - "test_email", - "", - "", - PermissionScopeSystem, - } - PERMISSION_CREATE_ELASTICSEARCH_POST_INDEXING_JOB = &Permission{ - "create_elasticsearch_post_indexing_job", - "", - "", - PermissionScopeSystem, - } - PERMISSION_CREATE_ELASTICSEARCH_POST_AGGREGATION_JOB = &Permission{ - "create_elasticsearch_post_aggregation_job", - "", - "", - PermissionScopeSystem, - } - PERMISSION_READ_ELASTICSEARCH_POST_INDEXING_JOB = &Permission{ - "read_elasticsearch_post_indexing_job", - "", - "", - PermissionScopeSystem, - } - PERMISSION_READ_ELASTICSEARCH_POST_AGGREGATION_JOB = &Permission{ - "read_elasticsearch_post_aggregation_job", - "", - "", - PermissionScopeSystem, - } - - PERMISSION_REMOVE_USER_FROM_TEAM = &Permission{ - "remove_user_from_team", - "authentication.permissions.remove_user_from_team.name", - "authentication.permissions.remove_user_from_team.description", - PermissionScopeTeam, - } - PERMISSION_CREATE_TEAM = &Permission{ - "create_team", - "authentication.permissions.create_team.name", - "authentication.permissions.create_team.description", - PermissionScopeSystem, - } - PERMISSION_MANAGE_TEAM = &Permission{ - "manage_team", - "authentication.permissions.manage_team.name", - "authentication.permissions.manage_team.description", - PermissionScopeTeam, - } - PERMISSION_IMPORT_TEAM = &Permission{ - "import_team", - "authentication.permissions.import_team.name", - "authentication.permissions.import_team.description", - PermissionScopeTeam, - } - PERMISSION_VIEW_TEAM = &Permission{ - "view_team", - "authentication.permissions.view_team.name", - "authentication.permissions.view_team.description", - PermissionScopeTeam, - } - PERMISSION_LIST_USERS_WITHOUT_TEAM = &Permission{ - "list_users_without_team", - "authentication.permissions.list_users_without_team.name", - "authentication.permissions.list_users_without_team.description", - PermissionScopeSystem, - } - PERMISSION_CREATE_USER_ACCESS_TOKEN = &Permission{ - "create_user_access_token", - "authentication.permissions.create_user_access_token.name", - "authentication.permissions.create_user_access_token.description", - PermissionScopeSystem, - } - PERMISSION_READ_USER_ACCESS_TOKEN = &Permission{ - "read_user_access_token", - "authentication.permissions.read_user_access_token.name", - "authentication.permissions.read_user_access_token.description", - PermissionScopeSystem, - } - PERMISSION_REVOKE_USER_ACCESS_TOKEN = &Permission{ - "revoke_user_access_token", - "authentication.permissions.revoke_user_access_token.name", - "authentication.permissions.revoke_user_access_token.description", - PermissionScopeSystem, - } - PERMISSION_CREATE_BOT = &Permission{ - "create_bot", - "authentication.permissions.create_bot.name", - "authentication.permissions.create_bot.description", - PermissionScopeSystem, - } - PERMISSION_ASSIGN_BOT = &Permission{ - "assign_bot", - "authentication.permissions.assign_bot.name", - "authentication.permissions.assign_bot.description", - PermissionScopeSystem, - } - PERMISSION_READ_BOTS = &Permission{ - "read_bots", - "authentication.permissions.read_bots.name", - "authentication.permissions.read_bots.description", - PermissionScopeSystem, - } - PERMISSION_READ_OTHERS_BOTS = &Permission{ - "read_others_bots", - "authentication.permissions.read_others_bots.name", - "authentication.permissions.read_others_bots.description", - PermissionScopeSystem, - } - PERMISSION_MANAGE_BOTS = &Permission{ - "manage_bots", - "authentication.permissions.manage_bots.name", - "authentication.permissions.manage_bots.description", - PermissionScopeSystem, - } - PERMISSION_MANAGE_OTHERS_BOTS = &Permission{ - "manage_others_bots", - "authentication.permissions.manage_others_bots.name", - "authentication.permissions.manage_others_bots.description", - PermissionScopeSystem, - } - PERMISSION_READ_JOBS = &Permission{ - "read_jobs", - "authentication.permisssions.read_jobs.name", - "authentication.permisssions.read_jobs.description", - PermissionScopeSystem, - } - PERMISSION_MANAGE_JOBS = &Permission{ - "manage_jobs", - "authentication.permisssions.manage_jobs.name", - "authentication.permisssions.manage_jobs.description", - PermissionScopeSystem, - } - PERMISSION_VIEW_MEMBERS = &Permission{ - "view_members", - "authentication.permisssions.view_members.name", - "authentication.permisssions.view_members.description", - PermissionScopeTeam, - } - PERMISSION_INVITE_GUEST = &Permission{ - "invite_guest", - "authentication.permissions.invite_guest.name", - "authentication.permissions.invite_guest.description", - PermissionScopeTeam, - } - PERMISSION_PROMOTE_GUEST = &Permission{ - "promote_guest", - "authentication.permissions.promote_guest.name", - "authentication.permissions.promote_guest.description", - PermissionScopeSystem, - } - PERMISSION_DEMOTE_TO_GUEST = &Permission{ - "demote_to_guest", - "authentication.permissions.demote_to_guest.name", - "authentication.permissions.demote_to_guest.description", - PermissionScopeSystem, - } - PERMISSION_USE_CHANNEL_MENTIONS = &Permission{ - "use_channel_mentions", - "authentication.permissions.use_channel_mentions.name", - "authentication.permissions.use_channel_mentions.description", - PermissionScopeChannel, - } - PERMISSION_USE_GROUP_MENTIONS = &Permission{ - "use_group_mentions", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeChannel, - } - PERMISSION_READ_OTHER_USERS_TEAMS = &Permission{ - "read_other_users_teams", - "authentication.permissions.read_other_users_teams.name", - "authentication.permissions.read_other_users_teams.description", - PermissionScopeSystem, - } - PERMISSION_EDIT_BRAND = &Permission{ - "edit_brand", - "authentication.permissions.edit_brand.name", - "authentication.permissions.edit_brand.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_READ_ABOUT = &Permission{ - "sysconsole_read_about", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_WRITE_ABOUT = &Permission{ - "sysconsole_write_about", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE = &Permission{ - "sysconsole_read_about_edition_and_license", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ABOUT_EDITION_AND_LICENSE = &Permission{ - "sysconsole_write_about_edition_and_license", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_BILLING = &Permission{ - "sysconsole_read_billing", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_BILLING = &Permission{ - "sysconsole_write_billing", - "", - "", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_READ_REPORTING = &Permission{ - "sysconsole_read_reporting", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_WRITE_REPORTING = &Permission{ - "sysconsole_write_reporting", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS = &Permission{ - "sysconsole_read_reporting_site_statistics", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_REPORTING_SITE_STATISTICS = &Permission{ - "sysconsole_write_reporting_site_statistics", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS = &Permission{ - "sysconsole_read_reporting_team_statistics", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_REPORTING_TEAM_STATISTICS = &Permission{ - "sysconsole_write_reporting_team_statistics", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS = &Permission{ - "sysconsole_read_reporting_server_logs", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_REPORTING_SERVER_LOGS = &Permission{ - "sysconsole_write_reporting_server_logs", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS = &Permission{ - "sysconsole_read_user_management_users", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_USERS = &Permission{ - "sysconsole_write_user_management_users", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS = &Permission{ - "sysconsole_read_user_management_groups", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS = &Permission{ - "sysconsole_write_user_management_groups", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS = &Permission{ - "sysconsole_read_user_management_teams", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS = &Permission{ - "sysconsole_write_user_management_teams", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS = &Permission{ - "sysconsole_read_user_management_channels", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS = &Permission{ - "sysconsole_write_user_management_channels", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS = &Permission{ - "sysconsole_read_user_management_permissions", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS = &Permission{ - "sysconsole_write_user_management_permissions", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_SYSTEM_ROLES = &Permission{ - "sysconsole_read_user_management_system_roles", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_SYSTEM_ROLES = &Permission{ - "sysconsole_write_user_management_system_roles", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT = &Permission{ - "sysconsole_read_environment", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT = &Permission{ - "sysconsole_write_environment", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_WEB_SERVER = &Permission{ - "sysconsole_read_environment_web_server", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_WEB_SERVER = &Permission{ - "sysconsole_write_environment_web_server", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DATABASE = &Permission{ - "sysconsole_read_environment_database", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DATABASE = &Permission{ - "sysconsole_write_environment_database", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH = &Permission{ - "sysconsole_read_environment_elasticsearch", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_ELASTICSEARCH = &Permission{ - "sysconsole_write_environment_elasticsearch", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_FILE_STORAGE = &Permission{ - "sysconsole_read_environment_file_storage", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_FILE_STORAGE = &Permission{ - "sysconsole_write_environment_file_storage", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_IMAGE_PROXY = &Permission{ - "sysconsole_read_environment_image_proxy", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_IMAGE_PROXY = &Permission{ - "sysconsole_write_environment_image_proxy", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SMTP = &Permission{ - "sysconsole_read_environment_smtp", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SMTP = &Permission{ - "sysconsole_write_environment_smtp", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PUSH_NOTIFICATION_SERVER = &Permission{ - "sysconsole_read_environment_push_notification_server", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PUSH_NOTIFICATION_SERVER = &Permission{ - "sysconsole_write_environment_push_notification_server", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_HIGH_AVAILABILITY = &Permission{ - "sysconsole_read_environment_high_availability", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_HIGH_AVAILABILITY = &Permission{ - "sysconsole_write_environment_high_availability", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_RATE_LIMITING = &Permission{ - "sysconsole_read_environment_rate_limiting", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_RATE_LIMITING = &Permission{ - "sysconsole_write_environment_rate_limiting", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_LOGGING = &Permission{ - "sysconsole_read_environment_logging", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_LOGGING = &Permission{ - "sysconsole_write_environment_logging", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS = &Permission{ - "sysconsole_read_environment_session_lengths", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SESSION_LENGTHS = &Permission{ - "sysconsole_write_environment_session_lengths", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING = &Permission{ - "sysconsole_read_environment_performance_monitoring", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PERFORMANCE_MONITORING = &Permission{ - "sysconsole_write_environment_performance_monitoring", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER = &Permission{ - "sysconsole_read_environment_developer", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DEVELOPER = &Permission{ - "sysconsole_write_environment_developer", - "", - "", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_READ_SITE = &Permission{ - "sysconsole_read_site", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_WRITE_SITE = &Permission{ - "sysconsole_write_site", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - - PERMISSION_SYSCONSOLE_READ_SITE_CUSTOMIZATION = &Permission{ - "sysconsole_read_site_customization", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_SITE_CUSTOMIZATION = &Permission{ - "sysconsole_write_site_customization", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_SITE_LOCALIZATION = &Permission{ - "sysconsole_read_site_localization", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_SITE_LOCALIZATION = &Permission{ - "sysconsole_write_site_localization", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_SITE_USERS_AND_TEAMS = &Permission{ - "sysconsole_read_site_users_and_teams", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_SITE_USERS_AND_TEAMS = &Permission{ - "sysconsole_write_site_users_and_teams", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_SITE_NOTIFICATIONS = &Permission{ - "sysconsole_read_site_notifications", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_SITE_NOTIFICATIONS = &Permission{ - "sysconsole_write_site_notifications", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_SITE_ANNOUNCEMENT_BANNER = &Permission{ - "sysconsole_read_site_announcement_banner", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_SITE_ANNOUNCEMENT_BANNER = &Permission{ - "sysconsole_write_site_announcement_banner", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_SITE_EMOJI = &Permission{ - "sysconsole_read_site_emoji", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_SITE_EMOJI = &Permission{ - "sysconsole_write_site_emoji", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_SITE_POSTS = &Permission{ - "sysconsole_read_site_posts", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_SITE_POSTS = &Permission{ - "sysconsole_write_site_posts", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_SITE_FILE_SHARING_AND_DOWNLOADS = &Permission{ - "sysconsole_read_site_file_sharing_and_downloads", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_SITE_FILE_SHARING_AND_DOWNLOADS = &Permission{ - "sysconsole_write_site_file_sharing_and_downloads", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_SITE_PUBLIC_LINKS = &Permission{ - "sysconsole_read_site_public_links", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_SITE_PUBLIC_LINKS = &Permission{ - "sysconsole_write_site_public_links", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_SITE_NOTICES = &Permission{ - "sysconsole_read_site_notices", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_SITE_NOTICES = &Permission{ - "sysconsole_write_site_notices", - "", - "", - PermissionScopeSystem, - } - - // Deprecated - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION = &Permission{ - "sysconsole_read_authentication", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - // Deprecated - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION = &Permission{ - "sysconsole_write_authentication", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP = &Permission{ - "sysconsole_read_authentication_signup", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SIGNUP = &Permission{ - "sysconsole_write_authentication_signup", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL = &Permission{ - "sysconsole_read_authentication_email", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_EMAIL = &Permission{ - "sysconsole_write_authentication_email", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD = &Permission{ - "sysconsole_read_authentication_password", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_PASSWORD = &Permission{ - "sysconsole_write_authentication_password", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA = &Permission{ - "sysconsole_read_authentication_mfa", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_MFA = &Permission{ - "sysconsole_write_authentication_mfa", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP = &Permission{ - "sysconsole_read_authentication_ldap", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_LDAP = &Permission{ - "sysconsole_write_authentication_ldap", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML = &Permission{ - "sysconsole_read_authentication_saml", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SAML = &Permission{ - "sysconsole_write_authentication_saml", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID = &Permission{ - "sysconsole_read_authentication_openid", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_OPENID = &Permission{ - "sysconsole_write_authentication_openid", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS = &Permission{ - "sysconsole_read_authentication_guest_access", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_GUEST_ACCESS = &Permission{ - "sysconsole_write_authentication_guest_access", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_PLUGINS = &Permission{ - "sysconsole_read_plugins", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_PLUGINS = &Permission{ - "sysconsole_write_plugins", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS = &Permission{ - "sysconsole_read_integrations", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS = &Permission{ - "sysconsole_write_integrations", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_INTEGRATION_MANAGEMENT = &Permission{ - "sysconsole_read_integrations_integration_management", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_INTEGRATION_MANAGEMENT = &Permission{ - "sysconsole_write_integrations_integration_management", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_BOT_ACCOUNTS = &Permission{ - "sysconsole_read_integrations_bot_accounts", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_BOT_ACCOUNTS = &Permission{ - "sysconsole_write_integrations_bot_accounts", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_GIF = &Permission{ - "sysconsole_read_integrations_gif", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_GIF = &Permission{ - "sysconsole_write_integrations_gif", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_CORS = &Permission{ - "sysconsole_read_integrations_cors", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_CORS = &Permission{ - "sysconsole_write_integrations_cors", - "", - "", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_READ_COMPLIANCE = &Permission{ - "sysconsole_read_compliance", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE = &Permission{ - "sysconsole_write_compliance", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_DATA_RETENTION_POLICY = &Permission{ - "sysconsole_read_compliance_data_retention_policy", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_DATA_RETENTION_POLICY = &Permission{ - "sysconsole_write_compliance_data_retention_policy", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_EXPORT = &Permission{ - "sysconsole_read_compliance_compliance_export", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_EXPORT = &Permission{ - "sysconsole_write_compliance_compliance_export", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_MONITORING = &Permission{ - "sysconsole_read_compliance_compliance_monitoring", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_MONITORING = &Permission{ - "sysconsole_write_compliance_compliance_monitoring", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE = &Permission{ - "sysconsole_read_compliance_custom_terms_of_service", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE = &Permission{ - "sysconsole_write_compliance_custom_terms_of_service", - "", - "", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL = &Permission{ - "sysconsole_read_experimental", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - // DEPRECATED - PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL = &Permission{ - "sysconsole_write_experimental", - "authentication.permissions.use_group_mentions.name", - "authentication.permissions.use_group_mentions.description", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURES = &Permission{ - "sysconsole_read_experimental_features", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURES = &Permission{ - "sysconsole_write_experimental_features", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURE_FLAGS = &Permission{ - "sysconsole_read_experimental_feature_flags", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURE_FLAGS = &Permission{ - "sysconsole_write_experimental_feature_flags", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_BLEVE = &Permission{ - "sysconsole_read_experimental_bleve", - "", - "", - PermissionScopeSystem, - } - PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_BLEVE = &Permission{ - "sysconsole_write_experimental_bleve", - "", - "", - PermissionScopeSystem, - } - - SysconsoleReadPermissions = []*Permission{ - PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE, - PERMISSION_SYSCONSOLE_READ_BILLING, - PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS, - PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS, - PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_SYSTEM_ROLES, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_WEB_SERVER, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DATABASE, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_FILE_STORAGE, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_IMAGE_PROXY, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SMTP, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PUSH_NOTIFICATION_SERVER, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_HIGH_AVAILABILITY, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_RATE_LIMITING, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_LOGGING, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER, - PERMISSION_SYSCONSOLE_READ_SITE_CUSTOMIZATION, - PERMISSION_SYSCONSOLE_READ_SITE_LOCALIZATION, - PERMISSION_SYSCONSOLE_READ_SITE_USERS_AND_TEAMS, - PERMISSION_SYSCONSOLE_READ_SITE_NOTIFICATIONS, - PERMISSION_SYSCONSOLE_READ_SITE_ANNOUNCEMENT_BANNER, - PERMISSION_SYSCONSOLE_READ_SITE_EMOJI, - PERMISSION_SYSCONSOLE_READ_SITE_POSTS, - PERMISSION_SYSCONSOLE_READ_SITE_FILE_SHARING_AND_DOWNLOADS, - PERMISSION_SYSCONSOLE_READ_SITE_PUBLIC_LINKS, - PERMISSION_SYSCONSOLE_READ_SITE_NOTICES, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS, - PERMISSION_SYSCONSOLE_READ_PLUGINS, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_INTEGRATION_MANAGEMENT, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_BOT_ACCOUNTS, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_GIF, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_CORS, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_DATA_RETENTION_POLICY, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_EXPORT, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_MONITORING, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE, - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURES, - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURE_FLAGS, - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_BLEVE, - } - - SysconsoleWritePermissions = []*Permission{ - PERMISSION_SYSCONSOLE_WRITE_ABOUT_EDITION_AND_LICENSE, - PERMISSION_SYSCONSOLE_WRITE_BILLING, - PERMISSION_SYSCONSOLE_WRITE_REPORTING_SITE_STATISTICS, - PERMISSION_SYSCONSOLE_WRITE_REPORTING_TEAM_STATISTICS, - PERMISSION_SYSCONSOLE_WRITE_REPORTING_SERVER_LOGS, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_USERS, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_SYSTEM_ROLES, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_WEB_SERVER, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DATABASE, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_ELASTICSEARCH, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_FILE_STORAGE, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_IMAGE_PROXY, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SMTP, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PUSH_NOTIFICATION_SERVER, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_HIGH_AVAILABILITY, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_RATE_LIMITING, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_LOGGING, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SESSION_LENGTHS, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PERFORMANCE_MONITORING, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DEVELOPER, - PERMISSION_SYSCONSOLE_WRITE_SITE_CUSTOMIZATION, - PERMISSION_SYSCONSOLE_WRITE_SITE_LOCALIZATION, - PERMISSION_SYSCONSOLE_WRITE_SITE_USERS_AND_TEAMS, - PERMISSION_SYSCONSOLE_WRITE_SITE_NOTIFICATIONS, - PERMISSION_SYSCONSOLE_WRITE_SITE_ANNOUNCEMENT_BANNER, - PERMISSION_SYSCONSOLE_WRITE_SITE_EMOJI, - PERMISSION_SYSCONSOLE_WRITE_SITE_POSTS, - PERMISSION_SYSCONSOLE_WRITE_SITE_FILE_SHARING_AND_DOWNLOADS, - PERMISSION_SYSCONSOLE_WRITE_SITE_PUBLIC_LINKS, - PERMISSION_SYSCONSOLE_WRITE_SITE_NOTICES, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SIGNUP, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_EMAIL, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_PASSWORD, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_MFA, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_LDAP, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SAML, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_OPENID, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_GUEST_ACCESS, - PERMISSION_SYSCONSOLE_WRITE_PLUGINS, - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_INTEGRATION_MANAGEMENT, - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_BOT_ACCOUNTS, - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_GIF, - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_CORS, - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_DATA_RETENTION_POLICY, - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_EXPORT, - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_MONITORING, - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE, - PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURES, - PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_FEATURE_FLAGS, - PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_BLEVE, - } - - SystemScopedPermissionsMinusSysconsole := []*Permission{ - PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE, - PERMISSION_MANAGE_ROLES, - PERMISSION_MANAGE_SYSTEM, - PERMISSION_CREATE_DIRECT_CHANNEL, - PERMISSION_CREATE_GROUP_CHANNEL, - PERMISSION_LIST_PUBLIC_TEAMS, - PERMISSION_JOIN_PUBLIC_TEAMS, - PERMISSION_LIST_PRIVATE_TEAMS, - PERMISSION_JOIN_PRIVATE_TEAMS, - PERMISSION_EDIT_OTHER_USERS, - PERMISSION_READ_OTHER_USERS_TEAMS, - PERMISSION_GET_PUBLIC_LINK, - PERMISSION_MANAGE_OAUTH, - PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH, - PERMISSION_CREATE_TEAM, - PERMISSION_LIST_USERS_WITHOUT_TEAM, - PERMISSION_CREATE_USER_ACCESS_TOKEN, - PERMISSION_READ_USER_ACCESS_TOKEN, - PERMISSION_REVOKE_USER_ACCESS_TOKEN, - PERMISSION_CREATE_BOT, - PERMISSION_ASSIGN_BOT, - PERMISSION_READ_BOTS, - PERMISSION_READ_OTHERS_BOTS, - PERMISSION_MANAGE_BOTS, - PERMISSION_MANAGE_OTHERS_BOTS, - PERMISSION_READ_JOBS, - PERMISSION_MANAGE_JOBS, - PERMISSION_PROMOTE_GUEST, - PERMISSION_DEMOTE_TO_GUEST, - PERMISSION_EDIT_BRAND, - PERMISSION_MANAGE_SHARED_CHANNELS, - PERMISSION_MANAGE_SECURE_CONNECTIONS, - PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT, - PERMISSION_CREATE_DATA_RETENTION_JOB, - PERMISSION_READ_DATA_RETENTION_JOB, - PERMISSION_CREATE_COMPLIANCE_EXPORT_JOB, - PERMISSION_READ_COMPLIANCE_EXPORT_JOB, - PERMISSION_READ_AUDITS, - PERMISSION_TEST_SITE_URL, - PERMISSION_TEST_ELASTICSEARCH, - PERMISSION_TEST_S3, - PERMISSION_RELOAD_CONFIG, - PERMISSION_INVALIDATE_CACHES, - PERMISSION_RECYCLE_DATABASE_CONNECTIONS, - PERMISSION_PURGE_ELASTICSEARCH_INDEXES, - PERMISSION_TEST_EMAIL, - PERMISSION_CREATE_ELASTICSEARCH_POST_INDEXING_JOB, - PERMISSION_CREATE_ELASTICSEARCH_POST_AGGREGATION_JOB, - PERMISSION_READ_ELASTICSEARCH_POST_INDEXING_JOB, - PERMISSION_READ_ELASTICSEARCH_POST_AGGREGATION_JOB, - PERMISSION_PURGE_BLEVE_INDEXES, - PERMISSION_CREATE_POST_BLEVE_INDEXES_JOB, - PERMISSION_CREATE_LDAP_SYNC_JOB, - PERMISSION_READ_LDAP_SYNC_JOB, - PERMISSION_TEST_LDAP, - PERMISSION_INVALIDATE_EMAIL_INVITE, - PERMISSION_GET_SAML_METADATA_FROM_IDP, - PERMISSION_ADD_SAML_PUBLIC_CERT, - PERMISSION_ADD_SAML_PRIVATE_CERT, - PERMISSION_ADD_SAML_IDP_CERT, - PERMISSION_REMOVE_SAML_PUBLIC_CERT, - PERMISSION_REMOVE_SAML_PRIVATE_CERT, - PERMISSION_REMOVE_SAML_IDP_CERT, - PERMISSION_GET_SAML_CERT_STATUS, - PERMISSION_ADD_LDAP_PUBLIC_CERT, - PERMISSION_ADD_LDAP_PRIVATE_CERT, - PERMISSION_REMOVE_LDAP_PUBLIC_CERT, - PERMISSION_REMOVE_LDAP_PRIVATE_CERT, - PERMISSION_GET_ANALYTICS, - PERMISSION_GET_LOGS, - PERMISSION_READ_LICENSE_INFORMATION, - PERMISSION_MANAGE_LICENSE_INFORMATION, - } - - TeamScopedPermissions := []*Permission{ - PERMISSION_INVITE_USER, - PERMISSION_ADD_USER_TO_TEAM, - PERMISSION_MANAGE_SLASH_COMMANDS, - PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS, - PERMISSION_CREATE_PUBLIC_CHANNEL, - PERMISSION_CREATE_PRIVATE_CHANNEL, - PERMISSION_MANAGE_TEAM_ROLES, - PERMISSION_LIST_TEAM_CHANNELS, - PERMISSION_JOIN_PUBLIC_CHANNELS, - PERMISSION_READ_PUBLIC_CHANNEL, - PERMISSION_MANAGE_INCOMING_WEBHOOKS, - PERMISSION_MANAGE_OUTGOING_WEBHOOKS, - PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS, - PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS, - PERMISSION_CREATE_EMOJIS, - PERMISSION_DELETE_EMOJIS, - PERMISSION_DELETE_OTHERS_EMOJIS, - PERMISSION_REMOVE_USER_FROM_TEAM, - PERMISSION_MANAGE_TEAM, - PERMISSION_IMPORT_TEAM, - PERMISSION_VIEW_TEAM, - PERMISSION_VIEW_MEMBERS, - PERMISSION_INVITE_GUEST, - } - - ChannelScopedPermissions := []*Permission{ - PERMISSION_USE_SLASH_COMMANDS, - PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS, - PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS, - PERMISSION_MANAGE_CHANNEL_ROLES, - PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES, - PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES, - PERMISSION_CONVERT_PUBLIC_CHANNEL_TO_PRIVATE, - PERMISSION_CONVERT_PRIVATE_CHANNEL_TO_PUBLIC, - PERMISSION_DELETE_PUBLIC_CHANNEL, - PERMISSION_DELETE_PRIVATE_CHANNEL, - PERMISSION_READ_CHANNEL, - PERMISSION_READ_PUBLIC_CHANNEL_GROUPS, - PERMISSION_READ_PRIVATE_CHANNEL_GROUPS, - PERMISSION_ADD_REACTION, - PERMISSION_REMOVE_REACTION, - PERMISSION_REMOVE_OTHERS_REACTIONS, - PERMISSION_UPLOAD_FILE, - PERMISSION_CREATE_POST, - PERMISSION_CREATE_POST_PUBLIC, - PERMISSION_CREATE_POST_EPHEMERAL, - PERMISSION_EDIT_POST, - PERMISSION_EDIT_OTHERS_POSTS, - PERMISSION_DELETE_POST, - PERMISSION_DELETE_OTHERS_POSTS, - PERMISSION_USE_CHANNEL_MENTIONS, - PERMISSION_USE_GROUP_MENTIONS, - } - - DeprecatedPermissions = []*Permission{ - PERMISSION_PERMANENT_DELETE_USER, - PERMISSION_MANAGE_WEBHOOKS, - PERMISSION_MANAGE_OTHERS_WEBHOOKS, - PERMISSION_MANAGE_EMOJIS, - PERMISSION_MANAGE_OTHERS_EMOJIS, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION, - PERMISSION_SYSCONSOLE_READ_SITE, - PERMISSION_SYSCONSOLE_WRITE_SITE, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT, - PERMISSION_SYSCONSOLE_READ_REPORTING, - PERMISSION_SYSCONSOLE_WRITE_REPORTING, - PERMISSION_SYSCONSOLE_READ_ABOUT, - PERMISSION_SYSCONSOLE_WRITE_ABOUT, - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL, - PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS, - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE, - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE, - } - - AllPermissions = []*Permission{} - AllPermissions = append(AllPermissions, SystemScopedPermissionsMinusSysconsole...) - AllPermissions = append(AllPermissions, TeamScopedPermissions...) - AllPermissions = append(AllPermissions, ChannelScopedPermissions...) - AllPermissions = append(AllPermissions, SysconsoleReadPermissions...) - AllPermissions = append(AllPermissions, SysconsoleWritePermissions...) - - ChannelModeratedPermissions = []string{ - PERMISSION_CREATE_POST.Id, - "create_reactions", - "manage_members", - PERMISSION_USE_CHANNEL_MENTIONS.Id, - } - - ChannelModeratedPermissionsMap = map[string]string{ - PERMISSION_CREATE_POST.Id: ChannelModeratedPermissions[0], - PERMISSION_ADD_REACTION.Id: ChannelModeratedPermissions[1], - PERMISSION_REMOVE_REACTION.Id: ChannelModeratedPermissions[1], - PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id: ChannelModeratedPermissions[2], - PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id: ChannelModeratedPermissions[2], - PERMISSION_USE_CHANNEL_MENTIONS.Id: ChannelModeratedPermissions[3], - } -} - -func init() { - initializePermissions() -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_cluster_event.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_cluster_event.go deleted file mode 100644 index ba5c8052..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_cluster_event.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -const ( - PluginClusterEventSendTypeReliable = CLUSTER_SEND_RELIABLE - PluginClusterEventSendTypeBestEffort = CLUSTER_SEND_BEST_EFFORT -) - -// PluginClusterEvent is used to allow intra-cluster plugin communication. -type PluginClusterEvent struct { - // Id is the unique identifier for the event. - Id string - // Data is the event payload. - Data []byte -} - -// PluginClusterEventSendOptions defines some properties that apply when sending -// plugin events across a cluster. -type PluginClusterEventSendOptions struct { - // SendType defines the type of communication channel used to send the event. - SendType string - // TargetId identifies the cluster node to which the event should be sent. - // It should match the cluster id of the receiving instance. - // If empty, the event gets broadcasted to all other nodes. - TargetId string -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_event_data.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_event_data.go deleted file mode 100644 index c704c993..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_event_data.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -// PluginEventData used to notify peers about plugin changes. -type PluginEventData struct { - Id string `json:"id"` -} - -func (p *PluginEventData) ToJson() string { - b, _ := json.Marshal(p) - return string(b) -} - -func PluginEventDataFromJson(data io.Reader) PluginEventData { - var m PluginEventData - json.NewDecoder(data).Decode(&m) - return m -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_key_value.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_key_value.go deleted file mode 100644 index 73ef2d23..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_key_value.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "net/http" - "unicode/utf8" -) - -const ( - KEY_VALUE_PLUGIN_ID_MAX_RUNES = 190 - KEY_VALUE_KEY_MAX_RUNES = 50 -) - -type PluginKeyValue struct { - PluginId string `json:"plugin_id"` - Key string `json:"key" db:"PKey"` - Value []byte `json:"value" db:"PValue"` - ExpireAt int64 `json:"expire_at"` -} - -func (kv *PluginKeyValue) IsValid() *AppError { - if kv.PluginId == "" || utf8.RuneCountInString(kv.PluginId) > KEY_VALUE_PLUGIN_ID_MAX_RUNES { - return NewAppError("PluginKeyValue.IsValid", "model.plugin_key_value.is_valid.plugin_id.app_error", map[string]interface{}{"Max": KEY_VALUE_KEY_MAX_RUNES, "Min": 0}, "key="+kv.Key, http.StatusBadRequest) - } - - if kv.Key == "" || utf8.RuneCountInString(kv.Key) > KEY_VALUE_KEY_MAX_RUNES { - return NewAppError("PluginKeyValue.IsValid", "model.plugin_key_value.is_valid.key.app_error", map[string]interface{}{"Max": KEY_VALUE_KEY_MAX_RUNES, "Min": 0}, "key="+kv.Key, http.StatusBadRequest) - } - - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_kvset_options.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_kvset_options.go deleted file mode 100644 index 1d374c80..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_kvset_options.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "net/http" -) - -// PluginKVSetOptions contains information on how to store a value in the plugin KV store. -type PluginKVSetOptions struct { - Atomic bool // Only store the value if the current value matches the oldValue - OldValue []byte // The value to compare with the current value. Only used when Atomic is true - ExpireInSeconds int64 // Set an expire counter -} - -// IsValid returns nil if the chosen options are valid. -func (opt *PluginKVSetOptions) IsValid() *AppError { - if !opt.Atomic && opt.OldValue != nil { - return NewAppError( - "PluginKVSetOptions.IsValid", - "model.plugin_kvset_options.is_valid.old_value.app_error", - nil, - "", - http.StatusBadRequest, - ) - } - - return nil -} - -// NewPluginKeyValueFromOptions return a PluginKeyValue given a pluginID, a KV pair and options. -func NewPluginKeyValueFromOptions(pluginId, key string, value []byte, opt PluginKVSetOptions) (*PluginKeyValue, *AppError) { - expireAt := int64(0) - if opt.ExpireInSeconds != 0 { - expireAt = GetMillis() + (opt.ExpireInSeconds * 1000) - } - - kv := &PluginKeyValue{ - PluginId: pluginId, - Key: key, - Value: value, - ExpireAt: expireAt, - } - - return kv, nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_status.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_status.go deleted file mode 100644 index b4ba2e73..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_status.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -const ( - PluginStateNotRunning = 0 - PluginStateStarting = 1 // unused by server - PluginStateRunning = 2 - PluginStateFailedToStart = 3 - PluginStateFailedToStayRunning = 4 - PluginStateStopping = 5 // unused by server -) - -// PluginStatus provides a cluster-aware view of installed plugins. -type PluginStatus struct { - PluginId string `json:"plugin_id"` - ClusterId string `json:"cluster_id"` - PluginPath string `json:"plugin_path"` - State int `json:"state"` - Name string `json:"name"` - Description string `json:"description"` - Version string `json:"version"` -} - -type PluginStatuses []*PluginStatus - -func (m *PluginStatuses) ToJson() string { - b, _ := json.Marshal(m) - return string(b) -} - -func PluginStatusesFromJson(data io.Reader) PluginStatuses { - var m PluginStatuses - json.NewDecoder(data).Decode(&m) - return m -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_valid.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_valid.go deleted file mode 100644 index b6144513..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/plugin_valid.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "regexp" - "unicode/utf8" -) - -const ( - MinIdLength = 3 - MaxIdLength = 190 - ValidIdRegex = `^[a-zA-Z0-9-_\.]+$` -) - -// ValidId constrains the set of valid plugin identifiers: -// ^[a-zA-Z0-9-_\.]+ -var validId *regexp.Regexp - -func init() { - validId = regexp.MustCompile(ValidIdRegex) -} - -// IsValidPluginId verifies that the plugin id has a minimum length of 3, maximum length of 190, and -// contains only alphanumeric characters, dashes, underscores and periods. -// -// These constraints are necessary since the plugin id is used as part of a filesystem path. -func IsValidPluginId(id string) bool { - if utf8.RuneCountInString(id) < MinIdLength { - return false - } - - if utf8.RuneCountInString(id) > MaxIdLength { - return false - } - - return validId.MatchString(id) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/plugins_response.go b/vendor/github.com/mattermost/mattermost-server/v5/model/plugins_response.go deleted file mode 100644 index 421ee2f5..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/plugins_response.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type PluginInfo struct { - Manifest -} - -type PluginsResponse struct { - Active []*PluginInfo `json:"active"` - Inactive []*PluginInfo `json:"inactive"` -} - -func (m *PluginsResponse) ToJson() string { - b, _ := json.Marshal(m) - return string(b) -} - -func PluginsResponseFromJson(data io.Reader) *PluginsResponse { - var m *PluginsResponse - json.NewDecoder(data).Decode(&m) - return m -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/post.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post.go deleted file mode 100644 index b7dff5bc..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/post.go +++ /dev/null @@ -1,751 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "errors" - "io" - "net/http" - "regexp" - "sort" - "strings" - "sync" - "unicode/utf8" - - "github.com/mattermost/mattermost-server/v5/shared/markdown" -) - -const ( - POST_SYSTEM_MESSAGE_PREFIX = "system_" - POST_DEFAULT = "" - POST_SLACK_ATTACHMENT = "slack_attachment" - POST_SYSTEM_GENERIC = "system_generic" - POST_JOIN_LEAVE = "system_join_leave" // Deprecated, use POST_JOIN_CHANNEL or POST_LEAVE_CHANNEL instead - POST_JOIN_CHANNEL = "system_join_channel" - POST_GUEST_JOIN_CHANNEL = "system_guest_join_channel" - POST_LEAVE_CHANNEL = "system_leave_channel" - POST_JOIN_TEAM = "system_join_team" - POST_LEAVE_TEAM = "system_leave_team" - POST_AUTO_RESPONDER = "system_auto_responder" - POST_ADD_REMOVE = "system_add_remove" // Deprecated, use POST_ADD_TO_CHANNEL or POST_REMOVE_FROM_CHANNEL instead - POST_ADD_TO_CHANNEL = "system_add_to_channel" - POST_ADD_GUEST_TO_CHANNEL = "system_add_guest_to_chan" - POST_REMOVE_FROM_CHANNEL = "system_remove_from_channel" - POST_MOVE_CHANNEL = "system_move_channel" - POST_ADD_TO_TEAM = "system_add_to_team" - POST_REMOVE_FROM_TEAM = "system_remove_from_team" - POST_HEADER_CHANGE = "system_header_change" - POST_DISPLAYNAME_CHANGE = "system_displayname_change" - POST_CONVERT_CHANNEL = "system_convert_channel" - POST_PURPOSE_CHANGE = "system_purpose_change" - POST_CHANNEL_DELETED = "system_channel_deleted" - POST_CHANNEL_RESTORED = "system_channel_restored" - POST_EPHEMERAL = "system_ephemeral" - POST_CHANGE_CHANNEL_PRIVACY = "system_change_chan_privacy" - POST_ADD_BOT_TEAMS_CHANNELS = "add_bot_teams_channels" - POST_FILEIDS_MAX_RUNES = 300 - POST_FILENAMES_MAX_RUNES = 4000 - POST_HASHTAGS_MAX_RUNES = 1000 - POST_MESSAGE_MAX_RUNES_V1 = 4000 - POST_MESSAGE_MAX_BYTES_V2 = 65535 // Maximum size of a TEXT column in MySQL - POST_MESSAGE_MAX_RUNES_V2 = POST_MESSAGE_MAX_BYTES_V2 / 4 // Assume a worst-case representation - POST_PROPS_MAX_RUNES = 8000 - POST_PROPS_MAX_USER_RUNES = POST_PROPS_MAX_RUNES - 400 // Leave some room for system / pre-save modifications - POST_CUSTOM_TYPE_PREFIX = "custom_" - POST_ME = "me" - PROPS_ADD_CHANNEL_MEMBER = "add_channel_member" - - POST_PROPS_ADDED_USER_ID = "addedUserId" - POST_PROPS_DELETE_BY = "deleteBy" - POST_PROPS_OVERRIDE_ICON_URL = "override_icon_url" - POST_PROPS_OVERRIDE_ICON_EMOJI = "override_icon_emoji" - - POST_PROPS_MENTION_HIGHLIGHT_DISABLED = "mentionHighlightDisabled" - POST_PROPS_GROUP_HIGHLIGHT_DISABLED = "disable_group_highlight" - POST_SYSTEM_WARN_METRIC_STATUS = "warn_metric_status" -) - -var AT_MENTION_PATTEN = regexp.MustCompile(`\B@`) - -type Post struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - EditAt int64 `json:"edit_at"` - DeleteAt int64 `json:"delete_at"` - IsPinned bool `json:"is_pinned"` - UserId string `json:"user_id"` - ChannelId string `json:"channel_id"` - RootId string `json:"root_id"` - ParentId string `json:"parent_id"` - OriginalId string `json:"original_id"` - - Message string `json:"message"` - // MessageSource will contain the message as submitted by the user if Message has been modified - // by Mattermost for presentation (e.g if an image proxy is being used). It should be used to - // populate edit boxes if present. - MessageSource string `json:"message_source,omitempty" db:"-"` - - Type string `json:"type"` - propsMu sync.RWMutex `db:"-"` // Unexported mutex used to guard Post.Props. - Props StringInterface `json:"props"` // Deprecated: use GetProps() - Hashtags string `json:"hashtags"` - Filenames StringArray `json:"filenames,omitempty"` // Deprecated, do not use this field any more - FileIds StringArray `json:"file_ids,omitempty"` - PendingPostId string `json:"pending_post_id" db:"-"` - HasReactions bool `json:"has_reactions,omitempty"` - RemoteId *string `json:"remote_id,omitempty"` - - // Transient data populated before sending a post to the client - ReplyCount int64 `json:"reply_count" db:"-"` - LastReplyAt int64 `json:"last_reply_at" db:"-"` - Participants []*User `json:"participants" db:"-"` - IsFollowing *bool `json:"is_following,omitempty" db:"-"` // for root posts in collapsed thread mode indicates if the current user is following this thread - Metadata *PostMetadata `json:"metadata,omitempty" db:"-"` -} - -type PostEphemeral struct { - UserID string `json:"user_id"` - Post *Post `json:"post"` -} - -type PostPatch struct { - IsPinned *bool `json:"is_pinned"` - Message *string `json:"message"` - Props *StringInterface `json:"props"` - FileIds *StringArray `json:"file_ids"` - HasReactions *bool `json:"has_reactions"` -} - -type SearchParameter struct { - Terms *string `json:"terms"` - IsOrSearch *bool `json:"is_or_search"` - TimeZoneOffset *int `json:"time_zone_offset"` - Page *int `json:"page"` - PerPage *int `json:"per_page"` - IncludeDeletedChannels *bool `json:"include_deleted_channels"` -} - -type AnalyticsPostCountsOptions struct { - TeamId string - BotsOnly bool - YesterdayOnly bool -} - -func (o *PostPatch) WithRewrittenImageURLs(f func(string) string) *PostPatch { - copy := *o - if copy.Message != nil { - *copy.Message = RewriteImageURLs(*o.Message, f) - } - return © -} - -type PostForExport struct { - Post - TeamName string - ChannelName string - Username string - ReplyCount int -} - -type DirectPostForExport struct { - Post - User string - ChannelMembers *[]string -} - -type ReplyForExport struct { - Post - Username string -} - -type PostForIndexing struct { - Post - TeamId string `json:"team_id"` - ParentCreateAt *int64 `json:"parent_create_at"` -} - -type FileForIndexing struct { - FileInfo - ChannelId string `json:"channel_id"` - Content string `json:"content"` -} - -// ShallowCopy is an utility function to shallow copy a Post to the given -// destination without touching the internal RWMutex. -func (o *Post) ShallowCopy(dst *Post) error { - if dst == nil { - return errors.New("dst cannot be nil") - } - o.propsMu.RLock() - defer o.propsMu.RUnlock() - dst.propsMu.Lock() - defer dst.propsMu.Unlock() - dst.Id = o.Id - dst.CreateAt = o.CreateAt - dst.UpdateAt = o.UpdateAt - dst.EditAt = o.EditAt - dst.DeleteAt = o.DeleteAt - dst.IsPinned = o.IsPinned - dst.UserId = o.UserId - dst.ChannelId = o.ChannelId - dst.RootId = o.RootId - dst.ParentId = o.ParentId - dst.OriginalId = o.OriginalId - dst.Message = o.Message - dst.MessageSource = o.MessageSource - dst.Type = o.Type - dst.Props = o.Props - dst.Hashtags = o.Hashtags - dst.Filenames = o.Filenames - dst.FileIds = o.FileIds - dst.PendingPostId = o.PendingPostId - dst.HasReactions = o.HasReactions - dst.ReplyCount = o.ReplyCount - dst.Participants = o.Participants - dst.LastReplyAt = o.LastReplyAt - dst.Metadata = o.Metadata - if o.IsFollowing != nil { - dst.IsFollowing = NewBool(*o.IsFollowing) - } - dst.RemoteId = o.RemoteId - return nil -} - -// Clone shallowly copies the post and returns the copy. -func (o *Post) Clone() *Post { - copy := &Post{} - o.ShallowCopy(copy) - return copy -} - -func (o *Post) ToJson() string { - copy := o.Clone() - copy.StripActionIntegrations() - b, _ := json.Marshal(copy) - return string(b) -} - -func (o *Post) ToUnsanitizedJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -type GetPostsSinceOptions struct { - UserId string - ChannelId string - Time int64 - SkipFetchThreads bool - CollapsedThreads bool - CollapsedThreadsExtended bool - SortAscending bool -} - -type GetPostsSinceForSyncCursor struct { - LastPostUpdateAt int64 - LastPostId string -} - -type GetPostsSinceForSyncOptions struct { - ChannelId string - ExcludeRemoteId string - IncludeDeleted bool -} - -type GetPostsOptions struct { - UserId string - ChannelId string - PostId string - Page int - PerPage int - SkipFetchThreads bool - CollapsedThreads bool - CollapsedThreadsExtended bool -} - -func PostFromJson(data io.Reader) *Post { - var o *Post - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *Post) Etag() string { - return Etag(o.Id, o.UpdateAt) -} - -func (o *Post) IsValid(maxPostSize int) *AppError { - if !IsValidId(o.Id) { - return NewAppError("Post.IsValid", "model.post.is_valid.id.app_error", nil, "", http.StatusBadRequest) - } - - if o.CreateAt == 0 { - return NewAppError("Post.IsValid", "model.post.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if o.UpdateAt == 0 { - return NewAppError("Post.IsValid", "model.post.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if !IsValidId(o.UserId) { - return NewAppError("Post.IsValid", "model.post.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidId(o.ChannelId) { - return NewAppError("Post.IsValid", "model.post.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest) - } - - if !(IsValidId(o.RootId) || o.RootId == "") { - return NewAppError("Post.IsValid", "model.post.is_valid.root_id.app_error", nil, "", http.StatusBadRequest) - } - - if !(IsValidId(o.ParentId) || o.ParentId == "") { - return NewAppError("Post.IsValid", "model.post.is_valid.parent_id.app_error", nil, "", http.StatusBadRequest) - } - - if len(o.ParentId) == 26 && o.RootId == "" { - return NewAppError("Post.IsValid", "model.post.is_valid.root_parent.app_error", nil, "", http.StatusBadRequest) - } - - if !(len(o.OriginalId) == 26 || o.OriginalId == "") { - return NewAppError("Post.IsValid", "model.post.is_valid.original_id.app_error", nil, "", http.StatusBadRequest) - } - - if utf8.RuneCountInString(o.Message) > maxPostSize { - return NewAppError("Post.IsValid", "model.post.is_valid.msg.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if utf8.RuneCountInString(o.Hashtags) > POST_HASHTAGS_MAX_RUNES { - return NewAppError("Post.IsValid", "model.post.is_valid.hashtags.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - switch o.Type { - case - POST_DEFAULT, - POST_SYSTEM_GENERIC, - POST_JOIN_LEAVE, - POST_AUTO_RESPONDER, - POST_ADD_REMOVE, - POST_JOIN_CHANNEL, - POST_GUEST_JOIN_CHANNEL, - POST_LEAVE_CHANNEL, - POST_JOIN_TEAM, - POST_LEAVE_TEAM, - POST_ADD_TO_CHANNEL, - POST_ADD_GUEST_TO_CHANNEL, - POST_REMOVE_FROM_CHANNEL, - POST_MOVE_CHANNEL, - POST_ADD_TO_TEAM, - POST_REMOVE_FROM_TEAM, - POST_SLACK_ATTACHMENT, - POST_HEADER_CHANGE, - POST_PURPOSE_CHANGE, - POST_DISPLAYNAME_CHANGE, - POST_CONVERT_CHANNEL, - POST_CHANNEL_DELETED, - POST_CHANNEL_RESTORED, - POST_CHANGE_CHANNEL_PRIVACY, - POST_ME, - POST_ADD_BOT_TEAMS_CHANNELS, - POST_SYSTEM_WARN_METRIC_STATUS: - default: - if !strings.HasPrefix(o.Type, POST_CUSTOM_TYPE_PREFIX) { - return NewAppError("Post.IsValid", "model.post.is_valid.type.app_error", nil, "id="+o.Type, http.StatusBadRequest) - } - } - - if utf8.RuneCountInString(ArrayToJson(o.Filenames)) > POST_FILENAMES_MAX_RUNES { - return NewAppError("Post.IsValid", "model.post.is_valid.filenames.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if utf8.RuneCountInString(ArrayToJson(o.FileIds)) > POST_FILEIDS_MAX_RUNES { - return NewAppError("Post.IsValid", "model.post.is_valid.file_ids.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if utf8.RuneCountInString(StringInterfaceToJson(o.GetProps())) > POST_PROPS_MAX_RUNES { - return NewAppError("Post.IsValid", "model.post.is_valid.props.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - return nil -} - -func (o *Post) SanitizeProps() { - if o == nil { - return - } - membersToSanitize := []string{ - PROPS_ADD_CHANNEL_MEMBER, - } - - for _, member := range membersToSanitize { - if _, ok := o.GetProps()[member]; ok { - o.DelProp(member) - } - } - for _, p := range o.Participants { - p.Sanitize(map[string]bool{}) - } -} - -func (o *Post) PreSave() { - if o.Id == "" { - o.Id = NewId() - } - - o.OriginalId = "" - - if o.CreateAt == 0 { - o.CreateAt = GetMillis() - } - - o.UpdateAt = o.CreateAt - o.PreCommit() -} - -func (o *Post) PreCommit() { - if o.GetProps() == nil { - o.SetProps(make(map[string]interface{})) - } - - if o.Filenames == nil { - o.Filenames = []string{} - } - - if o.FileIds == nil { - o.FileIds = []string{} - } - - o.GenerateActionIds() - - // There's a rare bug where the client sends up duplicate FileIds so protect against that - o.FileIds = RemoveDuplicateStrings(o.FileIds) -} - -func (o *Post) MakeNonNil() { - if o.GetProps() == nil { - o.SetProps(make(map[string]interface{})) - } -} - -func (o *Post) DelProp(key string) { - o.propsMu.Lock() - defer o.propsMu.Unlock() - propsCopy := make(map[string]interface{}, len(o.Props)-1) - for k, v := range o.Props { - propsCopy[k] = v - } - delete(propsCopy, key) - o.Props = propsCopy -} - -func (o *Post) AddProp(key string, value interface{}) { - o.propsMu.Lock() - defer o.propsMu.Unlock() - propsCopy := make(map[string]interface{}, len(o.Props)+1) - for k, v := range o.Props { - propsCopy[k] = v - } - propsCopy[key] = value - o.Props = propsCopy -} - -func (o *Post) GetProps() StringInterface { - o.propsMu.RLock() - defer o.propsMu.RUnlock() - return o.Props -} - -func (o *Post) SetProps(props StringInterface) { - o.propsMu.Lock() - defer o.propsMu.Unlock() - o.Props = props -} - -func (o *Post) GetProp(key string) interface{} { - o.propsMu.RLock() - defer o.propsMu.RUnlock() - return o.Props[key] -} - -func (o *Post) IsSystemMessage() bool { - return len(o.Type) >= len(POST_SYSTEM_MESSAGE_PREFIX) && o.Type[:len(POST_SYSTEM_MESSAGE_PREFIX)] == POST_SYSTEM_MESSAGE_PREFIX -} - -// IsRemote returns true if the post originated on a remote cluster. -func (o *Post) IsRemote() bool { - return o.RemoteId != nil && *o.RemoteId != "" -} - -// GetRemoteID safely returns the remoteID or empty string if not remote. -func (o *Post) GetRemoteID() string { - if o.RemoteId != nil { - return *o.RemoteId - } - return "" -} - -func (o *Post) IsJoinLeaveMessage() bool { - return o.Type == POST_JOIN_LEAVE || - o.Type == POST_ADD_REMOVE || - o.Type == POST_JOIN_CHANNEL || - o.Type == POST_LEAVE_CHANNEL || - o.Type == POST_JOIN_TEAM || - o.Type == POST_LEAVE_TEAM || - o.Type == POST_ADD_TO_CHANNEL || - o.Type == POST_REMOVE_FROM_CHANNEL || - o.Type == POST_ADD_TO_TEAM || - o.Type == POST_REMOVE_FROM_TEAM -} - -func (o *Post) Patch(patch *PostPatch) { - if patch.IsPinned != nil { - o.IsPinned = *patch.IsPinned - } - - if patch.Message != nil { - o.Message = *patch.Message - } - - if patch.Props != nil { - newProps := *patch.Props - o.SetProps(newProps) - } - - if patch.FileIds != nil { - o.FileIds = *patch.FileIds - } - - if patch.HasReactions != nil { - o.HasReactions = *patch.HasReactions - } -} - -func (o *PostPatch) ToJson() string { - b, err := json.Marshal(o) - if err != nil { - return "" - } - - return string(b) -} - -func PostPatchFromJson(data io.Reader) *PostPatch { - decoder := json.NewDecoder(data) - var post PostPatch - err := decoder.Decode(&post) - if err != nil { - return nil - } - - return &post -} - -func (o *SearchParameter) SearchParameterToJson() string { - b, err := json.Marshal(o) - if err != nil { - return "" - } - - return string(b) -} - -func SearchParameterFromJson(data io.Reader) (*SearchParameter, error) { - decoder := json.NewDecoder(data) - var searchParam SearchParameter - if err := decoder.Decode(&searchParam); err != nil { - return nil, err - } - - return &searchParam, nil -} - -func (o *Post) ChannelMentions() []string { - return ChannelMentions(o.Message) -} - -// DisableMentionHighlights disables a posts mention highlighting and returns the first channel mention that was present in the message. -func (o *Post) DisableMentionHighlights() string { - mention, hasMentions := findAtChannelMention(o.Message) - if hasMentions { - o.AddProp(POST_PROPS_MENTION_HIGHLIGHT_DISABLED, true) - } - return mention -} - -// DisableMentionHighlights disables mention highlighting for a post patch if required. -func (o *PostPatch) DisableMentionHighlights() { - if o.Message == nil { - return - } - if _, hasMentions := findAtChannelMention(*o.Message); hasMentions { - if o.Props == nil { - o.Props = &StringInterface{} - } - (*o.Props)[POST_PROPS_MENTION_HIGHLIGHT_DISABLED] = true - } -} - -func findAtChannelMention(message string) (mention string, found bool) { - re := regexp.MustCompile(`(?i)\B@(channel|all|here)\b`) - matched := re.FindStringSubmatch(message) - if found = (len(matched) > 0); found { - mention = strings.ToLower(matched[0]) - } - return -} - -func (o *Post) Attachments() []*SlackAttachment { - if attachments, ok := o.GetProp("attachments").([]*SlackAttachment); ok { - return attachments - } - var ret []*SlackAttachment - if attachments, ok := o.GetProp("attachments").([]interface{}); ok { - for _, attachment := range attachments { - if enc, err := json.Marshal(attachment); err == nil { - var decoded SlackAttachment - if json.Unmarshal(enc, &decoded) == nil { - // Ignoring nil actions - i := 0 - for _, action := range decoded.Actions { - if action != nil { - decoded.Actions[i] = action - i++ - } - } - decoded.Actions = decoded.Actions[:i] - - // Ignoring nil fields - i = 0 - for _, field := range decoded.Fields { - if field != nil { - decoded.Fields[i] = field - i++ - } - } - decoded.Fields = decoded.Fields[:i] - ret = append(ret, &decoded) - } - } - } - } - return ret -} - -func (o *Post) AttachmentsEqual(input *Post) bool { - attachments := o.Attachments() - inputAttachments := input.Attachments() - - if len(attachments) != len(inputAttachments) { - return false - } - - for i := range attachments { - if !attachments[i].Equals(inputAttachments[i]) { - return false - } - } - - return true -} - -var markdownDestinationEscaper = strings.NewReplacer( - `\`, `\\`, - `<`, `\<`, - `>`, `\>`, - `(`, `\(`, - `)`, `\)`, -) - -// WithRewrittenImageURLs returns a new shallow copy of the post where the message has been -// rewritten via RewriteImageURLs. -func (o *Post) WithRewrittenImageURLs(f func(string) string) *Post { - copy := o.Clone() - copy.Message = RewriteImageURLs(o.Message, f) - if copy.MessageSource == "" && copy.Message != o.Message { - copy.MessageSource = o.Message - } - return copy -} - -func (o *PostEphemeral) ToUnsanitizedJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -// RewriteImageURLs takes a message and returns a copy that has all of the image URLs replaced -// according to the function f. For each image URL, f will be invoked, and the resulting markdown -// will contain the URL returned by that invocation instead. -// -// Image URLs are destination URLs used in inline images or reference definitions that are used -// anywhere in the input markdown as an image. -func RewriteImageURLs(message string, f func(string) string) string { - if !strings.Contains(message, "![") { - return message - } - - var ranges []markdown.Range - - markdown.Inspect(message, func(blockOrInline interface{}) bool { - switch v := blockOrInline.(type) { - case *markdown.ReferenceImage: - ranges = append(ranges, v.ReferenceDefinition.RawDestination) - case *markdown.InlineImage: - ranges = append(ranges, v.RawDestination) - default: - return true - } - return true - }) - - if ranges == nil { - return message - } - - sort.Slice(ranges, func(i, j int) bool { - return ranges[i].Position < ranges[j].Position - }) - - copyRanges := make([]markdown.Range, 0, len(ranges)) - urls := make([]string, 0, len(ranges)) - resultLength := len(message) - - start := 0 - for i, r := range ranges { - switch { - case i == 0: - case r.Position != ranges[i-1].Position: - start = ranges[i-1].End - default: - continue - } - original := message[r.Position:r.End] - replacement := markdownDestinationEscaper.Replace(f(markdown.Unescape(original))) - resultLength += len(replacement) - len(original) - copyRanges = append(copyRanges, markdown.Range{Position: start, End: r.Position}) - urls = append(urls, replacement) - } - - result := make([]byte, resultLength) - - offset := 0 - for i, r := range copyRanges { - offset += copy(result[offset:], message[r.Position:r.End]) - offset += copy(result[offset:], urls[i]) - } - copy(result[offset:], message[ranges[len(ranges)-1].End:]) - - return string(result) -} - -func (o *Post) IsFromOAuthBot() bool { - props := o.GetProps() - return props["from_webhook"] == "true" && props["override_username"] != "" -} - -func (o *Post) ToNilIfInvalid() *Post { - if o.Id == "" { - return nil - } - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/post_embed.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post_embed.go deleted file mode 100644 index 5c6efec1..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/post_embed.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -const ( - POST_EMBED_IMAGE PostEmbedType = "image" - POST_EMBED_MESSAGE_ATTACHMENT PostEmbedType = "message_attachment" - POST_EMBED_OPENGRAPH PostEmbedType = "opengraph" - POST_EMBED_LINK PostEmbedType = "link" -) - -type PostEmbedType string - -type PostEmbed struct { - Type PostEmbedType `json:"type"` - - // The URL of the embedded content. Used for image and OpenGraph embeds. - URL string `json:"url,omitempty"` - - // Any additional data for the embedded content. Only used for OpenGraph embeds. - Data interface{} `json:"data,omitempty"` -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/post_list.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post_list.go deleted file mode 100644 index ba84f749..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/post_list.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "sort" -) - -type PostList struct { - Order []string `json:"order"` - Posts map[string]*Post `json:"posts"` - NextPostId string `json:"next_post_id"` - PrevPostId string `json:"prev_post_id"` -} - -func NewPostList() *PostList { - return &PostList{ - Order: make([]string, 0), - Posts: make(map[string]*Post), - NextPostId: "", - PrevPostId: "", - } -} - -func (o *PostList) ToSlice() []*Post { - var posts []*Post - - if l := len(o.Posts); l > 0 { - posts = make([]*Post, 0, l) - } - - for _, id := range o.Order { - posts = append(posts, o.Posts[id]) - } - return posts -} - -func (o *PostList) WithRewrittenImageURLs(f func(string) string) *PostList { - copy := *o - copy.Posts = make(map[string]*Post) - for id, post := range o.Posts { - copy.Posts[id] = post.WithRewrittenImageURLs(f) - } - return © -} - -func (o *PostList) StripActionIntegrations() { - posts := o.Posts - o.Posts = make(map[string]*Post) - for id, post := range posts { - pcopy := post.Clone() - pcopy.StripActionIntegrations() - o.Posts[id] = pcopy - } -} - -func (o *PostList) ToJson() string { - copy := *o - copy.StripActionIntegrations() - b, err := json.Marshal(©) - if err != nil { - return "" - } - return string(b) -} - -func (o *PostList) MakeNonNil() { - if o.Order == nil { - o.Order = make([]string, 0) - } - - if o.Posts == nil { - o.Posts = make(map[string]*Post) - } - - for _, v := range o.Posts { - v.MakeNonNil() - } -} - -func (o *PostList) AddOrder(id string) { - - if o.Order == nil { - o.Order = make([]string, 0, 128) - } - - o.Order = append(o.Order, id) -} - -func (o *PostList) AddPost(post *Post) { - - if o.Posts == nil { - o.Posts = make(map[string]*Post) - } - - o.Posts[post.Id] = post -} - -func (o *PostList) UniqueOrder() { - keys := make(map[string]bool) - order := []string{} - for _, postId := range o.Order { - if _, value := keys[postId]; !value { - keys[postId] = true - order = append(order, postId) - } - } - - o.Order = order -} - -func (o *PostList) Extend(other *PostList) { - for postId := range other.Posts { - o.AddPost(other.Posts[postId]) - } - - for _, postId := range other.Order { - o.AddOrder(postId) - } - - o.UniqueOrder() -} - -func (o *PostList) SortByCreateAt() { - sort.Slice(o.Order, func(i, j int) bool { - return o.Posts[o.Order[i]].CreateAt > o.Posts[o.Order[j]].CreateAt - }) -} - -func (o *PostList) Etag() string { - - id := "0" - var t int64 = 0 - - for _, v := range o.Posts { - if v.UpdateAt > t { - t = v.UpdateAt - id = v.Id - } else if v.UpdateAt == t && v.Id > id { - t = v.UpdateAt - id = v.Id - } - } - - orderId := "" - if len(o.Order) > 0 { - orderId = o.Order[0] - } - - return Etag(orderId, id, t) -} - -func (o *PostList) IsChannelId(channelId string) bool { - for _, v := range o.Posts { - if v.ChannelId != channelId { - return false - } - } - - return true -} - -func PostListFromJson(data io.Reader) *PostList { - var o *PostList - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/post_metadata.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post_metadata.go deleted file mode 100644 index 7b0687ca..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/post_metadata.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" -) - -type PostMetadata struct { - // Embeds holds information required to render content embedded in the post. This includes the OpenGraph metadata - // for links in the post. - Embeds []*PostEmbed `json:"embeds,omitempty"` - - // Emojis holds all custom emojis used in the post or used in reaction to the post. - Emojis []*Emoji `json:"emojis,omitempty"` - - // Files holds information about the file attachments on the post. - Files []*FileInfo `json:"files,omitempty"` - - // Images holds the dimensions of all external images in the post as a map of the image URL to its diemsnions. - // This includes image embeds (when the message contains a plaintext link to an image), Markdown images, images - // contained in the OpenGraph metadata, and images contained in message attachments. It does not contain - // the dimensions of any file attachments as those are stored in FileInfos. - Images map[string]*PostImage `json:"images,omitempty"` - - // Reactions holds reactions made to the post. - Reactions []*Reaction `json:"reactions,omitempty"` -} - -type PostImage struct { - Width int `json:"width"` - Height int `json:"height"` - - // Format is the name of the image format as used by image/go such as "png", "gif", or "jpeg". - Format string `json:"format"` - - // FrameCount stores the number of frames in this image, if it is an animated gif. It will be 0 for other formats. - FrameCount int `json:"frame_count"` -} - -func (o *PostImage) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/post_search_results.go b/vendor/github.com/mattermost/mattermost-server/v5/model/post_search_results.go deleted file mode 100644 index fc9ba083..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/post_search_results.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type PostSearchMatches map[string][]string - -type PostSearchResults struct { - *PostList - Matches PostSearchMatches `json:"matches"` -} - -func MakePostSearchResults(posts *PostList, matches PostSearchMatches) *PostSearchResults { - return &PostSearchResults{ - posts, - matches, - } -} - -func (o *PostSearchResults) ToJson() string { - copy := *o - copy.PostList.StripActionIntegrations() - b, err := json.Marshal(©) - if err != nil { - return "" - } - return string(b) -} - -func PostSearchResultsFromJson(data io.Reader) *PostSearchResults { - var o *PostSearchResults - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/preference.go b/vendor/github.com/mattermost/mattermost-server/v5/model/preference.go deleted file mode 100644 index ee0d21aa..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/preference.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" - "regexp" - "strings" - "unicode/utf8" -) - -const ( - PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW = "direct_channel_show" - PREFERENCE_CATEGORY_GROUP_CHANNEL_SHOW = "group_channel_show" - PREFERENCE_CATEGORY_TUTORIAL_STEPS = "tutorial_step" - PREFERENCE_CATEGORY_ADVANCED_SETTINGS = "advanced_settings" - PREFERENCE_CATEGORY_FLAGGED_POST = "flagged_post" - PREFERENCE_CATEGORY_FAVORITE_CHANNEL = "favorite_channel" - PREFERENCE_CATEGORY_SIDEBAR_SETTINGS = "sidebar_settings" - - PREFERENCE_CATEGORY_DISPLAY_SETTINGS = "display_settings" - PREFERENCE_NAME_COLLAPSED_THREADS_ENABLED = "collapsed_reply_threads" - PREFERENCE_NAME_CHANNEL_DISPLAY_MODE = "channel_display_mode" - PREFERENCE_NAME_COLLAPSE_SETTING = "collapse_previews" - PREFERENCE_NAME_MESSAGE_DISPLAY = "message_display" - PREFERENCE_NAME_NAME_FORMAT = "name_format" - PREFERENCE_NAME_USE_MILITARY_TIME = "use_military_time" - PREFERENCE_RECOMMENDED_NEXT_STEPS = "recommended_next_steps" - - PREFERENCE_CATEGORY_THEME = "theme" - // the name for theme props is the team id - - PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP = "oauth_app" - // the name for oauth_app is the client_id and value is the current scope - - PREFERENCE_CATEGORY_LAST = "last" - PREFERENCE_NAME_LAST_CHANNEL = "channel" - PREFERENCE_NAME_LAST_TEAM = "team" - - PREFERENCE_CATEGORY_CUSTOM_STATUS = "custom_status" - PREFERENCE_NAME_RECENT_CUSTOM_STATUSES = "recent_custom_statuses" - PREFERENCE_NAME_CUSTOM_STATUS_TUTORIAL_STATE = "custom_status_tutorial_state" - - PREFERENCE_CUSTOM_STATUS_MODAL_VIEWED = "custom_status_modal_viewed" - - PREFERENCE_CATEGORY_NOTIFICATIONS = "notifications" - PREFERENCE_NAME_EMAIL_INTERVAL = "email_interval" - - PREFERENCE_EMAIL_INTERVAL_NO_BATCHING_SECONDS = "30" // the "immediate" setting is actually 30s - PREFERENCE_EMAIL_INTERVAL_BATCHING_SECONDS = "900" // fifteen minutes is 900 seconds - PREFERENCE_EMAIL_INTERVAL_IMMEDIATELY = "immediately" - PREFERENCE_EMAIL_INTERVAL_FIFTEEN = "fifteen" - PREFERENCE_EMAIL_INTERVAL_FIFTEEN_AS_SECONDS = "900" - PREFERENCE_EMAIL_INTERVAL_HOUR = "hour" - PREFERENCE_EMAIL_INTERVAL_HOUR_AS_SECONDS = "3600" -) - -type Preference struct { - UserId string `json:"user_id"` - Category string `json:"category"` - Name string `json:"name"` - Value string `json:"value"` -} - -func (o *Preference) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func PreferenceFromJson(data io.Reader) *Preference { - var o *Preference - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *Preference) IsValid() *AppError { - if !IsValidId(o.UserId) { - return NewAppError("Preference.IsValid", "model.preference.is_valid.id.app_error", nil, "user_id="+o.UserId, http.StatusBadRequest) - } - - if o.Category == "" || len(o.Category) > 32 { - return NewAppError("Preference.IsValid", "model.preference.is_valid.category.app_error", nil, "category="+o.Category, http.StatusBadRequest) - } - - if len(o.Name) > 32 { - return NewAppError("Preference.IsValid", "model.preference.is_valid.name.app_error", nil, "name="+o.Name, http.StatusBadRequest) - } - - if utf8.RuneCountInString(o.Value) > 2000 { - return NewAppError("Preference.IsValid", "model.preference.is_valid.value.app_error", nil, "value="+o.Value, http.StatusBadRequest) - } - - if o.Category == PREFERENCE_CATEGORY_THEME { - var unused map[string]string - if err := json.NewDecoder(strings.NewReader(o.Value)).Decode(&unused); err != nil { - return NewAppError("Preference.IsValid", "model.preference.is_valid.theme.app_error", nil, "value="+o.Value, http.StatusBadRequest) - } - } - - return nil -} - -func (o *Preference) PreUpdate() { - if o.Category == PREFERENCE_CATEGORY_THEME { - // decode the value of theme (a map of strings to string) and eliminate any invalid values - var props map[string]string - if err := json.NewDecoder(strings.NewReader(o.Value)).Decode(&props); err != nil { - // just continue, the invalid preference value should get caught by IsValid before saving - return - } - - colorPattern := regexp.MustCompile(`^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$`) - - // blank out any invalid theme values - for name, value := range props { - if name == "image" || name == "type" || name == "codeTheme" { - continue - } - - if !colorPattern.MatchString(value) { - props[name] = "#ffffff" - } - } - - if b, err := json.Marshal(props); err == nil { - o.Value = string(b) - } - } -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/preferences.go b/vendor/github.com/mattermost/mattermost-server/v5/model/preferences.go deleted file mode 100644 index c2d24865..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/preferences.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type Preferences []Preference - -func (o *Preferences) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func PreferencesFromJson(data io.Reader) (Preferences, error) { - decoder := json.NewDecoder(data) - var o Preferences - err := decoder.Decode(&o) - if err != nil { - return nil, err - } - return o, nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/product_notices.go b/vendor/github.com/mattermost/mattermost-server/v5/model/product_notices.go deleted file mode 100644 index 455ae475..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/product_notices.go +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - - "github.com/pkg/errors" -) - -type ProductNotices []ProductNotice - -func (r *ProductNotices) Marshal() ([]byte, error) { - return json.Marshal(r) -} - -func UnmarshalProductNotices(data []byte) (ProductNotices, error) { - var r ProductNotices - err := json.Unmarshal(data, &r) - return r, err -} - -// List of product notices. Order is important and is used to resolve priorities. -// Each notice will only be show if conditions are met. -type ProductNotice struct { - Conditions Conditions `json:"conditions"` - ID string `json:"id"` // Unique identifier for this notice. Can be a running number. Used for storing 'viewed'; state on the server. - LocalizedMessages map[string]NoticeMessageInternal `json:"localizedMessages"` // Notice message data, organized by locale.; Example:; "localizedMessages": {; "en": { "title": "English", description: "English description"},; "frFR": { "title": "Frances", description: "French description"}; } - Repeatable *bool `json:"repeatable,omitempty"` // Configurable flag if the notice should reappear after it’s seen and dismissed -} - -func (n *ProductNotice) SysAdminOnly() bool { - return n.Conditions.Audience != nil && *n.Conditions.Audience == NoticeAudience_Sysadmin -} - -func (n *ProductNotice) TeamAdminOnly() bool { - return n.Conditions.Audience != nil && *n.Conditions.Audience == NoticeAudience_TeamAdmin -} - -type Conditions struct { - Audience *NoticeAudience `json:"audience,omitempty"` - ClientType *NoticeClientType `json:"clientType,omitempty"` // Only show the notice on specific clients. Defaults to 'all' - DesktopVersion []string `json:"desktopVersion,omitempty"` // What desktop client versions does this notice apply to.; Format: semver ranges (https://devhints.io/semver); Example: [">=1.2.3 < ~2.4.x"]; Example: ["<v5.19", "v5.20-v5.22"] - DisplayDate *string `json:"displayDate,omitempty"` // When to display the notice.; Examples:; "2020-03-01T00:00:00Z" - show on specified date; ">= 2020-03-01T00:00:00Z" - show after specified date; "< 2020-03-01T00:00:00Z" - show before the specified date; "> 2020-03-01T00:00:00Z <= 2020-04-01T00:00:00Z" - show only between the specified dates - InstanceType *NoticeInstanceType `json:"instanceType,omitempty"` - MobileVersion []string `json:"mobileVersion,omitempty"` // What mobile client versions does this notice apply to.; Format: semver ranges (https://devhints.io/semver); Example: [">=1.2.3 < ~2.4.x"]; Example: ["<v5.19", "v5.20-v5.22"] - NumberOfPosts *int64 `json:"numberOfPosts,omitempty"` // Only show the notice when server has more than specified number of posts - NumberOfUsers *int64 `json:"numberOfUsers,omitempty"` // Only show the notice when server has more than specified number of users - ServerConfig map[string]interface{} `json:"serverConfig,omitempty"` // Map of mattermost server config paths and their values. Notice will be displayed only if; the values match the target server config; Example: serverConfig: { "PluginSettings.Enable": true, "GuestAccountsSettings.Enable":; false } - ServerVersion []string `json:"serverVersion,omitempty"` // What server versions does this notice apply to.; Format: semver ranges (https://devhints.io/semver); Example: [">=1.2.3 < ~2.4.x"]; Example: ["<v5.19", "v5.20-v5.22"] - Sku *NoticeSKU `json:"sku,omitempty"` - UserConfig map[string]interface{} `json:"userConfig,omitempty"` // Map of user's settings and their values. Notice will be displayed only if the values; match the viewing users' config; Example: userConfig: { "new_sidebar.disabled": true } - DeprecatingDependency *ExternalDependency `json:"deprecating_dependency,omitempty"` // External dependency which is going to be deprecated -} - -type NoticeMessageInternal struct { - Action *NoticeAction `json:"action,omitempty"` // Optional action to perform on action button click. (defaults to closing the notice) - ActionParam *string `json:"actionParam,omitempty"` // Optional action parameter.; Example: {"action": "url", actionParam: "/console/some-page"} - ActionText *string `json:"actionText,omitempty"` // Optional override for the action button text (defaults to OK) - Description string `json:"description"` // Notice content. Use {{Mattermost}} instead of plain text to support white-labeling. Text; supports Markdown. - Image *string `json:"image,omitempty"` - Title string `json:"title"` // Notice title. Use {{Mattermost}} instead of plain text to support white-labeling. Text; supports Markdown. -} -type NoticeMessages []NoticeMessage - -type NoticeMessage struct { - NoticeMessageInternal - ID string `json:"id"` - SysAdminOnly bool `json:"sysAdminOnly"` - TeamAdminOnly bool `json:"teamAdminOnly"` -} - -func (r *NoticeMessages) Marshal() ([]byte, error) { - return json.Marshal(r) -} - -func UnmarshalProductNoticeMessages(data io.Reader) (NoticeMessages, error) { - var r NoticeMessages - err := json.NewDecoder(data).Decode(&r) - return r, err -} - -// User role, i.e. who will see the notice. Defaults to "all" -type NoticeAudience string - -func NewNoticeAudience(s NoticeAudience) *NoticeAudience { - return &s -} - -func (a *NoticeAudience) Matches(sysAdmin bool, teamAdmin bool) bool { - switch *a { - case NoticeAudience_All: - return true - case NoticeAudience_Member: - return !sysAdmin && !teamAdmin - case NoticeAudience_Sysadmin: - return sysAdmin - case NoticeAudience_TeamAdmin: - return teamAdmin - } - return false -} - -const ( - NoticeAudience_All NoticeAudience = "all" - NoticeAudience_Member NoticeAudience = "member" - NoticeAudience_Sysadmin NoticeAudience = "sysadmin" - NoticeAudience_TeamAdmin NoticeAudience = "teamadmin" -) - -// Only show the notice on specific clients. Defaults to 'all' -// -// Client type. Defaults to "all" -type NoticeClientType string - -func NewNoticeClientType(s NoticeClientType) *NoticeClientType { return &s } - -func (c *NoticeClientType) Matches(other NoticeClientType) bool { - switch *c { - case NoticeClientType_All: - return true - case NoticeClientType_Mobile: - return other == NoticeClientType_MobileIos || other == NoticeClientType_MobileAndroid - default: - return *c == other - } -} - -const ( - NoticeClientType_All NoticeClientType = "all" - NoticeClientType_Desktop NoticeClientType = "desktop" - NoticeClientType_Mobile NoticeClientType = "mobile" - NoticeClientType_MobileAndroid NoticeClientType = "mobile-android" - NoticeClientType_MobileIos NoticeClientType = "mobile-ios" - NoticeClientType_Web NoticeClientType = "web" -) - -func NoticeClientTypeFromString(s string) (NoticeClientType, error) { - switch s { - case "web": - return NoticeClientType_Web, nil - case "mobile-ios": - return NoticeClientType_MobileIos, nil - case "mobile-android": - return NoticeClientType_MobileAndroid, nil - case "desktop": - return NoticeClientType_Desktop, nil - } - return NoticeClientType_All, errors.New("Invalid client type supplied") -} - -// Instance type. Defaults to "both" -type NoticeInstanceType string - -func NewNoticeInstanceType(n NoticeInstanceType) *NoticeInstanceType { return &n } -func (t *NoticeInstanceType) Matches(isCloud bool) bool { - if *t == NoticeInstanceType_Both { - return true - } - if *t == NoticeInstanceType_Cloud && !isCloud { - return false - } - if *t == NoticeInstanceType_OnPrem && isCloud { - return false - } - return true -} - -const ( - NoticeInstanceType_Both NoticeInstanceType = "both" - NoticeInstanceType_Cloud NoticeInstanceType = "cloud" - NoticeInstanceType_OnPrem NoticeInstanceType = "onprem" -) - -// SKU. Defaults to "all" -type NoticeSKU string - -func NewNoticeSKU(s NoticeSKU) *NoticeSKU { return &s } -func (c *NoticeSKU) Matches(s string) bool { - switch *c { - case NoticeSKU_All: - return true - case NoticeSKU_E0, NoticeSKU_Team: - return s == "" - default: - return s == string(*c) - } -} - -const ( - NoticeSKU_E0 NoticeSKU = "e0" - NoticeSKU_E10 NoticeSKU = "e10" - NoticeSKU_E20 NoticeSKU = "e20" - NoticeSKU_All NoticeSKU = "all" - NoticeSKU_Team NoticeSKU = "team" -) - -// Optional action to perform on action button click. (defaults to closing the notice) -// -// Possible actions to execute on button press -type NoticeAction string - -const ( - URL NoticeAction = "url" -) - -// Definition of the table keeping the 'viewed' state of each in-product notice per user -type ProductNoticeViewState struct { - UserId string - NoticeId string - Viewed int32 - Timestamp int64 -} - -type ExternalDependency struct { - Name string `json:"name"` - MinimumVersion string `json:"minimum_version"` -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/push_notification.go b/vendor/github.com/mattermost/mattermost-server/v5/model/push_notification.go deleted file mode 100644 index 2a0dc658..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/push_notification.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "errors" - "io" - "strings" -) - -const ( - PUSH_NOTIFY_APPLE = "apple" - PUSH_NOTIFY_ANDROID = "android" - PUSH_NOTIFY_APPLE_REACT_NATIVE = "apple_rn" - PUSH_NOTIFY_ANDROID_REACT_NATIVE = "android_rn" - - PUSH_TYPE_MESSAGE = "message" - PUSH_TYPE_CLEAR = "clear" - PUSH_TYPE_UPDATE_BADGE = "update_badge" - PUSH_TYPE_SESSION = "session" - PUSH_MESSAGE_V2 = "v2" - - PUSH_SOUND_NONE = "none" - - // The category is set to handle a set of interactive Actions - // with the push notifications - CATEGORY_CAN_REPLY = "CAN_REPLY" - - MHPNS = "https://push.mattermost.com" - - PUSH_SEND_PREPARE = "Prepared to send" - PUSH_SEND_SUCCESS = "Successful" - PUSH_NOT_SENT = "Not Sent due to preferences" - PUSH_RECEIVED = "Received by device" -) - -type PushNotificationAck struct { - Id string `json:"id"` - ClientReceivedAt int64 `json:"received_at"` - ClientPlatform string `json:"platform"` - NotificationType string `json:"type"` - PostId string `json:"post_id,omitempty"` - IsIdLoaded bool `json:"is_id_loaded"` -} - -type PushNotification struct { - AckId string `json:"ack_id"` - Platform string `json:"platform"` - ServerId string `json:"server_id"` - DeviceId string `json:"device_id"` - PostId string `json:"post_id"` - Category string `json:"category,omitempty"` - Sound string `json:"sound,omitempty"` - Message string `json:"message,omitempty"` - Badge int `json:"badge,omitempty"` - ContentAvailable int `json:"cont_ava,omitempty"` - TeamId string `json:"team_id,omitempty"` - ChannelId string `json:"channel_id,omitempty"` - RootId string `json:"root_id,omitempty"` - ChannelName string `json:"channel_name,omitempty"` - Type string `json:"type,omitempty"` - SenderId string `json:"sender_id,omitempty"` - SenderName string `json:"sender_name,omitempty"` - OverrideUsername string `json:"override_username,omitempty"` - OverrideIconUrl string `json:"override_icon_url,omitempty"` - FromWebhook string `json:"from_webhook,omitempty"` - Version string `json:"version,omitempty"` - IsIdLoaded bool `json:"is_id_loaded"` -} - -func (pn *PushNotification) ToJson() string { - b, _ := json.Marshal(pn) - return string(b) -} - -func (pn *PushNotification) DeepCopy() *PushNotification { - copy := *pn - return © -} - -func (pn *PushNotification) SetDeviceIdAndPlatform(deviceId string) { - - index := strings.Index(deviceId, ":") - - if index > -1 { - pn.Platform = deviceId[:index] - pn.DeviceId = deviceId[index+1:] - } -} - -func PushNotificationFromJson(data io.Reader) (*PushNotification, error) { - if data == nil { - return nil, errors.New("push notification data can't be nil") - } - var pn *PushNotification - if err := json.NewDecoder(data).Decode(&pn); err != nil { - return nil, err - } - return pn, nil -} - -func PushNotificationAckFromJson(data io.Reader) (*PushNotificationAck, error) { - if data == nil { - return nil, errors.New("push notification data can't be nil") - } - var ack *PushNotificationAck - if err := json.NewDecoder(data).Decode(&ack); err != nil { - return nil, err - } - return ack, nil -} - -func (ack *PushNotificationAck) ToJson() string { - b, _ := json.Marshal(ack) - return string(b) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/push_response.go b/vendor/github.com/mattermost/mattermost-server/v5/model/push_response.go deleted file mode 100644 index 227a089b..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/push_response.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -const ( - PUSH_STATUS = "status" - PUSH_STATUS_OK = "OK" - PUSH_STATUS_FAIL = "FAIL" - PUSH_STATUS_REMOVE = "REMOVE" - PUSH_STATUS_ERROR_MSG = "error" -) - -type PushResponse map[string]string - -func NewOkPushResponse() PushResponse { - m := make(map[string]string) - m[PUSH_STATUS] = PUSH_STATUS_OK - return m -} - -func NewRemovePushResponse() PushResponse { - m := make(map[string]string) - m[PUSH_STATUS] = PUSH_STATUS_REMOVE - return m -} - -func NewErrorPushResponse(message string) PushResponse { - m := make(map[string]string) - m[PUSH_STATUS] = PUSH_STATUS_FAIL - m[PUSH_STATUS_ERROR_MSG] = message - return m -} - -func (pr *PushResponse) ToJson() string { - b, _ := json.Marshal(pr) - return string(b) -} - -func PushResponseFromJson(data io.Reader) PushResponse { - decoder := json.NewDecoder(data) - - var objmap PushResponse - if err := decoder.Decode(&objmap); err != nil { - return make(map[string]string) - } - return objmap -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/reaction.go b/vendor/github.com/mattermost/mattermost-server/v5/model/reaction.go deleted file mode 100644 index 6d0ea68d..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/reaction.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" - "regexp" -) - -type Reaction struct { - UserId string `json:"user_id"` - PostId string `json:"post_id"` - EmojiName string `json:"emoji_name"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - RemoteId *string `json:"remote_id"` -} - -func (o *Reaction) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func ReactionFromJson(data io.Reader) *Reaction { - var o Reaction - - if err := json.NewDecoder(data).Decode(&o); err != nil { - return nil - } - return &o -} - -func ReactionsToJson(o []*Reaction) string { - b, _ := json.Marshal(o) - return string(b) -} - -func MapPostIdToReactionsToJson(o map[string][]*Reaction) string { - b, _ := json.Marshal(o) - return string(b) -} - -func MapPostIdToReactionsFromJson(data io.Reader) map[string][]*Reaction { - decoder := json.NewDecoder(data) - - var objmap map[string][]*Reaction - if err := decoder.Decode(&objmap); err != nil { - return make(map[string][]*Reaction) - } - return objmap -} - -func ReactionsFromJson(data io.Reader) []*Reaction { - var o []*Reaction - - if err := json.NewDecoder(data).Decode(&o); err != nil { - return nil - } - return o -} - -func (o *Reaction) IsValid() *AppError { - if !IsValidId(o.UserId) { - return NewAppError("Reaction.IsValid", "model.reaction.is_valid.user_id.app_error", nil, "user_id="+o.UserId, http.StatusBadRequest) - } - - if !IsValidId(o.PostId) { - return NewAppError("Reaction.IsValid", "model.reaction.is_valid.post_id.app_error", nil, "post_id="+o.PostId, http.StatusBadRequest) - } - - validName := regexp.MustCompile(`^[a-zA-Z0-9\-\+_]+$`) - - if o.EmojiName == "" || len(o.EmojiName) > EMOJI_NAME_MAX_LENGTH || !validName.MatchString(o.EmojiName) { - return NewAppError("Reaction.IsValid", "model.reaction.is_valid.emoji_name.app_error", nil, "emoji_name="+o.EmojiName, http.StatusBadRequest) - } - - if o.CreateAt == 0 { - return NewAppError("Reaction.IsValid", "model.reaction.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) - } - - if o.UpdateAt == 0 { - return NewAppError("Reaction.IsValid", "model.reaction.is_valid.update_at.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (o *Reaction) PreSave() { - if o.CreateAt == 0 { - o.CreateAt = GetMillis() - } - o.UpdateAt = GetMillis() - o.DeleteAt = 0 - - if o.RemoteId == nil { - o.RemoteId = NewString("") - } -} - -func (o *Reaction) PreUpdate() { - o.UpdateAt = GetMillis() - - if o.RemoteId == nil { - o.RemoteId = NewString("") - } -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/remote_cluster.go b/vendor/github.com/mattermost/mattermost-server/v5/model/remote_cluster.go deleted file mode 100644 index 2ec0cc9b..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/remote_cluster.go +++ /dev/null @@ -1,355 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "encoding/json" - "errors" - "io" - "net/http" - "regexp" - "strings" - - "golang.org/x/crypto/scrypt" -) - -const ( - RemoteOfflineAfterMillis = 1000 * 60 * 5 // 5 minutes - RemoteNameMinLength = 1 - RemoteNameMaxLength = 64 -) - -var ( - validRemoteNameChars = regexp.MustCompile(`^[a-zA-Z0-9\.\-\_]+$`) -) - -type RemoteCluster struct { - RemoteId string `json:"remote_id"` - RemoteTeamId string `json:"remote_team_id"` - Name string `json:"name"` - DisplayName string `json:"display_name"` - SiteURL string `json:"site_url"` - CreateAt int64 `json:"create_at"` - LastPingAt int64 `json:"last_ping_at"` - Token string `json:"token"` - RemoteToken string `json:"remote_token"` - Topics string `json:"topics"` - CreatorId string `json:"creator_id"` -} - -func (rc *RemoteCluster) PreSave() { - if rc.RemoteId == "" { - rc.RemoteId = NewId() - } - - if rc.DisplayName == "" { - rc.DisplayName = rc.Name - } - - rc.Name = SanitizeUnicode(rc.Name) - rc.DisplayName = SanitizeUnicode(rc.DisplayName) - rc.Name = NormalizeRemoteName(rc.Name) - - if rc.Token == "" { - rc.Token = NewId() - } - - if rc.CreateAt == 0 { - rc.CreateAt = GetMillis() - } - rc.fixTopics() -} - -func (rc *RemoteCluster) IsValid() *AppError { - if !IsValidId(rc.RemoteId) { - return NewAppError("RemoteCluster.IsValid", "model.cluster.is_valid.id.app_error", nil, "id="+rc.RemoteId, http.StatusBadRequest) - } - - if !IsValidRemoteName(rc.Name) { - return NewAppError("RemoteCluster.IsValid", "model.cluster.is_valid.name.app_error", nil, "name="+rc.Name, http.StatusBadRequest) - } - - if rc.CreateAt == 0 { - return NewAppError("RemoteCluster.IsValid", "model.cluster.is_valid.create_at.app_error", nil, "create_at=0", http.StatusBadRequest) - } - - if !IsValidId(rc.CreatorId) { - return NewAppError("RemoteCluster.IsValid", "model.cluster.is_valid.id.app_error", nil, "creator_id="+rc.CreatorId, http.StatusBadRequest) - } - return nil -} - -func IsValidRemoteName(s string) bool { - if len(s) < RemoteNameMinLength || len(s) > RemoteNameMaxLength { - return false - } - return validRemoteNameChars.MatchString(s) -} - -func (rc *RemoteCluster) PreUpdate() { - if rc.DisplayName == "" { - rc.DisplayName = rc.Name - } - - rc.Name = SanitizeUnicode(rc.Name) - rc.DisplayName = SanitizeUnicode(rc.DisplayName) - rc.Name = NormalizeRemoteName(rc.Name) - rc.fixTopics() -} - -func (rc *RemoteCluster) IsOnline() bool { - return rc.LastPingAt > GetMillis()-RemoteOfflineAfterMillis -} - -// fixTopics ensures all topics are separated by one, and only one, space. -func (rc *RemoteCluster) fixTopics() { - trimmed := strings.TrimSpace(rc.Topics) - if trimmed == "" || trimmed == "*" { - rc.Topics = trimmed - return - } - - var sb strings.Builder - sb.WriteString(" ") - - ss := strings.Split(rc.Topics, " ") - for _, c := range ss { - cc := strings.TrimSpace(c) - if cc != "" { - sb.WriteString(cc) - sb.WriteString(" ") - } - } - rc.Topics = sb.String() -} - -func (rc *RemoteCluster) ToJSON() (string, error) { - b, err := json.Marshal(rc) - if err != nil { - return "", err - } - return string(b), nil -} - -func (rc *RemoteCluster) ToRemoteClusterInfo() RemoteClusterInfo { - return RemoteClusterInfo{ - Name: rc.Name, - DisplayName: rc.DisplayName, - CreateAt: rc.CreateAt, - LastPingAt: rc.LastPingAt, - } -} - -func NormalizeRemoteName(name string) string { - return strings.ToLower(name) -} - -func RemoteClusterFromJSON(data io.Reader) (*RemoteCluster, *AppError) { - var rc RemoteCluster - err := json.NewDecoder(data).Decode(&rc) - if err != nil { - return nil, NewAppError("RemoteClusterFromJSON", "model.utils.decode_json.app_error", nil, err.Error(), http.StatusBadRequest) - } - return &rc, nil -} - -// RemoteClusterInfo provides a subset of RemoteCluster fields suitable for sending to clients. -type RemoteClusterInfo struct { - Name string `json:"name"` - DisplayName string `json:"display_name"` - CreateAt int64 `json:"create_at"` - LastPingAt int64 `json:"last_ping_at"` -} - -// RemoteClusterFrame wraps a `RemoteClusterMsg` with credentials specific to a remote cluster. -type RemoteClusterFrame struct { - RemoteId string `json:"remote_id"` - Msg RemoteClusterMsg `json:"msg"` -} - -func (f *RemoteClusterFrame) IsValid() *AppError { - if !IsValidId(f.RemoteId) { - return NewAppError("RemoteClusterFrame.IsValid", "api.remote_cluster.invalid_id.app_error", nil, "RemoteId="+f.RemoteId, http.StatusBadRequest) - } - - if err := f.Msg.IsValid(); err != nil { - return err - } - - return nil -} - -func RemoteClusterFrameFromJSON(data io.Reader) (*RemoteClusterFrame, *AppError) { - var frame RemoteClusterFrame - err := json.NewDecoder(data).Decode(&frame) - if err != nil { - return nil, NewAppError("RemoteClusterFrameFromJSON", "model.utils.decode_json.app_error", nil, err.Error(), http.StatusBadRequest) - } - return &frame, nil -} - -// RemoteClusterMsg represents a message that is sent and received between clusters. -// These are processed and routed via the RemoteClusters service. -type RemoteClusterMsg struct { - Id string `json:"id"` - Topic string `json:"topic"` - CreateAt int64 `json:"create_at"` - Payload json.RawMessage `json:"payload"` -} - -func NewRemoteClusterMsg(topic string, payload json.RawMessage) RemoteClusterMsg { - return RemoteClusterMsg{ - Id: NewId(), - Topic: topic, - CreateAt: GetMillis(), - Payload: payload, - } -} - -func (m RemoteClusterMsg) IsValid() *AppError { - if !IsValidId(m.Id) { - return NewAppError("RemoteClusterMsg.IsValid", "api.remote_cluster.invalid_id.app_error", nil, "Id="+m.Id, http.StatusBadRequest) - } - - if m.Topic == "" { - return NewAppError("RemoteClusterMsg.IsValid", "api.remote_cluster.invalid_topic.app_error", nil, "Topic empty", http.StatusBadRequest) - } - - if len(m.Payload) == 0 { - return NewAppError("RemoteClusterMsg.IsValid", "api.context.invalid_body_param.app_error", map[string]interface{}{"Name": "PayLoad"}, "", http.StatusBadRequest) - } - - return nil -} - -func RemoteClusterMsgFromJSON(data io.Reader) (RemoteClusterMsg, *AppError) { - var msg RemoteClusterMsg - err := json.NewDecoder(data).Decode(&msg) - if err != nil { - return RemoteClusterMsg{}, NewAppError("RemoteClusterMsgFromJSON", "model.utils.decode_json.app_error", nil, err.Error(), http.StatusBadRequest) - } - return msg, nil -} - -// RemoteClusterPing represents a ping that is sent and received between clusters -// to indicate a connection is alive. This is the payload for a `RemoteClusterMsg`. -type RemoteClusterPing struct { - SentAt int64 `json:"sent_at"` - RecvAt int64 `json:"recv_at"` -} - -func RemoteClusterPingFromRawJSON(raw json.RawMessage) (RemoteClusterPing, *AppError) { - var ping RemoteClusterPing - err := json.Unmarshal(raw, &ping) - if err != nil { - return RemoteClusterPing{}, NewAppError("RemoteClusterPingFromRawJSON", "model.utils.decode_json.app_error", nil, err.Error(), http.StatusBadRequest) - } - return ping, nil -} - -// RemoteClusterInvite represents an invitation to establish a simple trust with a remote cluster. -type RemoteClusterInvite struct { - RemoteId string `json:"remote_id"` - RemoteTeamId string `json:"remote_team_id"` - SiteURL string `json:"site_url"` - Token string `json:"token"` -} - -func RemoteClusterInviteFromRawJSON(raw json.RawMessage) (*RemoteClusterInvite, *AppError) { - var invite RemoteClusterInvite - err := json.Unmarshal(raw, &invite) - if err != nil { - return nil, NewAppError("RemoteClusterInviteFromRawJSON", "model.utils.decode_json.app_error", nil, err.Error(), http.StatusBadRequest) - } - return &invite, nil -} - -func (rci *RemoteClusterInvite) Encrypt(password string) ([]byte, error) { - raw, err := json.Marshal(&rci) - if err != nil { - return nil, err - } - - // create random salt to be prepended to the blob. - salt := make([]byte, 16) - if _, err = io.ReadFull(rand.Reader, salt); err != nil { - return nil, err - } - - key, err := scrypt.Key([]byte(password), salt, 32768, 8, 1, 32) - if err != nil { - return nil, err - } - - block, err := aes.NewCipher(key[:]) - if err != nil { - return nil, err - } - - gcm, err := cipher.NewGCM(block) - if err != nil { - return nil, err - } - - // create random nonce - nonce := make([]byte, gcm.NonceSize()) - if _, err = io.ReadFull(rand.Reader, nonce); err != nil { - return nil, err - } - - // prefix the nonce to the cyphertext so we don't need to keep track of it. - sealed := gcm.Seal(nonce, nonce, raw, nil) - - return append(salt, sealed...), nil -} - -func (rci *RemoteClusterInvite) Decrypt(encrypted []byte, password string) error { - if len(encrypted) <= 16 { - return errors.New("invalid length") - } - - // first 16 bytes is the salt that was used to derive a key - salt := encrypted[:16] - encrypted = encrypted[16:] - - key, err := scrypt.Key([]byte(password), salt, 32768, 8, 1, 32) - if err != nil { - return err - } - - block, err := aes.NewCipher(key[:]) - if err != nil { - return err - } - - gcm, err := cipher.NewGCM(block) - if err != nil { - return err - } - - // nonce was prefixed to the cyphertext when encrypting so we need to extract it. - nonceSize := gcm.NonceSize() - nonce, cyphertext := encrypted[:nonceSize], encrypted[nonceSize:] - - plain, err := gcm.Open(nil, nonce, cyphertext, nil) - if err != nil { - return err - } - - // try to unmarshall the decrypted JSON to this invite struct. - return json.Unmarshal(plain, &rci) -} - -// RemoteClusterQueryFilter provides filter criteria for RemoteClusterStore.GetAll -type RemoteClusterQueryFilter struct { - ExcludeOffline bool - InChannel string - NotInChannel string - Topic string - CreatorId string - OnlyConfirmed bool -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/role.go b/vendor/github.com/mattermost/mattermost-server/v5/model/role.go deleted file mode 100644 index fc1606ce..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/role.go +++ /dev/null @@ -1,952 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "strings" -) - -// SysconsoleAncillaryPermissions maps the non-sysconsole permissions required by each sysconsole view. -var SysconsoleAncillaryPermissions map[string][]*Permission -var SystemManagerDefaultPermissions []string -var SystemUserManagerDefaultPermissions []string -var SystemReadOnlyAdminDefaultPermissions []string - -var BuiltInSchemeManagedRoleIDs []string - -var NewSystemRoleIDs []string - -func init() { - NewSystemRoleIDs = []string{ - SYSTEM_USER_MANAGER_ROLE_ID, - SYSTEM_READ_ONLY_ADMIN_ROLE_ID, - SYSTEM_MANAGER_ROLE_ID, - } - - BuiltInSchemeManagedRoleIDs = append([]string{ - SYSTEM_GUEST_ROLE_ID, - SYSTEM_USER_ROLE_ID, - SYSTEM_ADMIN_ROLE_ID, - SYSTEM_POST_ALL_ROLE_ID, - SYSTEM_POST_ALL_PUBLIC_ROLE_ID, - SYSTEM_USER_ACCESS_TOKEN_ROLE_ID, - - TEAM_GUEST_ROLE_ID, - TEAM_USER_ROLE_ID, - TEAM_ADMIN_ROLE_ID, - TEAM_POST_ALL_ROLE_ID, - TEAM_POST_ALL_PUBLIC_ROLE_ID, - - CHANNEL_GUEST_ROLE_ID, - CHANNEL_USER_ROLE_ID, - CHANNEL_ADMIN_ROLE_ID, - }, NewSystemRoleIDs...) - - // When updating the values here, the values in mattermost-redux must also be updated. - SysconsoleAncillaryPermissions = map[string][]*Permission{ - PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE.Id: { - PERMISSION_READ_LICENSE_INFORMATION, - }, - PERMISSION_SYSCONSOLE_WRITE_ABOUT_EDITION_AND_LICENSE.Id: { - PERMISSION_MANAGE_LICENSE_INFORMATION, - }, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS.Id: { - PERMISSION_READ_PUBLIC_CHANNEL, - PERMISSION_READ_CHANNEL, - PERMISSION_READ_PUBLIC_CHANNEL_GROUPS, - PERMISSION_READ_PRIVATE_CHANNEL_GROUPS, - }, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS.Id: { - PERMISSION_READ_OTHER_USERS_TEAMS, - PERMISSION_GET_ANALYTICS, - }, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS.Id: { - PERMISSION_LIST_PRIVATE_TEAMS, - PERMISSION_LIST_PUBLIC_TEAMS, - PERMISSION_VIEW_TEAM, - }, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH.Id: { - PERMISSION_READ_ELASTICSEARCH_POST_INDEXING_JOB, - PERMISSION_READ_ELASTICSEARCH_POST_AGGREGATION_JOB, - }, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_WEB_SERVER.Id: { - PERMISSION_TEST_SITE_URL, - PERMISSION_RELOAD_CONFIG, - PERMISSION_INVALIDATE_CACHES, - }, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DATABASE.Id: { - PERMISSION_RECYCLE_DATABASE_CONNECTIONS, - }, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_ELASTICSEARCH.Id: { - PERMISSION_TEST_ELASTICSEARCH, - PERMISSION_CREATE_ELASTICSEARCH_POST_INDEXING_JOB, - PERMISSION_CREATE_ELASTICSEARCH_POST_AGGREGATION_JOB, - PERMISSION_PURGE_ELASTICSEARCH_INDEXES, - }, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_FILE_STORAGE.Id: { - PERMISSION_TEST_S3, - }, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SMTP.Id: { - PERMISSION_TEST_EMAIL, - }, - PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS.Id: { - PERMISSION_GET_LOGS, - }, - PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS.Id: { - PERMISSION_GET_ANALYTICS, - }, - PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS.Id: { - PERMISSION_VIEW_TEAM, - }, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_USERS.Id: { - PERMISSION_EDIT_OTHER_USERS, - PERMISSION_DEMOTE_TO_GUEST, - PERMISSION_PROMOTE_GUEST, - }, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS.Id: { - PERMISSION_MANAGE_TEAM, - PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES, - PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES, - PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS, - PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS, - PERMISSION_DELETE_PRIVATE_CHANNEL, - PERMISSION_DELETE_PUBLIC_CHANNEL, - PERMISSION_MANAGE_CHANNEL_ROLES, - PERMISSION_CONVERT_PUBLIC_CHANNEL_TO_PRIVATE, - PERMISSION_CONVERT_PRIVATE_CHANNEL_TO_PUBLIC, - }, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS.Id: { - PERMISSION_MANAGE_TEAM, - PERMISSION_MANAGE_TEAM_ROLES, - PERMISSION_REMOVE_USER_FROM_TEAM, - PERMISSION_JOIN_PRIVATE_TEAMS, - PERMISSION_JOIN_PUBLIC_TEAMS, - PERMISSION_ADD_USER_TO_TEAM, - }, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS.Id: { - PERMISSION_MANAGE_TEAM, - PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS, - PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS, - PERMISSION_CONVERT_PUBLIC_CHANNEL_TO_PRIVATE, - PERMISSION_CONVERT_PRIVATE_CHANNEL_TO_PUBLIC, - }, - PERMISSION_SYSCONSOLE_WRITE_SITE_CUSTOMIZATION.Id: { - PERMISSION_EDIT_BRAND, - }, - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_DATA_RETENTION_POLICY.Id: { - PERMISSION_CREATE_DATA_RETENTION_JOB, - }, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_DATA_RETENTION_POLICY.Id: { - PERMISSION_READ_DATA_RETENTION_JOB, - }, - PERMISSION_SYSCONSOLE_WRITE_COMPLIANCE_COMPLIANCE_EXPORT.Id: { - PERMISSION_CREATE_COMPLIANCE_EXPORT_JOB, - PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT, - }, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_EXPORT.Id: { - PERMISSION_READ_COMPLIANCE_EXPORT_JOB, - PERMISSION_DOWNLOAD_COMPLIANCE_EXPORT_RESULT, - }, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE.Id: { - PERMISSION_READ_AUDITS, - }, - PERMISSION_SYSCONSOLE_WRITE_EXPERIMENTAL_BLEVE.Id: { - PERMISSION_CREATE_POST_BLEVE_INDEXES_JOB, - PERMISSION_PURGE_BLEVE_INDEXES, - }, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_LDAP.Id: { - PERMISSION_CREATE_LDAP_SYNC_JOB, - PERMISSION_ADD_LDAP_PUBLIC_CERT, - PERMISSION_REMOVE_LDAP_PUBLIC_CERT, - PERMISSION_ADD_LDAP_PRIVATE_CERT, - PERMISSION_REMOVE_LDAP_PRIVATE_CERT, - }, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP.Id: { - PERMISSION_TEST_LDAP, - PERMISSION_READ_LDAP_SYNC_JOB, - }, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_EMAIL.Id: { - PERMISSION_INVALIDATE_EMAIL_INVITE, - }, - PERMISSION_SYSCONSOLE_WRITE_AUTHENTICATION_SAML.Id: { - PERMISSION_GET_SAML_METADATA_FROM_IDP, - PERMISSION_ADD_SAML_PUBLIC_CERT, - PERMISSION_ADD_SAML_PRIVATE_CERT, - PERMISSION_ADD_SAML_IDP_CERT, - PERMISSION_REMOVE_SAML_PUBLIC_CERT, - PERMISSION_REMOVE_SAML_PRIVATE_CERT, - PERMISSION_REMOVE_SAML_IDP_CERT, - PERMISSION_GET_SAML_CERT_STATUS, - }, - } - - SystemUserManagerDefaultPermissions = []string{ - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS.Id, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS.Id, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS.Id, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS.Id, - } - - SystemReadOnlyAdminDefaultPermissions = []string{ - PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE.Id, - PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS.Id, - PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS.Id, - PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_USERS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_WEB_SERVER.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DATABASE.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_FILE_STORAGE.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_IMAGE_PROXY.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SMTP.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PUSH_NOTIFICATION_SERVER.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_HIGH_AVAILABILITY.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_RATE_LIMITING.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_LOGGING.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER.Id, - PERMISSION_SYSCONSOLE_READ_SITE_CUSTOMIZATION.Id, - PERMISSION_SYSCONSOLE_READ_SITE_LOCALIZATION.Id, - PERMISSION_SYSCONSOLE_READ_SITE_USERS_AND_TEAMS.Id, - PERMISSION_SYSCONSOLE_READ_SITE_NOTIFICATIONS.Id, - PERMISSION_SYSCONSOLE_READ_SITE_ANNOUNCEMENT_BANNER.Id, - PERMISSION_SYSCONSOLE_READ_SITE_EMOJI.Id, - PERMISSION_SYSCONSOLE_READ_SITE_POSTS.Id, - PERMISSION_SYSCONSOLE_READ_SITE_FILE_SHARING_AND_DOWNLOADS.Id, - PERMISSION_SYSCONSOLE_READ_SITE_PUBLIC_LINKS.Id, - PERMISSION_SYSCONSOLE_READ_SITE_NOTICES.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS.Id, - PERMISSION_SYSCONSOLE_READ_PLUGINS.Id, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_INTEGRATION_MANAGEMENT.Id, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_BOT_ACCOUNTS.Id, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_GIF.Id, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_CORS.Id, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_DATA_RETENTION_POLICY.Id, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_EXPORT.Id, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_COMPLIANCE_MONITORING.Id, - PERMISSION_SYSCONSOLE_READ_COMPLIANCE_CUSTOM_TERMS_OF_SERVICE.Id, - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURES.Id, - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_FEATURE_FLAGS.Id, - PERMISSION_SYSCONSOLE_READ_EXPERIMENTAL_BLEVE.Id, - } - - SystemManagerDefaultPermissions = []string{ - PERMISSION_SYSCONSOLE_READ_ABOUT_EDITION_AND_LICENSE.Id, - PERMISSION_SYSCONSOLE_READ_REPORTING_SITE_STATISTICS.Id, - PERMISSION_SYSCONSOLE_READ_REPORTING_TEAM_STATISTICS.Id, - PERMISSION_SYSCONSOLE_READ_REPORTING_SERVER_LOGS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_GROUPS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_TEAMS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_CHANNELS.Id, - PERMISSION_SYSCONSOLE_READ_USERMANAGEMENT_PERMISSIONS.Id, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_GROUPS.Id, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_TEAMS.Id, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_CHANNELS.Id, - PERMISSION_SYSCONSOLE_WRITE_USERMANAGEMENT_PERMISSIONS.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_WEB_SERVER.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DATABASE.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_ELASTICSEARCH.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_FILE_STORAGE.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_IMAGE_PROXY.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SMTP.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PUSH_NOTIFICATION_SERVER.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_HIGH_AVAILABILITY.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_RATE_LIMITING.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_LOGGING.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_SESSION_LENGTHS.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_PERFORMANCE_MONITORING.Id, - PERMISSION_SYSCONSOLE_READ_ENVIRONMENT_DEVELOPER.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_WEB_SERVER.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DATABASE.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_ELASTICSEARCH.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_FILE_STORAGE.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_IMAGE_PROXY.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SMTP.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PUSH_NOTIFICATION_SERVER.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_HIGH_AVAILABILITY.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_RATE_LIMITING.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_LOGGING.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_SESSION_LENGTHS.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_PERFORMANCE_MONITORING.Id, - PERMISSION_SYSCONSOLE_WRITE_ENVIRONMENT_DEVELOPER.Id, - PERMISSION_SYSCONSOLE_READ_SITE_CUSTOMIZATION.Id, - PERMISSION_SYSCONSOLE_WRITE_SITE_CUSTOMIZATION.Id, - PERMISSION_SYSCONSOLE_READ_SITE_LOCALIZATION.Id, - PERMISSION_SYSCONSOLE_WRITE_SITE_LOCALIZATION.Id, - PERMISSION_SYSCONSOLE_READ_SITE_USERS_AND_TEAMS.Id, - PERMISSION_SYSCONSOLE_WRITE_SITE_USERS_AND_TEAMS.Id, - PERMISSION_SYSCONSOLE_READ_SITE_NOTIFICATIONS.Id, - PERMISSION_SYSCONSOLE_WRITE_SITE_NOTIFICATIONS.Id, - PERMISSION_SYSCONSOLE_READ_SITE_ANNOUNCEMENT_BANNER.Id, - PERMISSION_SYSCONSOLE_WRITE_SITE_ANNOUNCEMENT_BANNER.Id, - PERMISSION_SYSCONSOLE_READ_SITE_EMOJI.Id, - PERMISSION_SYSCONSOLE_WRITE_SITE_EMOJI.Id, - PERMISSION_SYSCONSOLE_READ_SITE_POSTS.Id, - PERMISSION_SYSCONSOLE_WRITE_SITE_POSTS.Id, - PERMISSION_SYSCONSOLE_READ_SITE_FILE_SHARING_AND_DOWNLOADS.Id, - PERMISSION_SYSCONSOLE_WRITE_SITE_FILE_SHARING_AND_DOWNLOADS.Id, - PERMISSION_SYSCONSOLE_READ_SITE_PUBLIC_LINKS.Id, - PERMISSION_SYSCONSOLE_WRITE_SITE_PUBLIC_LINKS.Id, - PERMISSION_SYSCONSOLE_READ_SITE_NOTICES.Id, - PERMISSION_SYSCONSOLE_WRITE_SITE_NOTICES.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SIGNUP.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_EMAIL.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_PASSWORD.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_MFA.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_LDAP.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_SAML.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_OPENID.Id, - PERMISSION_SYSCONSOLE_READ_AUTHENTICATION_GUEST_ACCESS.Id, - PERMISSION_SYSCONSOLE_READ_PLUGINS.Id, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_INTEGRATION_MANAGEMENT.Id, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_BOT_ACCOUNTS.Id, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_GIF.Id, - PERMISSION_SYSCONSOLE_READ_INTEGRATIONS_CORS.Id, - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_INTEGRATION_MANAGEMENT.Id, - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_BOT_ACCOUNTS.Id, - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_GIF.Id, - PERMISSION_SYSCONSOLE_WRITE_INTEGRATIONS_CORS.Id, - } - - // Add the ancillary permissions to each system role - SystemUserManagerDefaultPermissions = AddAncillaryPermissions(SystemUserManagerDefaultPermissions) - SystemReadOnlyAdminDefaultPermissions = AddAncillaryPermissions(SystemReadOnlyAdminDefaultPermissions) - SystemManagerDefaultPermissions = AddAncillaryPermissions(SystemManagerDefaultPermissions) -} - -type RoleType string -type RoleScope string - -const ( - SYSTEM_GUEST_ROLE_ID = "system_guest" - SYSTEM_USER_ROLE_ID = "system_user" - SYSTEM_ADMIN_ROLE_ID = "system_admin" - SYSTEM_POST_ALL_ROLE_ID = "system_post_all" - SYSTEM_POST_ALL_PUBLIC_ROLE_ID = "system_post_all_public" - SYSTEM_USER_ACCESS_TOKEN_ROLE_ID = "system_user_access_token" - SYSTEM_USER_MANAGER_ROLE_ID = "system_user_manager" - SYSTEM_READ_ONLY_ADMIN_ROLE_ID = "system_read_only_admin" - SYSTEM_MANAGER_ROLE_ID = "system_manager" - - TEAM_GUEST_ROLE_ID = "team_guest" - TEAM_USER_ROLE_ID = "team_user" - TEAM_ADMIN_ROLE_ID = "team_admin" - TEAM_POST_ALL_ROLE_ID = "team_post_all" - TEAM_POST_ALL_PUBLIC_ROLE_ID = "team_post_all_public" - - CHANNEL_GUEST_ROLE_ID = "channel_guest" - CHANNEL_USER_ROLE_ID = "channel_user" - CHANNEL_ADMIN_ROLE_ID = "channel_admin" - - ROLE_NAME_MAX_LENGTH = 64 - ROLE_DISPLAY_NAME_MAX_LENGTH = 128 - ROLE_DESCRIPTION_MAX_LENGTH = 1024 - - RoleScopeSystem RoleScope = "System" - RoleScopeTeam RoleScope = "Team" - RoleScopeChannel RoleScope = "Channel" - - RoleTypeGuest RoleType = "Guest" - RoleTypeUser RoleType = "User" - RoleTypeAdmin RoleType = "Admin" -) - -type Role struct { - Id string `json:"id"` - Name string `json:"name"` - DisplayName string `json:"display_name"` - Description string `json:"description"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - Permissions []string `json:"permissions"` - SchemeManaged bool `json:"scheme_managed"` - BuiltIn bool `json:"built_in"` -} - -type RolePatch struct { - Permissions *[]string `json:"permissions"` -} - -type RolePermissions struct { - RoleID string - Permissions []string -} - -func (r *Role) ToJson() string { - b, _ := json.Marshal(r) - return string(b) -} - -func RoleFromJson(data io.Reader) *Role { - var r *Role - json.NewDecoder(data).Decode(&r) - return r -} - -func RoleListToJson(r []*Role) string { - b, _ := json.Marshal(r) - return string(b) -} - -func RoleListFromJson(data io.Reader) []*Role { - var roles []*Role - json.NewDecoder(data).Decode(&roles) - return roles -} - -func (r *RolePatch) ToJson() string { - b, _ := json.Marshal(r) - return string(b) -} - -func RolePatchFromJson(data io.Reader) *RolePatch { - var rolePatch *RolePatch - json.NewDecoder(data).Decode(&rolePatch) - return rolePatch -} - -func (r *Role) Patch(patch *RolePatch) { - if patch.Permissions != nil { - r.Permissions = *patch.Permissions - } -} - -// MergeChannelHigherScopedPermissions is meant to be invoked on a channel scheme's role and merges the higher-scoped -// channel role's permissions. -func (r *Role) MergeChannelHigherScopedPermissions(higherScopedPermissions *RolePermissions) { - mergedPermissions := []string{} - - higherScopedPermissionsMap := AsStringBoolMap(higherScopedPermissions.Permissions) - rolePermissionsMap := AsStringBoolMap(r.Permissions) - - for _, cp := range AllPermissions { - if cp.Scope != PermissionScopeChannel { - continue - } - - _, presentOnHigherScope := higherScopedPermissionsMap[cp.Id] - - // For the channel admin role always look to the higher scope to determine if the role has their permission. - // The channel admin is a special case because they're not part of the UI to be "channel moderated", only - // channel members and channel guests are. - if higherScopedPermissions.RoleID == CHANNEL_ADMIN_ROLE_ID && presentOnHigherScope { - mergedPermissions = append(mergedPermissions, cp.Id) - continue - } - - _, permissionIsModerated := ChannelModeratedPermissionsMap[cp.Id] - if permissionIsModerated { - _, presentOnRole := rolePermissionsMap[cp.Id] - if presentOnRole && presentOnHigherScope { - mergedPermissions = append(mergedPermissions, cp.Id) - } - } else { - if presentOnHigherScope { - mergedPermissions = append(mergedPermissions, cp.Id) - } - } - } - - r.Permissions = mergedPermissions -} - -// Returns an array of permissions that are in either role.Permissions -// or patch.Permissions, but not both. -func PermissionsChangedByPatch(role *Role, patch *RolePatch) []string { - var result []string - - if patch.Permissions == nil { - return result - } - - roleMap := make(map[string]bool) - patchMap := make(map[string]bool) - - for _, permission := range role.Permissions { - roleMap[permission] = true - } - - for _, permission := range *patch.Permissions { - patchMap[permission] = true - } - - for _, permission := range role.Permissions { - if !patchMap[permission] { - result = append(result, permission) - } - } - - for _, permission := range *patch.Permissions { - if !roleMap[permission] { - result = append(result, permission) - } - } - - return result -} - -func ChannelModeratedPermissionsChangedByPatch(role *Role, patch *RolePatch) []string { - var result []string - - if role == nil { - return result - } - - if patch.Permissions == nil { - return result - } - - roleMap := make(map[string]bool) - patchMap := make(map[string]bool) - - for _, permission := range role.Permissions { - if channelModeratedPermissionName, found := ChannelModeratedPermissionsMap[permission]; found { - roleMap[channelModeratedPermissionName] = true - } - } - - for _, permission := range *patch.Permissions { - if channelModeratedPermissionName, found := ChannelModeratedPermissionsMap[permission]; found { - patchMap[channelModeratedPermissionName] = true - } - } - - for permissionKey := range roleMap { - if !patchMap[permissionKey] { - result = append(result, permissionKey) - } - } - - for permissionKey := range patchMap { - if !roleMap[permissionKey] { - result = append(result, permissionKey) - } - } - - return result -} - -// GetChannelModeratedPermissions returns a map of channel moderated permissions that the role has access to -func (r *Role) GetChannelModeratedPermissions(channelType string) map[string]bool { - moderatedPermissions := make(map[string]bool) - for _, permission := range r.Permissions { - if _, found := ChannelModeratedPermissionsMap[permission]; !found { - continue - } - - for moderated, moderatedPermissionValue := range ChannelModeratedPermissionsMap { - // the moderated permission has already been found to be true so skip this iteration - if moderatedPermissions[moderatedPermissionValue] { - continue - } - - if moderated == permission { - // Special case where the channel moderated permission for `manage_members` is different depending on whether the channel is private or public - if moderated == PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id || moderated == PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id { - canManagePublic := channelType == CHANNEL_OPEN && moderated == PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id - canManagePrivate := channelType == CHANNEL_PRIVATE && moderated == PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id - moderatedPermissions[moderatedPermissionValue] = canManagePublic || canManagePrivate - } else { - moderatedPermissions[moderatedPermissionValue] = true - } - } - } - } - - return moderatedPermissions -} - -// RolePatchFromChannelModerationsPatch Creates and returns a RolePatch based on a slice of ChannelModerationPatchs, roleName is expected to be either "members" or "guests". -func (r *Role) RolePatchFromChannelModerationsPatch(channelModerationsPatch []*ChannelModerationPatch, roleName string) *RolePatch { - permissionsToAddToPatch := make(map[string]bool) - - // Iterate through the list of existing permissions on the role and append permissions that we want to keep. - for _, permission := range r.Permissions { - // Permission is not moderated so dont add it to the patch and skip the channelModerationsPatch - if _, isModerated := ChannelModeratedPermissionsMap[permission]; !isModerated { - continue - } - - permissionEnabled := true - // Check if permission has a matching moderated permission name inside the channel moderation patch - for _, channelModerationPatch := range channelModerationsPatch { - if *channelModerationPatch.Name == ChannelModeratedPermissionsMap[permission] { - // Permission key exists in patch with a value of false so skip over it - if roleName == "members" { - if channelModerationPatch.Roles.Members != nil && !*channelModerationPatch.Roles.Members { - permissionEnabled = false - } - } else if roleName == "guests" { - if channelModerationPatch.Roles.Guests != nil && !*channelModerationPatch.Roles.Guests { - permissionEnabled = false - } - } - } - } - - if permissionEnabled { - permissionsToAddToPatch[permission] = true - } - } - - // Iterate through the patch and add any permissions that dont already exist on the role - for _, channelModerationPatch := range channelModerationsPatch { - for permission, moderatedPermissionName := range ChannelModeratedPermissionsMap { - if roleName == "members" && channelModerationPatch.Roles.Members != nil && *channelModerationPatch.Roles.Members && *channelModerationPatch.Name == moderatedPermissionName { - permissionsToAddToPatch[permission] = true - } - - if roleName == "guests" && channelModerationPatch.Roles.Guests != nil && *channelModerationPatch.Roles.Guests && *channelModerationPatch.Name == moderatedPermissionName { - permissionsToAddToPatch[permission] = true - } - } - } - - patchPermissions := make([]string, 0, len(permissionsToAddToPatch)) - for permission := range permissionsToAddToPatch { - patchPermissions = append(patchPermissions, permission) - } - - return &RolePatch{Permissions: &patchPermissions} -} - -func (r *Role) IsValid() bool { - if !IsValidId(r.Id) { - return false - } - - return r.IsValidWithoutId() -} - -func (r *Role) IsValidWithoutId() bool { - if !IsValidRoleName(r.Name) { - return false - } - - if r.DisplayName == "" || len(r.DisplayName) > ROLE_DISPLAY_NAME_MAX_LENGTH { - return false - } - - if len(r.Description) > ROLE_DESCRIPTION_MAX_LENGTH { - return false - } - - check := func(perms []*Permission, permission string) bool { - for _, p := range perms { - if permission == p.Id { - return true - } - } - return false - } - for _, permission := range r.Permissions { - permissionValidated := check(AllPermissions, permission) || check(DeprecatedPermissions, permission) - if !permissionValidated { - return false - } - } - - return true -} - -func CleanRoleNames(roleNames []string) ([]string, bool) { - var cleanedRoleNames []string - for _, roleName := range roleNames { - if strings.TrimSpace(roleName) == "" { - continue - } - - if !IsValidRoleName(roleName) { - return roleNames, false - } - - cleanedRoleNames = append(cleanedRoleNames, roleName) - } - - return cleanedRoleNames, true -} - -func IsValidRoleName(roleName string) bool { - if roleName == "" || len(roleName) > ROLE_NAME_MAX_LENGTH { - return false - } - - if strings.TrimLeft(roleName, "abcdefghijklmnopqrstuvwxyz0123456789_") != "" { - return false - } - - return true -} - -func MakeDefaultRoles() map[string]*Role { - roles := make(map[string]*Role) - - roles[CHANNEL_GUEST_ROLE_ID] = &Role{ - Name: "channel_guest", - DisplayName: "authentication.roles.channel_guest.name", - Description: "authentication.roles.channel_guest.description", - Permissions: []string{ - PERMISSION_READ_CHANNEL.Id, - PERMISSION_ADD_REACTION.Id, - PERMISSION_REMOVE_REACTION.Id, - PERMISSION_UPLOAD_FILE.Id, - PERMISSION_EDIT_POST.Id, - PERMISSION_CREATE_POST.Id, - PERMISSION_USE_CHANNEL_MENTIONS.Id, - PERMISSION_USE_SLASH_COMMANDS.Id, - }, - SchemeManaged: true, - BuiltIn: true, - } - - roles[CHANNEL_USER_ROLE_ID] = &Role{ - Name: "channel_user", - DisplayName: "authentication.roles.channel_user.name", - Description: "authentication.roles.channel_user.description", - Permissions: []string{ - PERMISSION_READ_CHANNEL.Id, - PERMISSION_ADD_REACTION.Id, - PERMISSION_REMOVE_REACTION.Id, - PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id, - PERMISSION_UPLOAD_FILE.Id, - PERMISSION_GET_PUBLIC_LINK.Id, - PERMISSION_CREATE_POST.Id, - PERMISSION_USE_CHANNEL_MENTIONS.Id, - PERMISSION_USE_SLASH_COMMANDS.Id, - }, - SchemeManaged: true, - BuiltIn: true, - } - - roles[CHANNEL_ADMIN_ROLE_ID] = &Role{ - Name: "channel_admin", - DisplayName: "authentication.roles.channel_admin.name", - Description: "authentication.roles.channel_admin.description", - Permissions: []string{ - PERMISSION_MANAGE_CHANNEL_ROLES.Id, - PERMISSION_USE_GROUP_MENTIONS.Id, - }, - SchemeManaged: true, - BuiltIn: true, - } - - roles[TEAM_GUEST_ROLE_ID] = &Role{ - Name: "team_guest", - DisplayName: "authentication.roles.team_guest.name", - Description: "authentication.roles.team_guest.description", - Permissions: []string{ - PERMISSION_VIEW_TEAM.Id, - }, - SchemeManaged: true, - BuiltIn: true, - } - - roles[TEAM_USER_ROLE_ID] = &Role{ - Name: "team_user", - DisplayName: "authentication.roles.team_user.name", - Description: "authentication.roles.team_user.description", - Permissions: []string{ - PERMISSION_LIST_TEAM_CHANNELS.Id, - PERMISSION_JOIN_PUBLIC_CHANNELS.Id, - PERMISSION_READ_PUBLIC_CHANNEL.Id, - PERMISSION_VIEW_TEAM.Id, - }, - SchemeManaged: true, - BuiltIn: true, - } - - roles[TEAM_POST_ALL_ROLE_ID] = &Role{ - Name: "team_post_all", - DisplayName: "authentication.roles.team_post_all.name", - Description: "authentication.roles.team_post_all.description", - Permissions: []string{ - PERMISSION_CREATE_POST.Id, - PERMISSION_USE_CHANNEL_MENTIONS.Id, - }, - SchemeManaged: false, - BuiltIn: true, - } - - roles[TEAM_POST_ALL_PUBLIC_ROLE_ID] = &Role{ - Name: "team_post_all_public", - DisplayName: "authentication.roles.team_post_all_public.name", - Description: "authentication.roles.team_post_all_public.description", - Permissions: []string{ - PERMISSION_CREATE_POST_PUBLIC.Id, - PERMISSION_USE_CHANNEL_MENTIONS.Id, - }, - SchemeManaged: false, - BuiltIn: true, - } - - roles[TEAM_ADMIN_ROLE_ID] = &Role{ - Name: "team_admin", - DisplayName: "authentication.roles.team_admin.name", - Description: "authentication.roles.team_admin.description", - Permissions: []string{ - PERMISSION_REMOVE_USER_FROM_TEAM.Id, - PERMISSION_MANAGE_TEAM.Id, - PERMISSION_IMPORT_TEAM.Id, - PERMISSION_MANAGE_TEAM_ROLES.Id, - PERMISSION_MANAGE_CHANNEL_ROLES.Id, - PERMISSION_MANAGE_OTHERS_INCOMING_WEBHOOKS.Id, - PERMISSION_MANAGE_OTHERS_OUTGOING_WEBHOOKS.Id, - PERMISSION_MANAGE_SLASH_COMMANDS.Id, - PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id, - PERMISSION_MANAGE_INCOMING_WEBHOOKS.Id, - PERMISSION_MANAGE_OUTGOING_WEBHOOKS.Id, - PERMISSION_CONVERT_PUBLIC_CHANNEL_TO_PRIVATE.Id, - PERMISSION_CONVERT_PRIVATE_CHANNEL_TO_PUBLIC.Id, - }, - SchemeManaged: true, - BuiltIn: true, - } - - roles[SYSTEM_GUEST_ROLE_ID] = &Role{ - Name: "system_guest", - DisplayName: "authentication.roles.global_guest.name", - Description: "authentication.roles.global_guest.description", - Permissions: []string{ - PERMISSION_CREATE_DIRECT_CHANNEL.Id, - PERMISSION_CREATE_GROUP_CHANNEL.Id, - }, - SchemeManaged: true, - BuiltIn: true, - } - - roles[SYSTEM_USER_ROLE_ID] = &Role{ - Name: "system_user", - DisplayName: "authentication.roles.global_user.name", - Description: "authentication.roles.global_user.description", - Permissions: []string{ - PERMISSION_LIST_PUBLIC_TEAMS.Id, - PERMISSION_JOIN_PUBLIC_TEAMS.Id, - PERMISSION_CREATE_DIRECT_CHANNEL.Id, - PERMISSION_CREATE_GROUP_CHANNEL.Id, - PERMISSION_VIEW_MEMBERS.Id, - }, - SchemeManaged: true, - BuiltIn: true, - } - - roles[SYSTEM_POST_ALL_ROLE_ID] = &Role{ - Name: "system_post_all", - DisplayName: "authentication.roles.system_post_all.name", - Description: "authentication.roles.system_post_all.description", - Permissions: []string{ - PERMISSION_CREATE_POST.Id, - PERMISSION_USE_CHANNEL_MENTIONS.Id, - }, - SchemeManaged: false, - BuiltIn: true, - } - - roles[SYSTEM_POST_ALL_PUBLIC_ROLE_ID] = &Role{ - Name: "system_post_all_public", - DisplayName: "authentication.roles.system_post_all_public.name", - Description: "authentication.roles.system_post_all_public.description", - Permissions: []string{ - PERMISSION_CREATE_POST_PUBLIC.Id, - PERMISSION_USE_CHANNEL_MENTIONS.Id, - }, - SchemeManaged: false, - BuiltIn: true, - } - - roles[SYSTEM_USER_ACCESS_TOKEN_ROLE_ID] = &Role{ - Name: "system_user_access_token", - DisplayName: "authentication.roles.system_user_access_token.name", - Description: "authentication.roles.system_user_access_token.description", - Permissions: []string{ - PERMISSION_CREATE_USER_ACCESS_TOKEN.Id, - PERMISSION_READ_USER_ACCESS_TOKEN.Id, - PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id, - }, - SchemeManaged: false, - BuiltIn: true, - } - - roles[SYSTEM_USER_MANAGER_ROLE_ID] = &Role{ - Name: "system_user_manager", - DisplayName: "authentication.roles.system_user_manager.name", - Description: "authentication.roles.system_user_manager.description", - Permissions: SystemUserManagerDefaultPermissions, - SchemeManaged: false, - BuiltIn: true, - } - - roles[SYSTEM_READ_ONLY_ADMIN_ROLE_ID] = &Role{ - Name: "system_read_only_admin", - DisplayName: "authentication.roles.system_read_only_admin.name", - Description: "authentication.roles.system_read_only_admin.description", - Permissions: SystemReadOnlyAdminDefaultPermissions, - SchemeManaged: false, - BuiltIn: true, - } - - roles[SYSTEM_MANAGER_ROLE_ID] = &Role{ - Name: "system_manager", - DisplayName: "authentication.roles.system_manager.name", - Description: "authentication.roles.system_manager.description", - Permissions: SystemManagerDefaultPermissions, - SchemeManaged: false, - BuiltIn: true, - } - - allPermissionIDs := []string{} - for _, permission := range AllPermissions { - allPermissionIDs = append(allPermissionIDs, permission.Id) - } - - roles[SYSTEM_ADMIN_ROLE_ID] = &Role{ - Name: "system_admin", - DisplayName: "authentication.roles.global_admin.name", - Description: "authentication.roles.global_admin.description", - // System admins can do anything channel and team admins can do - // plus everything members of teams and channels can do to all teams - // and channels on the system - Permissions: allPermissionIDs, - SchemeManaged: true, - BuiltIn: true, - } - - return roles -} - -func AddAncillaryPermissions(permissions []string) []string { - for _, permission := range permissions { - if ancillaryPermissions, ok := SysconsoleAncillaryPermissions[permission]; ok { - for _, ancillaryPermission := range ancillaryPermissions { - permissions = append(permissions, ancillaryPermission.Id) - } - } - } - return permissions -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/saml.go b/vendor/github.com/mattermost/mattermost-server/v5/model/saml.go deleted file mode 100644 index feaf325a..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/saml.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "encoding/xml" - "io" - "time" -) - -const ( - USER_AUTH_SERVICE_SAML = "saml" - USER_AUTH_SERVICE_SAML_TEXT = "SAML" - USER_AUTH_SERVICE_IS_SAML = "isSaml" - USER_AUTH_SERVICE_IS_MOBILE = "isMobile" - USER_AUTH_SERVICE_IS_OAUTH = "isOAuthUser" -) - -type SamlAuthRequest struct { - Base64AuthRequest string - URL string - RelayState string -} - -type SamlCertificateStatus struct { - IdpCertificateFile bool `json:"idp_certificate_file"` - PrivateKeyFile bool `json:"private_key_file"` - PublicCertificateFile bool `json:"public_certificate_file"` -} - -type SamlMetadataResponse struct { - IdpDescriptorUrl string `json:"idp_descriptor_url"` - IdpUrl string `json:"idp_url"` - IdpPublicCertificate string `json:"idp_public_certificate"` -} - -type NameIDFormat struct { - XMLName xml.Name - Format string `xml:",attr,omitempty"` - Value string `xml:",innerxml"` -} - -type NameID struct { - NameQualifier string `xml:",attr"` - SPNameQualifier string `xml:",attr"` - Format string `xml:",attr,omitempty"` - SPProvidedID string `xml:",attr"` - Value string `xml:",chardata"` -} - -type AttributeValue struct { - Type string `xml:"http://www.w3.org/2001/XMLSchema-instance type,attr"` - Value string `xml:",chardata"` - NameID *NameID -} - -type Attribute struct { - XMLName xml.Name - FriendlyName string `xml:",attr"` - Name string `xml:",attr"` - NameFormat string `xml:",attr"` - Values []AttributeValue `xml:"AttributeValue"` -} - -type Endpoint struct { - XMLName xml.Name - Binding string `xml:"Binding,attr"` - Location string `xml:"Location,attr"` - ResponseLocation string `xml:"ResponseLocation,attr,omitempty"` -} - -type IndexedEndpoint struct { - XMLName xml.Name - Binding string `xml:"Binding,attr"` - Location string `xml:"Location,attr"` - ResponseLocation *string `xml:"ResponseLocation,attr,omitempty"` - Index int `xml:"index,attr"` - IsDefault *bool `xml:"isDefault,attr"` -} - -type IDPSSODescriptor struct { - XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata IDPSSODescriptor"` - SSODescriptor - WantAuthnRequestsSigned *bool `xml:",attr"` - - SingleSignOnServices []Endpoint `xml:"SingleSignOnService"` - NameIDMappingServices []Endpoint `xml:"NameIDMappingService"` - AssertionIDRequestServices []Endpoint `xml:"AssertionIDRequestService"` - AttributeProfiles []string `xml:"AttributeProfile"` - Attributes []Attribute `xml:"Attribute"` -} - -type SSODescriptor struct { - XMLName xml.Name - RoleDescriptor - ArtifactResolutionServices []IndexedEndpoint `xml:"ArtifactResolutionService"` - SingleLogoutServices []Endpoint `xml:"SingleLogoutService"` - ManageNameIDServices []Endpoint `xml:"ManageNameIDService"` - NameIDFormats []NameIDFormat `xml:"NameIDFormat"` -} - -type X509Certificate struct { - XMLName xml.Name - Cert string `xml:",innerxml"` -} - -type X509Data struct { - XMLName xml.Name - X509Certificate X509Certificate `xml:"X509Certificate"` -} - -type KeyInfo struct { - XMLName xml.Name - DS string `xml:"xmlns:ds,attr"` - X509Data X509Data `xml:"X509Data"` -} -type EncryptionMethod struct { - Algorithm string `xml:"Algorithm,attr"` -} - -type KeyDescriptor struct { - XMLName xml.Name - Use string `xml:"use,attr,omitempty"` - KeyInfo KeyInfo `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo,omitempty"` -} - -type RoleDescriptor struct { - XMLName xml.Name - ID string `xml:",attr,omitempty"` - ValidUntil time.Time `xml:"validUntil,attr,omitempty"` - CacheDuration time.Duration `xml:"cacheDuration,attr,omitempty"` - ProtocolSupportEnumeration string `xml:"protocolSupportEnumeration,attr"` - ErrorURL string `xml:"errorURL,attr,omitempty"` - KeyDescriptors []KeyDescriptor `xml:"KeyDescriptor,omitempty"` - Organization *Organization `xml:"Organization,omitempty"` - ContactPersons []ContactPerson `xml:"ContactPerson,omitempty"` -} - -type ContactPerson struct { - XMLName xml.Name - ContactType string `xml:"contactType,attr"` - Company string - GivenName string - SurName string - EmailAddresses []string `xml:"EmailAddress"` - TelephoneNumbers []string `xml:"TelephoneNumber"` -} - -type LocalizedName struct { - Lang string `xml:"xml lang,attr"` - Value string `xml:",chardata"` -} - -type LocalizedURI struct { - Lang string `xml:"xml lang,attr"` - Value string `xml:",chardata"` -} - -type Organization struct { - XMLName xml.Name - OrganizationNames []LocalizedName `xml:"OrganizationName"` - OrganizationDisplayNames []LocalizedName `xml:"OrganizationDisplayName"` - OrganizationURLs []LocalizedURI `xml:"OrganizationURL"` -} - -type EntityDescriptor struct { - XMLName xml.Name `xml:"urn:oasis:names:tc:SAML:2.0:metadata EntityDescriptor"` - EntityID string `xml:"entityID,attr"` - ID string `xml:",attr,omitempty"` - ValidUntil time.Time `xml:"validUntil,attr,omitempty"` - CacheDuration time.Duration `xml:"cacheDuration,attr,omitempty"` - RoleDescriptors []RoleDescriptor `xml:"RoleDescriptor"` - IDPSSODescriptors []IDPSSODescriptor `xml:"IDPSSODescriptor"` - Organization Organization `xml:"Organization"` - ContactPerson ContactPerson `xml:"ContactPerson"` -} - -func (s *SamlCertificateStatus) ToJson() string { - b, _ := json.Marshal(s) - return string(b) -} - -func SamlCertificateStatusFromJson(data io.Reader) *SamlCertificateStatus { - var status *SamlCertificateStatus - json.NewDecoder(data).Decode(&status) - return status -} - -func (s *SamlMetadataResponse) ToJson() string { - b, _ := json.Marshal(s) - return string(b) -} - -func SamlMetadataResponseFromJson(data io.Reader) *SamlMetadataResponse { - var status *SamlMetadataResponse - json.NewDecoder(data).Decode(&status) - return status -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/scheduled_task.go b/vendor/github.com/mattermost/mattermost-server/v5/model/scheduled_task.go deleted file mode 100644 index cf20db63..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/scheduled_task.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "fmt" - "time" -) - -type TaskFunc func() - -type ScheduledTask struct { - Name string `json:"name"` - Interval time.Duration `json:"interval"` - Recurring bool `json:"recurring"` - function func() - cancel chan struct{} - cancelled chan struct{} - fromNextIntervalTime bool -} - -func CreateTask(name string, function TaskFunc, timeToExecution time.Duration) *ScheduledTask { - return createTask(name, function, timeToExecution, false, false) -} - -func CreateRecurringTask(name string, function TaskFunc, interval time.Duration) *ScheduledTask { - return createTask(name, function, interval, true, false) -} - -func CreateRecurringTaskFromNextIntervalTime(name string, function TaskFunc, interval time.Duration) *ScheduledTask { - return createTask(name, function, interval, true, true) -} - -func createTask(name string, function TaskFunc, interval time.Duration, recurring bool, fromNextIntervalTime bool) *ScheduledTask { - task := &ScheduledTask{ - Name: name, - Interval: interval, - Recurring: recurring, - function: function, - cancel: make(chan struct{}), - cancelled: make(chan struct{}), - fromNextIntervalTime: fromNextIntervalTime, - } - - go func() { - defer close(task.cancelled) - - var firstTick <-chan time.Time - var ticker *time.Ticker - - if task.fromNextIntervalTime { - currTime := time.Now() - first := currTime.Truncate(interval) - if first.Before(currTime) { - first = first.Add(interval) - } - firstTick = time.After(time.Until(first)) - ticker = &time.Ticker{C: nil} - } else { - firstTick = nil - ticker = time.NewTicker(interval) - } - defer func() { - ticker.Stop() - }() - - for { - select { - case <-firstTick: - ticker = time.NewTicker(interval) - function() - case <-ticker.C: - function() - case <-task.cancel: - return - } - - if !task.Recurring { - break - } - } - }() - - return task -} - -func (task *ScheduledTask) Cancel() { - close(task.cancel) - <-task.cancelled -} - -func (task *ScheduledTask) String() string { - return fmt.Sprintf( - "%s\nInterval: %s\nRecurring: %t\n", - task.Name, - task.Interval.String(), - task.Recurring, - ) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/scheme.go b/vendor/github.com/mattermost/mattermost-server/v5/model/scheme.go deleted file mode 100644 index b5bbf34a..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/scheme.go +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "regexp" -) - -const ( - SCHEME_DISPLAY_NAME_MAX_LENGTH = 128 - SCHEME_NAME_MAX_LENGTH = 64 - SCHEME_DESCRIPTION_MAX_LENGTH = 1024 - SCHEME_SCOPE_TEAM = "team" - SCHEME_SCOPE_CHANNEL = "channel" -) - -type Scheme struct { - Id string `json:"id"` - Name string `json:"name"` - DisplayName string `json:"display_name"` - Description string `json:"description"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - Scope string `json:"scope"` - DefaultTeamAdminRole string `json:"default_team_admin_role"` - DefaultTeamUserRole string `json:"default_team_user_role"` - DefaultChannelAdminRole string `json:"default_channel_admin_role"` - DefaultChannelUserRole string `json:"default_channel_user_role"` - DefaultTeamGuestRole string `json:"default_team_guest_role"` - DefaultChannelGuestRole string `json:"default_channel_guest_role"` -} - -type SchemePatch struct { - Name *string `json:"name"` - DisplayName *string `json:"display_name"` - Description *string `json:"description"` -} - -type SchemeIDPatch struct { - SchemeID *string `json:"scheme_id"` -} - -// SchemeConveyor is used for importing and exporting a Scheme and its associated Roles. -type SchemeConveyor struct { - Name string `json:"name"` - DisplayName string `json:"display_name"` - Description string `json:"description"` - Scope string `json:"scope"` - TeamAdmin string `json:"default_team_admin_role"` - TeamUser string `json:"default_team_user_role"` - TeamGuest string `json:"default_team_guest_role"` - ChannelAdmin string `json:"default_channel_admin_role"` - ChannelUser string `json:"default_channel_user_role"` - ChannelGuest string `json:"default_channel_guest_role"` - Roles []*Role `json:"roles"` -} - -func (sc *SchemeConveyor) Scheme() *Scheme { - return &Scheme{ - DisplayName: sc.DisplayName, - Name: sc.Name, - Description: sc.Description, - Scope: sc.Scope, - DefaultTeamAdminRole: sc.TeamAdmin, - DefaultTeamUserRole: sc.TeamUser, - DefaultTeamGuestRole: sc.TeamGuest, - DefaultChannelAdminRole: sc.ChannelAdmin, - DefaultChannelUserRole: sc.ChannelUser, - DefaultChannelGuestRole: sc.ChannelGuest, - } -} - -type SchemeRoles struct { - SchemeAdmin bool `json:"scheme_admin"` - SchemeUser bool `json:"scheme_user"` - SchemeGuest bool `json:"scheme_guest"` -} - -func (scheme *Scheme) ToJson() string { - b, _ := json.Marshal(scheme) - return string(b) -} - -func SchemeFromJson(data io.Reader) *Scheme { - var scheme *Scheme - json.NewDecoder(data).Decode(&scheme) - return scheme -} - -func SchemesToJson(schemes []*Scheme) string { - b, _ := json.Marshal(schemes) - return string(b) -} - -func SchemesFromJson(data io.Reader) []*Scheme { - var schemes []*Scheme - if err := json.NewDecoder(data).Decode(&schemes); err == nil { - return schemes - } - return nil -} - -func (scheme *Scheme) IsValid() bool { - if !IsValidId(scheme.Id) { - return false - } - - return scheme.IsValidForCreate() -} - -func (scheme *Scheme) IsValidForCreate() bool { - if scheme.DisplayName == "" || len(scheme.DisplayName) > SCHEME_DISPLAY_NAME_MAX_LENGTH { - return false - } - - if !IsValidSchemeName(scheme.Name) { - return false - } - - if len(scheme.Description) > SCHEME_DESCRIPTION_MAX_LENGTH { - return false - } - - switch scheme.Scope { - case SCHEME_SCOPE_TEAM, SCHEME_SCOPE_CHANNEL: - default: - return false - } - - if !IsValidRoleName(scheme.DefaultChannelAdminRole) { - return false - } - - if !IsValidRoleName(scheme.DefaultChannelUserRole) { - return false - } - - if !IsValidRoleName(scheme.DefaultChannelGuestRole) { - return false - } - - if scheme.Scope == SCHEME_SCOPE_TEAM { - if !IsValidRoleName(scheme.DefaultTeamAdminRole) { - return false - } - - if !IsValidRoleName(scheme.DefaultTeamUserRole) { - return false - } - - if !IsValidRoleName(scheme.DefaultTeamGuestRole) { - return false - } - } - - if scheme.Scope == SCHEME_SCOPE_CHANNEL { - if scheme.DefaultTeamAdminRole != "" { - return false - } - - if scheme.DefaultTeamUserRole != "" { - return false - } - - if scheme.DefaultTeamGuestRole != "" { - return false - } - } - - return true -} - -func (scheme *Scheme) Patch(patch *SchemePatch) { - if patch.DisplayName != nil { - scheme.DisplayName = *patch.DisplayName - } - if patch.Name != nil { - scheme.Name = *patch.Name - } - if patch.Description != nil { - scheme.Description = *patch.Description - } -} - -func (patch *SchemePatch) ToJson() string { - b, _ := json.Marshal(patch) - return string(b) -} - -func SchemePatchFromJson(data io.Reader) *SchemePatch { - var patch *SchemePatch - json.NewDecoder(data).Decode(&patch) - return patch -} - -func SchemeIDFromJson(data io.Reader) *string { - var p *SchemeIDPatch - json.NewDecoder(data).Decode(&p) - return p.SchemeID -} - -func (p *SchemeIDPatch) ToJson() string { - b, _ := json.Marshal(p) - return string(b) -} - -func IsValidSchemeName(name string) bool { - re := regexp.MustCompile(fmt.Sprintf("^[a-z0-9_]{2,%d}$", SCHEME_NAME_MAX_LENGTH)) - return re.MatchString(name) -} - -func (schemeRoles *SchemeRoles) ToJson() string { - b, _ := json.Marshal(schemeRoles) - return string(b) -} - -func SchemeRolesFromJson(data io.Reader) *SchemeRoles { - var schemeRoles *SchemeRoles - json.NewDecoder(data).Decode(&schemeRoles) - return schemeRoles -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/search_params.go b/vendor/github.com/mattermost/mattermost-server/v5/model/search_params.go deleted file mode 100644 index 41a2db2a..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/search_params.go +++ /dev/null @@ -1,397 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "net/http" - "regexp" - "strings" - "time" -) - -var searchTermPuncStart = regexp.MustCompile(`^[^\pL\d\s#"]+`) -var searchTermPuncEnd = regexp.MustCompile(`[^\pL\d\s*"]+$`) - -type SearchParams struct { - Terms string - ExcludedTerms string - IsHashtag bool - InChannels []string - ExcludedChannels []string - FromUsers []string - ExcludedUsers []string - AfterDate string - ExcludedAfterDate string - BeforeDate string - ExcludedBeforeDate string - Extensions []string - ExcludedExtensions []string - OnDate string - ExcludedDate string - OrTerms bool - IncludeDeletedChannels bool - TimeZoneOffset int - // True if this search doesn't originate from a "current user". - SearchWithoutUserId bool -} - -// Returns the epoch timestamp of the start of the day specified by SearchParams.AfterDate -func (p *SearchParams) GetAfterDateMillis() int64 { - date, err := time.Parse("2006-01-02", PadDateStringZeros(p.AfterDate)) - if err != nil { - date = time.Now() - } - - // travel forward 1 day - oneDay := time.Hour * 24 - afterDate := date.Add(oneDay) - return GetStartOfDayMillis(afterDate, p.TimeZoneOffset) -} - -// Returns the epoch timestamp of the start of the day specified by SearchParams.ExcludedAfterDate -func (p *SearchParams) GetExcludedAfterDateMillis() int64 { - date, err := time.Parse("2006-01-02", PadDateStringZeros(p.ExcludedAfterDate)) - if err != nil { - date = time.Now() - } - - // travel forward 1 day - oneDay := time.Hour * 24 - afterDate := date.Add(oneDay) - return GetStartOfDayMillis(afterDate, p.TimeZoneOffset) -} - -// Returns the epoch timestamp of the end of the day specified by SearchParams.BeforeDate -func (p *SearchParams) GetBeforeDateMillis() int64 { - date, err := time.Parse("2006-01-02", PadDateStringZeros(p.BeforeDate)) - if err != nil { - return 0 - } - - // travel back 1 day - oneDay := time.Hour * -24 - beforeDate := date.Add(oneDay) - return GetEndOfDayMillis(beforeDate, p.TimeZoneOffset) -} - -// Returns the epoch timestamp of the end of the day specified by SearchParams.ExcludedBeforeDate -func (p *SearchParams) GetExcludedBeforeDateMillis() int64 { - date, err := time.Parse("2006-01-02", PadDateStringZeros(p.ExcludedBeforeDate)) - if err != nil { - return 0 - } - - // travel back 1 day - oneDay := time.Hour * -24 - beforeDate := date.Add(oneDay) - return GetEndOfDayMillis(beforeDate, p.TimeZoneOffset) -} - -// Returns the epoch timestamps of the start and end of the day specified by SearchParams.OnDate -func (p *SearchParams) GetOnDateMillis() (int64, int64) { - date, err := time.Parse("2006-01-02", PadDateStringZeros(p.OnDate)) - if err != nil { - return 0, 0 - } - - return GetStartOfDayMillis(date, p.TimeZoneOffset), GetEndOfDayMillis(date, p.TimeZoneOffset) -} - -// Returns the epoch timestamps of the start and end of the day specified by SearchParams.ExcludedDate -func (p *SearchParams) GetExcludedDateMillis() (int64, int64) { - date, err := time.Parse("2006-01-02", PadDateStringZeros(p.ExcludedDate)) - if err != nil { - return 0, 0 - } - - return GetStartOfDayMillis(date, p.TimeZoneOffset), GetEndOfDayMillis(date, p.TimeZoneOffset) -} - -var searchFlags = [...]string{"from", "channel", "in", "before", "after", "on", "ext"} - -type flag struct { - name string - value string - exclude bool -} - -type searchWord struct { - value string - exclude bool -} - -func splitWords(text string) []string { - words := []string{} - - foundQuote := false - location := 0 - for i, char := range text { - if char == '"' { - if foundQuote { - // Grab the quoted section - word := text[location : i+1] - words = append(words, word) - foundQuote = false - location = i + 1 - } else { - nextStart := i - if i > 0 && text[i-1] == '-' { - nextStart = i - 1 - } - words = append(words, strings.Fields(text[location:nextStart])...) - foundQuote = true - location = nextStart - } - } - } - - words = append(words, strings.Fields(text[location:])...) - - return words -} - -func parseSearchFlags(input []string) ([]searchWord, []flag) { - words := []searchWord{} - flags := []flag{} - - skipNextWord := false - for i, word := range input { - if skipNextWord { - skipNextWord = false - continue - } - - isFlag := false - - if colon := strings.Index(word, ":"); colon != -1 { - var flagName string - var exclude bool - if strings.HasPrefix(word, "-") { - flagName = word[1:colon] - exclude = true - } else { - flagName = word[:colon] - exclude = false - } - - value := word[colon+1:] - - for _, searchFlag := range searchFlags { - // check for case insensitive equality - if strings.EqualFold(flagName, searchFlag) { - if value != "" { - flags = append(flags, flag{ - searchFlag, - value, - exclude, - }) - isFlag = true - } else if i < len(input)-1 { - flags = append(flags, flag{ - searchFlag, - input[i+1], - exclude, - }) - skipNextWord = true - isFlag = true - } - - if isFlag { - break - } - } - } - } - - if !isFlag { - exclude := false - if strings.HasPrefix(word, "-") { - exclude = true - } - // trim off surrounding punctuation (note that we leave trailing asterisks to allow wildcards) - word = searchTermPuncStart.ReplaceAllString(word, "") - word = searchTermPuncEnd.ReplaceAllString(word, "") - - // and remove extra pound #s - word = hashtagStart.ReplaceAllString(word, "#") - - if word != "" { - words = append(words, searchWord{ - word, - exclude, - }) - } - } - } - - return words, flags -} - -func ParseSearchParams(text string, timeZoneOffset int) []*SearchParams { - words, flags := parseSearchFlags(splitWords(text)) - - hashtagTermList := []string{} - excludedHashtagTermList := []string{} - plainTermList := []string{} - excludedPlainTermList := []string{} - - for _, word := range words { - if validHashtag.MatchString(word.value) { - if word.exclude { - excludedHashtagTermList = append(excludedHashtagTermList, word.value) - } else { - hashtagTermList = append(hashtagTermList, word.value) - } - } else { - if word.exclude { - excludedPlainTermList = append(excludedPlainTermList, word.value) - } else { - plainTermList = append(plainTermList, word.value) - } - } - } - - hashtagTerms := strings.Join(hashtagTermList, " ") - excludedHashtagTerms := strings.Join(excludedHashtagTermList, " ") - plainTerms := strings.Join(plainTermList, " ") - excludedPlainTerms := strings.Join(excludedPlainTermList, " ") - - inChannels := []string{} - excludedChannels := []string{} - fromUsers := []string{} - excludedUsers := []string{} - afterDate := "" - excludedAfterDate := "" - beforeDate := "" - excludedBeforeDate := "" - onDate := "" - excludedDate := "" - excludedExtensions := []string{} - extensions := []string{} - - for _, flag := range flags { - if flag.name == "in" || flag.name == "channel" { - if flag.exclude { - excludedChannels = append(excludedChannels, flag.value) - } else { - inChannels = append(inChannels, flag.value) - } - } else if flag.name == "from" { - if flag.exclude { - excludedUsers = append(excludedUsers, flag.value) - } else { - fromUsers = append(fromUsers, flag.value) - } - } else if flag.name == "after" { - if flag.exclude { - excludedAfterDate = flag.value - } else { - afterDate = flag.value - } - } else if flag.name == "before" { - if flag.exclude { - excludedBeforeDate = flag.value - } else { - beforeDate = flag.value - } - } else if flag.name == "on" { - if flag.exclude { - excludedDate = flag.value - } else { - onDate = flag.value - } - } else if flag.name == "ext" { - if flag.exclude { - excludedExtensions = append(excludedExtensions, flag.value) - } else { - extensions = append(extensions, flag.value) - } - } - } - - paramsList := []*SearchParams{} - - if plainTerms != "" || excludedPlainTerms != "" { - paramsList = append(paramsList, &SearchParams{ - Terms: plainTerms, - ExcludedTerms: excludedPlainTerms, - IsHashtag: false, - InChannels: inChannels, - ExcludedChannels: excludedChannels, - FromUsers: fromUsers, - ExcludedUsers: excludedUsers, - AfterDate: afterDate, - ExcludedAfterDate: excludedAfterDate, - BeforeDate: beforeDate, - ExcludedBeforeDate: excludedBeforeDate, - Extensions: extensions, - ExcludedExtensions: excludedExtensions, - OnDate: onDate, - ExcludedDate: excludedDate, - TimeZoneOffset: timeZoneOffset, - }) - } - - if hashtagTerms != "" || excludedHashtagTerms != "" { - paramsList = append(paramsList, &SearchParams{ - Terms: hashtagTerms, - ExcludedTerms: excludedHashtagTerms, - IsHashtag: true, - InChannels: inChannels, - ExcludedChannels: excludedChannels, - FromUsers: fromUsers, - ExcludedUsers: excludedUsers, - AfterDate: afterDate, - ExcludedAfterDate: excludedAfterDate, - BeforeDate: beforeDate, - ExcludedBeforeDate: excludedBeforeDate, - Extensions: extensions, - ExcludedExtensions: excludedExtensions, - OnDate: onDate, - ExcludedDate: excludedDate, - TimeZoneOffset: timeZoneOffset, - }) - } - - // special case for when no terms are specified but we still have a filter - if plainTerms == "" && hashtagTerms == "" && - excludedPlainTerms == "" && excludedHashtagTerms == "" && - (len(inChannels) != 0 || len(fromUsers) != 0 || - len(excludedChannels) != 0 || len(excludedUsers) != 0 || - len(extensions) != 0 || len(excludedExtensions) != 0 || - afterDate != "" || excludedAfterDate != "" || - beforeDate != "" || excludedBeforeDate != "" || - onDate != "" || excludedDate != "") { - paramsList = append(paramsList, &SearchParams{ - Terms: "", - ExcludedTerms: "", - IsHashtag: false, - InChannels: inChannels, - ExcludedChannels: excludedChannels, - FromUsers: fromUsers, - ExcludedUsers: excludedUsers, - AfterDate: afterDate, - ExcludedAfterDate: excludedAfterDate, - BeforeDate: beforeDate, - ExcludedBeforeDate: excludedBeforeDate, - Extensions: extensions, - ExcludedExtensions: excludedExtensions, - OnDate: onDate, - ExcludedDate: excludedDate, - TimeZoneOffset: timeZoneOffset, - }) - } - - return paramsList -} - -func IsSearchParamsListValid(paramsList []*SearchParams) *AppError { - // All SearchParams should have same IncludeDeletedChannels value. - for _, params := range paramsList { - if params.IncludeDeletedChannels != paramsList[0].IncludeDeletedChannels { - return NewAppError("IsSearchParamsListValid", "model.search_params_list.is_valid.include_deleted_channels.app_error", nil, "", http.StatusInternalServerError) - } - } - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/security_bulletin.go b/vendor/github.com/mattermost/mattermost-server/v5/model/security_bulletin.go deleted file mode 100644 index 66a65812..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/security_bulletin.go +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type SecurityBulletin struct { - Id string `json:"id"` - AppliesToVersion string `json:"applies_to_version"` -} - -type SecurityBulletins []SecurityBulletin - -func (sb *SecurityBulletin) ToJson() string { - b, _ := json.Marshal(sb) - return string(b) -} - -func SecurityBulletinFromJson(data io.Reader) *SecurityBulletin { - var o *SecurityBulletin - json.NewDecoder(data).Decode(&o) - return o -} - -func (sb SecurityBulletins) ToJson() string { - b, err := json.Marshal(sb) - if err != nil { - return "[]" - } - return string(b) -} - -func SecurityBulletinsFromJson(data io.Reader) SecurityBulletins { - var o SecurityBulletins - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/session.go b/vendor/github.com/mattermost/mattermost-server/v5/model/session.go deleted file mode 100644 index 334c7175..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/session.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "strconv" - "strings" - - "github.com/mattermost/mattermost-server/v5/shared/mlog" -) - -const ( - SESSION_COOKIE_TOKEN = "MMAUTHTOKEN" - SESSION_COOKIE_USER = "MMUSERID" - SESSION_COOKIE_CSRF = "MMCSRF" - SESSION_CACHE_SIZE = 35000 - SESSION_PROP_PLATFORM = "platform" - SESSION_PROP_OS = "os" - SESSION_PROP_BROWSER = "browser" - SESSION_PROP_TYPE = "type" - SESSION_PROP_USER_ACCESS_TOKEN_ID = "user_access_token_id" - SESSION_PROP_IS_BOT = "is_bot" - SESSION_PROP_IS_BOT_VALUE = "true" - SESSION_TYPE_USER_ACCESS_TOKEN = "UserAccessToken" - SESSION_TYPE_CLOUD_KEY = "CloudKey" - SESSION_TYPE_REMOTECLUSTER_TOKEN = "RemoteClusterToken" - SESSION_PROP_IS_GUEST = "is_guest" - SESSION_ACTIVITY_TIMEOUT = 1000 * 60 * 5 // 5 minutes - SESSION_USER_ACCESS_TOKEN_EXPIRY = 100 * 365 // 100 years -) - -//msgp StringMap -type StringMap map[string]string - -//msgp:tuple Session - -// Session contains the user session details. -// This struct's serializer methods are auto-generated. If a new field is added/removed, -// please run make gen-serialized. -type Session struct { - Id string `json:"id"` - Token string `json:"token"` - CreateAt int64 `json:"create_at"` - ExpiresAt int64 `json:"expires_at"` - LastActivityAt int64 `json:"last_activity_at"` - UserId string `json:"user_id"` - DeviceId string `json:"device_id"` - Roles string `json:"roles"` - IsOAuth bool `json:"is_oauth"` - ExpiredNotify bool `json:"expired_notify"` - Props StringMap `json:"props"` - TeamMembers []*TeamMember `json:"team_members" db:"-"` - Local bool `json:"local" db:"-"` -} - -// Returns true if the session is unrestricted, which should grant it -// with all permissions. This is used for local mode sessions -func (s *Session) IsUnrestricted() bool { - return s.Local -} - -func (s *Session) DeepCopy() *Session { - copySession := *s - - if s.Props != nil { - copySession.Props = CopyStringMap(s.Props) - } - - if s.TeamMembers != nil { - copySession.TeamMembers = make([]*TeamMember, len(s.TeamMembers)) - for index, tm := range s.TeamMembers { - copySession.TeamMembers[index] = new(TeamMember) - *copySession.TeamMembers[index] = *tm - } - } - - return ©Session -} - -func (s *Session) ToJson() string { - b, _ := json.Marshal(s) - return string(b) -} - -func SessionFromJson(data io.Reader) *Session { - var s *Session - json.NewDecoder(data).Decode(&s) - return s -} - -func (s *Session) PreSave() { - if s.Id == "" { - s.Id = NewId() - } - - if s.Token == "" { - s.Token = NewId() - } - - s.CreateAt = GetMillis() - s.LastActivityAt = s.CreateAt - - if s.Props == nil { - s.Props = make(map[string]string) - } -} - -func (s *Session) Sanitize() { - s.Token = "" -} - -func (s *Session) IsExpired() bool { - - if s.ExpiresAt <= 0 { - return false - } - - if GetMillis() > s.ExpiresAt { - return true - } - - return false -} - -// Deprecated: SetExpireInDays is deprecated and should not be used. -// Use (*App).SetSessionExpireInDays instead which handles the -// cases where the new ExpiresAt is not relative to CreateAt. -func (s *Session) SetExpireInDays(days int) { - if s.CreateAt == 0 { - s.ExpiresAt = GetMillis() + (1000 * 60 * 60 * 24 * int64(days)) - } else { - s.ExpiresAt = s.CreateAt + (1000 * 60 * 60 * 24 * int64(days)) - } -} - -func (s *Session) AddProp(key string, value string) { - - if s.Props == nil { - s.Props = make(map[string]string) - } - - s.Props[key] = value -} - -func (s *Session) GetTeamByTeamId(teamId string) *TeamMember { - for _, team := range s.TeamMembers { - if team.TeamId == teamId { - return team - } - } - - return nil -} - -func (s *Session) IsMobileApp() bool { - return s.DeviceId != "" || s.IsMobile() -} - -func (s *Session) IsMobile() bool { - val, ok := s.Props[USER_AUTH_SERVICE_IS_MOBILE] - if !ok { - return false - } - isMobile, err := strconv.ParseBool(val) - if err != nil { - mlog.Debug("Error parsing boolean property from Session", mlog.Err(err)) - return false - } - return isMobile -} - -func (s *Session) IsSaml() bool { - val, ok := s.Props[USER_AUTH_SERVICE_IS_SAML] - if !ok { - return false - } - isSaml, err := strconv.ParseBool(val) - if err != nil { - mlog.Debug("Error parsing boolean property from Session", mlog.Err(err)) - return false - } - return isSaml -} - -func (s *Session) IsOAuthUser() bool { - val, ok := s.Props[USER_AUTH_SERVICE_IS_OAUTH] - if !ok { - return false - } - isOAuthUser, err := strconv.ParseBool(val) - if err != nil { - mlog.Debug("Error parsing boolean property from Session", mlog.Err(err)) - return false - } - return isOAuthUser -} - -func (s *Session) IsSSOLogin() bool { - return s.IsOAuthUser() || s.IsSaml() -} - -func (s *Session) GetUserRoles() []string { - return strings.Fields(s.Roles) -} - -func (s *Session) GenerateCSRF() string { - token := NewId() - s.AddProp("csrf", token) - return token -} - -func (s *Session) GetCSRF() string { - if s.Props == nil { - return "" - } - - return s.Props["csrf"] -} - -func SessionsToJson(o []*Session) string { - b, err := json.Marshal(o) - if err != nil { - return "[]" - } - return string(b) -} - -func SessionsFromJson(data io.Reader) []*Session { - var o []*Session - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/session_serial_gen.go b/vendor/github.com/mattermost/mattermost-server/v5/model/session_serial_gen.go deleted file mode 100644 index 612bbb89..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/session_serial_gen.go +++ /dev/null @@ -1,540 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -// Code generated by github.com/tinylib/msgp DO NOT EDIT. - -import ( - "github.com/tinylib/msgp/msgp" -) - -// DecodeMsg implements msgp.Decodable -func (z *Session) DecodeMsg(dc *msgp.Reader) (err error) { - var zb0001 uint32 - zb0001, err = dc.ReadArrayHeader() - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0001 != 13 { - err = msgp.ArrayError{Wanted: 13, Got: zb0001} - return - } - z.Id, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - z.Token, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Token") - return - } - z.CreateAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - z.ExpiresAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "ExpiresAt") - return - } - z.LastActivityAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - z.UserId, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - z.DeviceId, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "DeviceId") - return - } - z.Roles, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - z.IsOAuth, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "IsOAuth") - return - } - z.ExpiredNotify, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "ExpiredNotify") - return - } - var zb0002 uint32 - zb0002, err = dc.ReadMapHeader() - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - if z.Props == nil { - z.Props = make(StringMap, zb0002) - } else if len(z.Props) > 0 { - for key := range z.Props { - delete(z.Props, key) - } - } - for zb0002 > 0 { - zb0002-- - var za0001 string - var za0002 string - za0001, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - za0002, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Props", za0001) - return - } - z.Props[za0001] = za0002 - } - var zb0003 uint32 - zb0003, err = dc.ReadArrayHeader() - if err != nil { - err = msgp.WrapError(err, "TeamMembers") - return - } - if cap(z.TeamMembers) >= int(zb0003) { - z.TeamMembers = (z.TeamMembers)[:zb0003] - } else { - z.TeamMembers = make([]*TeamMember, zb0003) - } - for za0003 := range z.TeamMembers { - if dc.IsNil() { - err = dc.ReadNil() - if err != nil { - err = msgp.WrapError(err, "TeamMembers", za0003) - return - } - z.TeamMembers[za0003] = nil - } else { - if z.TeamMembers[za0003] == nil { - z.TeamMembers[za0003] = new(TeamMember) - } - err = z.TeamMembers[za0003].DecodeMsg(dc) - if err != nil { - err = msgp.WrapError(err, "TeamMembers", za0003) - return - } - } - } - z.Local, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "Local") - return - } - return -} - -// EncodeMsg implements msgp.Encodable -func (z *Session) EncodeMsg(en *msgp.Writer) (err error) { - // array header, size 13 - err = en.Append(0x9d) - if err != nil { - return - } - err = en.WriteString(z.Id) - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - err = en.WriteString(z.Token) - if err != nil { - err = msgp.WrapError(err, "Token") - return - } - err = en.WriteInt64(z.CreateAt) - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - err = en.WriteInt64(z.ExpiresAt) - if err != nil { - err = msgp.WrapError(err, "ExpiresAt") - return - } - err = en.WriteInt64(z.LastActivityAt) - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - err = en.WriteString(z.UserId) - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - err = en.WriteString(z.DeviceId) - if err != nil { - err = msgp.WrapError(err, "DeviceId") - return - } - err = en.WriteString(z.Roles) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - err = en.WriteBool(z.IsOAuth) - if err != nil { - err = msgp.WrapError(err, "IsOAuth") - return - } - err = en.WriteBool(z.ExpiredNotify) - if err != nil { - err = msgp.WrapError(err, "ExpiredNotify") - return - } - err = en.WriteMapHeader(uint32(len(z.Props))) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - for za0001, za0002 := range z.Props { - err = en.WriteString(za0001) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - err = en.WriteString(za0002) - if err != nil { - err = msgp.WrapError(err, "Props", za0001) - return - } - } - err = en.WriteArrayHeader(uint32(len(z.TeamMembers))) - if err != nil { - err = msgp.WrapError(err, "TeamMembers") - return - } - for za0003 := range z.TeamMembers { - if z.TeamMembers[za0003] == nil { - err = en.WriteNil() - if err != nil { - return - } - } else { - err = z.TeamMembers[za0003].EncodeMsg(en) - if err != nil { - err = msgp.WrapError(err, "TeamMembers", za0003) - return - } - } - } - err = en.WriteBool(z.Local) - if err != nil { - err = msgp.WrapError(err, "Local") - return - } - return -} - -// MarshalMsg implements msgp.Marshaler -func (z *Session) MarshalMsg(b []byte) (o []byte, err error) { - o = msgp.Require(b, z.Msgsize()) - // array header, size 13 - o = append(o, 0x9d) - o = msgp.AppendString(o, z.Id) - o = msgp.AppendString(o, z.Token) - o = msgp.AppendInt64(o, z.CreateAt) - o = msgp.AppendInt64(o, z.ExpiresAt) - o = msgp.AppendInt64(o, z.LastActivityAt) - o = msgp.AppendString(o, z.UserId) - o = msgp.AppendString(o, z.DeviceId) - o = msgp.AppendString(o, z.Roles) - o = msgp.AppendBool(o, z.IsOAuth) - o = msgp.AppendBool(o, z.ExpiredNotify) - o = msgp.AppendMapHeader(o, uint32(len(z.Props))) - for za0001, za0002 := range z.Props { - o = msgp.AppendString(o, za0001) - o = msgp.AppendString(o, za0002) - } - o = msgp.AppendArrayHeader(o, uint32(len(z.TeamMembers))) - for za0003 := range z.TeamMembers { - if z.TeamMembers[za0003] == nil { - o = msgp.AppendNil(o) - } else { - o, err = z.TeamMembers[za0003].MarshalMsg(o) - if err != nil { - err = msgp.WrapError(err, "TeamMembers", za0003) - return - } - } - } - o = msgp.AppendBool(o, z.Local) - return -} - -// UnmarshalMsg implements msgp.Unmarshaler -func (z *Session) UnmarshalMsg(bts []byte) (o []byte, err error) { - var zb0001 uint32 - zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0001 != 13 { - err = msgp.ArrayError{Wanted: 13, Got: zb0001} - return - } - z.Id, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - z.Token, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Token") - return - } - z.CreateAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - z.ExpiresAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "ExpiresAt") - return - } - z.LastActivityAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - z.UserId, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - z.DeviceId, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "DeviceId") - return - } - z.Roles, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - z.IsOAuth, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "IsOAuth") - return - } - z.ExpiredNotify, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "ExpiredNotify") - return - } - var zb0002 uint32 - zb0002, bts, err = msgp.ReadMapHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - if z.Props == nil { - z.Props = make(StringMap, zb0002) - } else if len(z.Props) > 0 { - for key := range z.Props { - delete(z.Props, key) - } - } - for zb0002 > 0 { - var za0001 string - var za0002 string - zb0002-- - za0001, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - za0002, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Props", za0001) - return - } - z.Props[za0001] = za0002 - } - var zb0003 uint32 - zb0003, bts, err = msgp.ReadArrayHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err, "TeamMembers") - return - } - if cap(z.TeamMembers) >= int(zb0003) { - z.TeamMembers = (z.TeamMembers)[:zb0003] - } else { - z.TeamMembers = make([]*TeamMember, zb0003) - } - for za0003 := range z.TeamMembers { - if msgp.IsNil(bts) { - bts, err = msgp.ReadNilBytes(bts) - if err != nil { - return - } - z.TeamMembers[za0003] = nil - } else { - if z.TeamMembers[za0003] == nil { - z.TeamMembers[za0003] = new(TeamMember) - } - bts, err = z.TeamMembers[za0003].UnmarshalMsg(bts) - if err != nil { - err = msgp.WrapError(err, "TeamMembers", za0003) - return - } - } - } - z.Local, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Local") - return - } - o = bts - return -} - -// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message -func (z *Session) Msgsize() (s int) { - s = 1 + msgp.StringPrefixSize + len(z.Id) + msgp.StringPrefixSize + len(z.Token) + msgp.Int64Size + msgp.Int64Size + msgp.Int64Size + msgp.StringPrefixSize + len(z.UserId) + msgp.StringPrefixSize + len(z.DeviceId) + msgp.StringPrefixSize + len(z.Roles) + msgp.BoolSize + msgp.BoolSize + msgp.MapHeaderSize - if z.Props != nil { - for za0001, za0002 := range z.Props { - _ = za0002 - s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002) - } - } - s += msgp.ArrayHeaderSize - for za0003 := range z.TeamMembers { - if z.TeamMembers[za0003] == nil { - s += msgp.NilSize - } else { - s += z.TeamMembers[za0003].Msgsize() - } - } - s += msgp.BoolSize - return -} - -// DecodeMsg implements msgp.Decodable -func (z *StringMap) DecodeMsg(dc *msgp.Reader) (err error) { - var zb0003 uint32 - zb0003, err = dc.ReadMapHeader() - if err != nil { - err = msgp.WrapError(err) - return - } - if (*z) == nil { - (*z) = make(StringMap, zb0003) - } else if len((*z)) > 0 { - for key := range *z { - delete((*z), key) - } - } - for zb0003 > 0 { - zb0003-- - var zb0001 string - var zb0002 string - zb0001, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err) - return - } - zb0002, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, zb0001) - return - } - (*z)[zb0001] = zb0002 - } - return -} - -// EncodeMsg implements msgp.Encodable -func (z StringMap) EncodeMsg(en *msgp.Writer) (err error) { - err = en.WriteMapHeader(uint32(len(z))) - if err != nil { - err = msgp.WrapError(err) - return - } - for zb0004, zb0005 := range z { - err = en.WriteString(zb0004) - if err != nil { - err = msgp.WrapError(err) - return - } - err = en.WriteString(zb0005) - if err != nil { - err = msgp.WrapError(err, zb0004) - return - } - } - return -} - -// MarshalMsg implements msgp.Marshaler -func (z StringMap) MarshalMsg(b []byte) (o []byte, err error) { - o = msgp.Require(b, z.Msgsize()) - o = msgp.AppendMapHeader(o, uint32(len(z))) - for zb0004, zb0005 := range z { - o = msgp.AppendString(o, zb0004) - o = msgp.AppendString(o, zb0005) - } - return -} - -// UnmarshalMsg implements msgp.Unmarshaler -func (z *StringMap) UnmarshalMsg(bts []byte) (o []byte, err error) { - var zb0003 uint32 - zb0003, bts, err = msgp.ReadMapHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - if (*z) == nil { - (*z) = make(StringMap, zb0003) - } else if len((*z)) > 0 { - for key := range *z { - delete((*z), key) - } - } - for zb0003 > 0 { - var zb0001 string - var zb0002 string - zb0003-- - zb0001, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - zb0002, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, zb0001) - return - } - (*z)[zb0001] = zb0002 - } - o = bts - return -} - -// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message -func (z StringMap) Msgsize() (s int) { - s = msgp.MapHeaderSize - if z != nil { - for zb0004, zb0005 := range z { - _ = zb0005 - s += msgp.StringPrefixSize + len(zb0004) + msgp.StringPrefixSize + len(zb0005) - } - } - return -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/shared_channel.go b/vendor/github.com/mattermost/mattermost-server/v5/model/shared_channel.go deleted file mode 100644 index e3643812..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/shared_channel.go +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" - "unicode/utf8" -) - -// SharedChannel represents a channel that can be synchronized with a remote cluster. -// If "home" is true, then the shared channel is homed locally and "SharedChannelRemote" -// table contains the remote clusters that have been invited. -// If "home" is false, then the shared channel is homed remotely, and "RemoteId" -// field points to the remote cluster connection in "RemoteClusters" table. -type SharedChannel struct { - ChannelId string `json:"id"` - TeamId string `json:"team_id"` - Home bool `json:"home"` - ReadOnly bool `json:"readonly"` - ShareName string `json:"name"` - ShareDisplayName string `json:"display_name"` - SharePurpose string `json:"purpose"` - ShareHeader string `json:"header"` - CreatorId string `json:"creator_id"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - RemoteId string `json:"remote_id,omitempty"` // if not "home" - Type string `db:"-"` -} - -func (sc *SharedChannel) ToJson() string { - b, _ := json.Marshal(sc) - return string(b) -} - -func SharedChannelFromJson(data io.Reader) (*SharedChannel, error) { - var sc *SharedChannel - err := json.NewDecoder(data).Decode(&sc) - return sc, err -} - -func (sc *SharedChannel) IsValid() *AppError { - if !IsValidId(sc.ChannelId) { - return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.id.app_error", nil, "ChannelId="+sc.ChannelId, http.StatusBadRequest) - } - - if sc.Type != CHANNEL_DIRECT && !IsValidId(sc.TeamId) { - return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.id.app_error", nil, "TeamId="+sc.TeamId, http.StatusBadRequest) - } - - if sc.CreateAt == 0 { - return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.create_at.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) - } - - if sc.UpdateAt == 0 { - return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.update_at.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) - } - - if utf8.RuneCountInString(sc.ShareDisplayName) > CHANNEL_DISPLAY_NAME_MAX_RUNES { - return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.display_name.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) - } - - if !IsValidChannelIdentifier(sc.ShareName) { - return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.2_or_more.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) - } - - if utf8.RuneCountInString(sc.ShareHeader) > CHANNEL_HEADER_MAX_RUNES { - return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.header.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) - } - - if utf8.RuneCountInString(sc.SharePurpose) > CHANNEL_PURPOSE_MAX_RUNES { - return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.purpose.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) - } - - if !IsValidId(sc.CreatorId) { - return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.creator_id.app_error", nil, "CreatorId="+sc.CreatorId, http.StatusBadRequest) - } - - if !sc.Home { - if !IsValidId(sc.RemoteId) { - return NewAppError("SharedChannel.IsValid", "model.channel.is_valid.id.app_error", nil, "RemoteId="+sc.RemoteId, http.StatusBadRequest) - } - } - return nil -} - -func (sc *SharedChannel) PreSave() { - sc.ShareName = SanitizeUnicode(sc.ShareName) - sc.ShareDisplayName = SanitizeUnicode(sc.ShareDisplayName) - - sc.CreateAt = GetMillis() - sc.UpdateAt = sc.CreateAt -} - -func (sc *SharedChannel) PreUpdate() { - sc.UpdateAt = GetMillis() - sc.ShareName = SanitizeUnicode(sc.ShareName) - sc.ShareDisplayName = SanitizeUnicode(sc.ShareDisplayName) -} - -// SharedChannelRemote represents a remote cluster that has been invited -// to a shared channel. -type SharedChannelRemote struct { - Id string `json:"id"` - ChannelId string `json:"channel_id"` - CreatorId string `json:"creator_id"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - IsInviteAccepted bool `json:"is_invite_accepted"` - IsInviteConfirmed bool `json:"is_invite_confirmed"` - RemoteId string `json:"remote_id"` - LastPostUpdateAt int64 `json:"last_post_update_at"` - LastPostId string `json:"last_post_id"` -} - -func (sc *SharedChannelRemote) ToJson() string { - b, _ := json.Marshal(sc) - return string(b) -} - -func SharedChannelRemoteFromJson(data io.Reader) (*SharedChannelRemote, error) { - var sc *SharedChannelRemote - err := json.NewDecoder(data).Decode(&sc) - return sc, err -} - -func (sc *SharedChannelRemote) IsValid() *AppError { - if !IsValidId(sc.Id) { - return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.id.app_error", nil, "Id="+sc.Id, http.StatusBadRequest) - } - - if !IsValidId(sc.ChannelId) { - return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.id.app_error", nil, "ChannelId="+sc.ChannelId, http.StatusBadRequest) - } - - if sc.CreateAt == 0 { - return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.create_at.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) - } - - if sc.UpdateAt == 0 { - return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.update_at.app_error", nil, "id="+sc.ChannelId, http.StatusBadRequest) - } - - if !IsValidId(sc.CreatorId) { - return NewAppError("SharedChannelRemote.IsValid", "model.channel.is_valid.creator_id.app_error", nil, "id="+sc.CreatorId, http.StatusBadRequest) - } - return nil -} - -func (sc *SharedChannelRemote) PreSave() { - if sc.Id == "" { - sc.Id = NewId() - } - sc.CreateAt = GetMillis() - sc.UpdateAt = sc.CreateAt -} - -func (sc *SharedChannelRemote) PreUpdate() { - sc.UpdateAt = GetMillis() -} - -type SharedChannelRemoteStatus struct { - ChannelId string `json:"channel_id"` - DisplayName string `json:"display_name"` - SiteURL string `json:"site_url"` - LastPingAt int64 `json:"last_ping_at"` - NextSyncAt int64 `json:"next_sync_at"` - ReadOnly bool `json:"readonly"` - IsInviteAccepted bool `json:"is_invite_accepted"` - Token string `json:"token"` -} - -// SharedChannelUser stores a lastSyncAt timestamp on behalf of a remote cluster for -// each user that has been synchronized. -type SharedChannelUser struct { - Id string `json:"id"` - UserId string `json:"user_id"` - ChannelId string `json:"channel_id"` - RemoteId string `json:"remote_id"` - CreateAt int64 `json:"create_at"` - LastSyncAt int64 `json:"last_sync_at"` -} - -func (scu *SharedChannelUser) PreSave() { - scu.Id = NewId() - scu.CreateAt = GetMillis() -} - -func (scu *SharedChannelUser) IsValid() *AppError { - if !IsValidId(scu.Id) { - return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.id.app_error", nil, "Id="+scu.Id, http.StatusBadRequest) - } - - if !IsValidId(scu.UserId) { - return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.id.app_error", nil, "UserId="+scu.UserId, http.StatusBadRequest) - } - - if !IsValidId(scu.ChannelId) { - return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.id.app_error", nil, "ChannelId="+scu.ChannelId, http.StatusBadRequest) - } - - if !IsValidId(scu.RemoteId) { - return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.id.app_error", nil, "RemoteId="+scu.RemoteId, http.StatusBadRequest) - } - - if scu.CreateAt == 0 { - return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) - } - return nil -} - -type GetUsersForSyncFilter struct { - CheckProfileImage bool - ChannelID string - Limit uint64 -} - -// SharedChannelAttachment stores a lastSyncAt timestamp on behalf of a remote cluster for -// each file attachment that has been synchronized. -type SharedChannelAttachment struct { - Id string `json:"id"` - FileId string `json:"file_id"` - RemoteId string `json:"remote_id"` - CreateAt int64 `json:"create_at"` - LastSyncAt int64 `json:"last_sync_at"` -} - -func (scf *SharedChannelAttachment) PreSave() { - if scf.Id == "" { - scf.Id = NewId() - } - if scf.CreateAt == 0 { - scf.CreateAt = GetMillis() - scf.LastSyncAt = scf.CreateAt - } else { - scf.LastSyncAt = GetMillis() - } -} - -func (scf *SharedChannelAttachment) IsValid() *AppError { - if !IsValidId(scf.Id) { - return NewAppError("SharedChannelAttachment.IsValid", "model.channel.is_valid.id.app_error", nil, "Id="+scf.Id, http.StatusBadRequest) - } - - if !IsValidId(scf.FileId) { - return NewAppError("SharedChannelAttachment.IsValid", "model.channel.is_valid.id.app_error", nil, "FileId="+scf.FileId, http.StatusBadRequest) - } - - if !IsValidId(scf.RemoteId) { - return NewAppError("SharedChannelAttachment.IsValid", "model.channel.is_valid.id.app_error", nil, "RemoteId="+scf.RemoteId, http.StatusBadRequest) - } - - if scf.CreateAt == 0 { - return NewAppError("SharedChannelAttachment.IsValid", "model.channel.is_valid.create_at.app_error", nil, "", http.StatusBadRequest) - } - return nil -} - -type SharedChannelFilterOpts struct { - TeamId string - CreatorId string - ExcludeHome bool - ExcludeRemote bool -} - -type SharedChannelRemoteFilterOpts struct { - ChannelId string - RemoteId string - InclUnconfirmed bool -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/slack_attachment.go b/vendor/github.com/mattermost/mattermost-server/v5/model/slack_attachment.go deleted file mode 100644 index 371baaab..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/slack_attachment.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "fmt" - "regexp" -) - -var linkWithTextRegex = regexp.MustCompile(`<([^<\|]+)\|([^>]+)>`) - -type SlackAttachment struct { - Id int64 `json:"id"` - Fallback string `json:"fallback"` - Color string `json:"color"` - Pretext string `json:"pretext"` - AuthorName string `json:"author_name"` - AuthorLink string `json:"author_link"` - AuthorIcon string `json:"author_icon"` - Title string `json:"title"` - TitleLink string `json:"title_link"` - Text string `json:"text"` - Fields []*SlackAttachmentField `json:"fields"` - ImageURL string `json:"image_url"` - ThumbURL string `json:"thumb_url"` - Footer string `json:"footer"` - FooterIcon string `json:"footer_icon"` - Timestamp interface{} `json:"ts"` // This is either a string or an int64 - Actions []*PostAction `json:"actions,omitempty"` -} - -func (s *SlackAttachment) Equals(input *SlackAttachment) bool { - // Direct comparison of simple types - - if s.Id != input.Id { - return false - } - - if s.Fallback != input.Fallback { - return false - } - - if s.Color != input.Color { - return false - } - - if s.Pretext != input.Pretext { - return false - } - - if s.AuthorName != input.AuthorName { - return false - } - - if s.AuthorLink != input.AuthorLink { - return false - } - - if s.AuthorIcon != input.AuthorIcon { - return false - } - - if s.Title != input.Title { - return false - } - - if s.TitleLink != input.TitleLink { - return false - } - - if s.Text != input.Text { - return false - } - - if s.ImageURL != input.ImageURL { - return false - } - - if s.ThumbURL != input.ThumbURL { - return false - } - - if s.Footer != input.Footer { - return false - } - - if s.FooterIcon != input.FooterIcon { - return false - } - - // Compare length & slice values of fields - if len(s.Fields) != len(input.Fields) { - return false - } - - for j := range s.Fields { - if !s.Fields[j].Equals(input.Fields[j]) { - return false - } - } - - // Compare length & slice values of actions - if len(s.Actions) != len(input.Actions) { - return false - } - - for j := range s.Actions { - if !s.Actions[j].Equals(input.Actions[j]) { - return false - } - } - - return s.Timestamp == input.Timestamp -} - -type SlackAttachmentField struct { - Title string `json:"title"` - Value interface{} `json:"value"` - Short SlackCompatibleBool `json:"short"` -} - -func (s *SlackAttachmentField) Equals(input *SlackAttachmentField) bool { - if s.Title != input.Title { - return false - } - - if s.Value != input.Value { - return false - } - - if s.Short != input.Short { - return false - } - - return true -} - -func StringifySlackFieldValue(a []*SlackAttachment) []*SlackAttachment { - var nonNilAttachments []*SlackAttachment - for _, attachment := range a { - if attachment == nil { - continue - } - nonNilAttachments = append(nonNilAttachments, attachment) - - var nonNilFields []*SlackAttachmentField - for _, field := range attachment.Fields { - if field == nil { - continue - } - nonNilFields = append(nonNilFields, field) - - if field.Value != nil { - // Ensure the value is set to a string if it is set - field.Value = fmt.Sprintf("%v", field.Value) - } - } - attachment.Fields = nonNilFields - } - return nonNilAttachments -} - -// This method only parses and processes the attachments, -// all else should be set in the post which is passed -func ParseSlackAttachment(post *Post, attachments []*SlackAttachment) { - if post.Type == "" { - post.Type = POST_SLACK_ATTACHMENT - } - - postAttachments := []*SlackAttachment{} - - for _, attachment := range attachments { - if attachment == nil { - continue - } - - attachment.Text = ParseSlackLinksToMarkdown(attachment.Text) - attachment.Pretext = ParseSlackLinksToMarkdown(attachment.Pretext) - - for _, field := range attachment.Fields { - if field == nil { - continue - } - if value, ok := field.Value.(string); ok { - field.Value = ParseSlackLinksToMarkdown(value) - } - } - postAttachments = append(postAttachments, attachment) - } - post.AddProp("attachments", postAttachments) -} - -func ParseSlackLinksToMarkdown(text string) string { - return linkWithTextRegex.ReplaceAllString(text, "[${2}](${1})") -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/slack_compatibility.go b/vendor/github.com/mattermost/mattermost-server/v5/model/slack_compatibility.go deleted file mode 100644 index 2d3e2878..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/slack_compatibility.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "fmt" - "strings" -) - -// SlackCompatibleBool is an alias for bool that implements json.Unmarshaler -type SlackCompatibleBool bool - -// UnmarshalJSON implements json.Unmarshaler -// -// Slack allows bool values to be represented as strings ("true"/"false") or -// literals (true/false). To maintain compatibility, we define an Unmarshaler -// that supports both. -func (b *SlackCompatibleBool) UnmarshalJSON(data []byte) error { - value := strings.ToLower(string(data)) - if value == "true" || value == `"true"` { - *b = true - } else if value == "false" || value == `"false"` { - *b = false - } else { - return fmt.Errorf("unmarshal: unable to convert %s to bool", data) - } - - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/status.go b/vendor/github.com/mattermost/mattermost-server/v5/model/status.go deleted file mode 100644 index f6f3a67a..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/status.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -const ( - STATUS_OUT_OF_OFFICE = "ooo" - STATUS_OFFLINE = "offline" - STATUS_AWAY = "away" - STATUS_DND = "dnd" - STATUS_ONLINE = "online" - STATUS_CACHE_SIZE = SESSION_CACHE_SIZE - STATUS_CHANNEL_TIMEOUT = 20000 // 20 seconds - STATUS_MIN_UPDATE_TIME = 120000 // 2 minutes -) - -type Status struct { - UserId string `json:"user_id"` - Status string `json:"status"` - Manual bool `json:"manual"` - LastActivityAt int64 `json:"last_activity_at"` - ActiveChannel string `json:"active_channel,omitempty" db:"-"` - DNDEndTime int64 `json:"dnd_end_time"` - PrevStatus string `json:"-"` -} - -func (o *Status) ToJson() string { - oCopy := *o - oCopy.ActiveChannel = "" - b, _ := json.Marshal(oCopy) - return string(b) -} - -func (o *Status) ToClusterJson() string { - oCopy := *o - b, _ := json.Marshal(oCopy) - return string(b) -} - -func StatusFromJson(data io.Reader) *Status { - var o *Status - json.NewDecoder(data).Decode(&o) - return o -} - -func StatusListToJson(u []*Status) string { - uCopy := make([]Status, len(u)) - for i, s := range u { - sCopy := *s - sCopy.ActiveChannel = "" - uCopy[i] = sCopy - } - - b, _ := json.Marshal(uCopy) - return string(b) -} - -func StatusListFromJson(data io.Reader) []*Status { - var statuses []*Status - json.NewDecoder(data).Decode(&statuses) - return statuses -} - -func StatusMapToInterfaceMap(statusMap map[string]*Status) map[string]interface{} { - interfaceMap := map[string]interface{}{} - for _, s := range statusMap { - // Omitted statues mean offline - if s.Status != STATUS_OFFLINE { - interfaceMap[s.UserId] = s.Status - } - } - return interfaceMap -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/suggest_command.go b/vendor/github.com/mattermost/mattermost-server/v5/model/suggest_command.go deleted file mode 100644 index 45a7af38..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/suggest_command.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type SuggestCommand struct { - Suggestion string `json:"suggestion"` - Description string `json:"description"` -} - -func (o *SuggestCommand) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func SuggestCommandFromJson(data io.Reader) *SuggestCommand { - var o *SuggestCommand - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/switch_request.go b/vendor/github.com/mattermost/mattermost-server/v5/model/switch_request.go deleted file mode 100644 index bdb90045..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/switch_request.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type SwitchRequest struct { - CurrentService string `json:"current_service"` - NewService string `json:"new_service"` - Email string `json:"email"` - Password string `json:"password"` - NewPassword string `json:"new_password"` - MfaCode string `json:"mfa_code"` - LdapLoginId string `json:"ldap_id"` -} - -func (o *SwitchRequest) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func SwitchRequestFromJson(data io.Reader) *SwitchRequest { - var o *SwitchRequest - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *SwitchRequest) EmailToOAuth() bool { - return o.CurrentService == USER_AUTH_SERVICE_EMAIL && - (o.NewService == USER_AUTH_SERVICE_SAML || - o.NewService == USER_AUTH_SERVICE_GITLAB || - o.NewService == SERVICE_GOOGLE || - o.NewService == SERVICE_OFFICE365 || - o.NewService == SERVICE_OPENID) -} - -func (o *SwitchRequest) OAuthToEmail() bool { - return (o.CurrentService == USER_AUTH_SERVICE_SAML || - o.CurrentService == USER_AUTH_SERVICE_GITLAB || - o.CurrentService == SERVICE_GOOGLE || - o.CurrentService == SERVICE_OFFICE365 || - o.CurrentService == SERVICE_OPENID) && o.NewService == USER_AUTH_SERVICE_EMAIL -} - -func (o *SwitchRequest) EmailToLdap() bool { - return o.CurrentService == USER_AUTH_SERVICE_EMAIL && o.NewService == USER_AUTH_SERVICE_LDAP -} - -func (o *SwitchRequest) LdapToEmail() bool { - return o.CurrentService == USER_AUTH_SERVICE_LDAP && o.NewService == USER_AUTH_SERVICE_EMAIL -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/system.go b/vendor/github.com/mattermost/mattermost-server/v5/model/system.go deleted file mode 100644 index b7cda1ef..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/system.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "math/big" -) - -const ( - SYSTEM_TELEMETRY_ID = "DiagnosticId" - SYSTEM_RAN_UNIT_TESTS = "RanUnitTests" - SYSTEM_LAST_SECURITY_TIME = "LastSecurityTime" - SYSTEM_ACTIVE_LICENSE_ID = "ActiveLicenseId" - SYSTEM_LICENSE_RENEWAL_TOKEN = "LicenseRenewalToken" - SYSTEM_LAST_COMPLIANCE_TIME = "LastComplianceTime" - SYSTEM_ASYMMETRIC_SIGNING_KEY = "AsymmetricSigningKey" - SYSTEM_POST_ACTION_COOKIE_SECRET = "PostActionCookieSecret" - SYSTEM_INSTALLATION_DATE_KEY = "InstallationDate" - SYSTEM_FIRST_SERVER_RUN_TIMESTAMP_KEY = "FirstServerRunTimestamp" - SYSTEM_CLUSTER_ENCRYPTION_KEY = "ClusterEncryptionKey" - SYSTEM_UPGRADED_FROM_TE_ID = "UpgradedFromTE" - SYSTEM_WARN_METRIC_NUMBER_OF_TEAMS_5 = "warn_metric_number_of_teams_5" - SYSTEM_WARN_METRIC_NUMBER_OF_CHANNELS_50 = "warn_metric_number_of_channels_50" - SYSTEM_WARN_METRIC_MFA = "warn_metric_mfa" - SYSTEM_WARN_METRIC_EMAIL_DOMAIN = "warn_metric_email_domain" - SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_100 = "warn_metric_number_of_active_users_100" - SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200 = "warn_metric_number_of_active_users_200" - SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300 = "warn_metric_number_of_active_users_300" - SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500 = "warn_metric_number_of_active_users_500" - SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M = "warn_metric_number_of_posts_2M" - SYSTEM_WARN_METRIC_LAST_RUN_TIMESTAMP_KEY = "LastWarnMetricRunTimestamp" - SYSTEM_METRIC_SUPPORT_EMAIL_NOT_CONFIGURED = "warn_metric_support_email_not_configured" - SYSTEM_FIRST_ADMIN_VISIT_MARKETPLACE = "FirstAdminVisitMarketplace" - AWS_METERING_REPORT_INTERVAL = 1 - AWS_METERING_DIMENSION_USAGE_HRS = "UsageHrs" - USER_LIMIT_OVERAGE_CYCLE_END_DATE = "UserLimitOverageCycleEndDate" - OVER_USER_LIMIT_FORGIVEN_COUNT = "OverUserLimitForgivenCount" - OVER_USER_LIMIT_LAST_EMAIL_SENT = "OverUserLimitLastEmailSent" -) - -const ( - WARN_METRIC_STATUS_LIMIT_REACHED = "true" - WARN_METRIC_STATUS_RUNONCE = "runonce" - WARN_METRIC_STATUS_ACK = "ack" - WARN_METRIC_STATUS_STORE_PREFIX = "warn_metric_" - WARN_METRIC_JOB_INTERVAL = 24 * 7 - WARN_METRIC_NUMBER_OF_ACTIVE_USERS_25 = 25 - WARN_METRIC_JOB_WAIT_TIME = 1000 * 3600 * 24 * 7 // 7 days -) - -type System struct { - Name string `json:"name"` - Value string `json:"value"` -} - -func (o *System) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func SystemFromJson(data io.Reader) *System { - var o *System - json.NewDecoder(data).Decode(&o) - return o -} - -type SystemPostActionCookieSecret struct { - Secret []byte `json:"key,omitempty"` -} - -type SystemAsymmetricSigningKey struct { - ECDSAKey *SystemECDSAKey `json:"ecdsa_key,omitempty"` -} - -type SystemECDSAKey struct { - Curve string `json:"curve"` - X *big.Int `json:"x"` - Y *big.Int `json:"y"` - D *big.Int `json:"d,omitempty"` -} - -// ServerBusyState provides serialization for app.Busy. -type ServerBusyState struct { - Busy bool `json:"busy"` - Expires int64 `json:"expires"` - Expires_ts string `json:"expires_ts,omitempty"` -} - -type SupportPacket struct { - ServerOS string `yaml:"server_os"` - ServerArchitecture string `yaml:"server_architecture"` - DatabaseType string `yaml:"database_type"` - DatabaseVersion string `yaml:"database_version"` - LdapVendorName string `yaml:"ldap_vendor_name,omitempty"` - LdapVendorVersion string `yaml:"ldap_vendor_version,omitempty"` - ElasticServerVersion string `yaml:"elastic_server_version,omitempty"` - ElasticServerPlugins []string `yaml:"elastic_server_plugins,omitempty"` -} - -type FileData struct { - Filename string - Body []byte -} - -func (sbs *ServerBusyState) ToJson() string { - b, _ := json.Marshal(sbs) - return string(b) -} - -func ServerBusyStateFromJson(r io.Reader) *ServerBusyState { - var sbs *ServerBusyState - json.NewDecoder(r).Decode(&sbs) - return sbs -} - -var WarnMetricsTable = map[string]WarnMetric{ - SYSTEM_WARN_METRIC_MFA: { - Id: SYSTEM_WARN_METRIC_MFA, - Limit: -1, - IsBotOnly: true, - IsRunOnce: true, - }, - SYSTEM_WARN_METRIC_EMAIL_DOMAIN: { - Id: SYSTEM_WARN_METRIC_EMAIL_DOMAIN, - Limit: -1, - IsBotOnly: true, - IsRunOnce: true, - }, - SYSTEM_WARN_METRIC_NUMBER_OF_TEAMS_5: { - Id: SYSTEM_WARN_METRIC_NUMBER_OF_TEAMS_5, - Limit: 5, - IsBotOnly: true, - IsRunOnce: true, - }, - SYSTEM_WARN_METRIC_NUMBER_OF_CHANNELS_50: { - Id: SYSTEM_WARN_METRIC_NUMBER_OF_CHANNELS_50, - Limit: 50, - IsBotOnly: true, - IsRunOnce: true, - }, - SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_100: { - Id: SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_100, - Limit: 100, - IsBotOnly: true, - IsRunOnce: true, - }, - SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200: { - Id: SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_200, - Limit: 200, - IsBotOnly: true, - IsRunOnce: true, - }, - SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300: { - Id: SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_300, - Limit: 300, - IsBotOnly: true, - IsRunOnce: true, - }, - SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500: { - Id: SYSTEM_WARN_METRIC_NUMBER_OF_ACTIVE_USERS_500, - Limit: 500, - IsBotOnly: false, - IsRunOnce: true, - }, - SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M: { - Id: SYSTEM_WARN_METRIC_NUMBER_OF_POSTS_2M, - Limit: 2000000, - IsBotOnly: false, - IsRunOnce: true, - }, - SYSTEM_METRIC_SUPPORT_EMAIL_NOT_CONFIGURED: { - Id: SYSTEM_METRIC_SUPPORT_EMAIL_NOT_CONFIGURED, - Limit: -1, - IsBotOnly: true, - IsRunOnce: false, - SkipAction: true, - }, -} - -type WarnMetric struct { - Id string - Limit int64 - IsBotOnly bool - IsRunOnce bool - SkipAction bool -} - -type WarnMetricDisplayTexts struct { - BotTitle string - BotMessageBody string - BotSuccessMessage string - EmailBody string -} -type WarnMetricStatus struct { - Id string `json:"id"` - Limit int64 `json:"limit"` - Acked bool `json:"acked"` - StoreStatus string `json:"store_status,omitempty"` -} - -func (wms *WarnMetricStatus) ToJson() string { - b, _ := json.Marshal(wms) - return string(b) -} - -func WarnMetricStatusFromJson(data io.Reader) *WarnMetricStatus { - var o WarnMetricStatus - if err := json.NewDecoder(data).Decode(&o); err != nil { - return nil - } - return &o -} - -func MapWarnMetricStatusToJson(o map[string]*WarnMetricStatus) string { - b, _ := json.Marshal(o) - return string(b) -} - -type SendWarnMetricAck struct { - ForceAck bool `json:"forceAck"` -} - -func (swma *SendWarnMetricAck) ToJson() string { - b, _ := json.Marshal(swma) - return string(b) -} - -func SendWarnMetricAckFromJson(r io.Reader) *SendWarnMetricAck { - var swma *SendWarnMetricAck - json.NewDecoder(r).Decode(&swma) - return swma -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/team.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team.go deleted file mode 100644 index fc752f30..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/team.go +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "regexp" - "strings" - "unicode/utf8" -) - -const ( - TEAM_OPEN = "O" - TEAM_INVITE = "I" - TEAM_ALLOWED_DOMAINS_MAX_LENGTH = 500 - TEAM_COMPANY_NAME_MAX_LENGTH = 64 - TEAM_DESCRIPTION_MAX_LENGTH = 255 - TEAM_DISPLAY_NAME_MAX_RUNES = 64 - TEAM_EMAIL_MAX_LENGTH = 128 - TEAM_NAME_MAX_LENGTH = 64 - TEAM_NAME_MIN_LENGTH = 2 -) - -type Team struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at"` - UpdateAt int64 `json:"update_at"` - DeleteAt int64 `json:"delete_at"` - DisplayName string `json:"display_name"` - Name string `json:"name"` - Description string `json:"description"` - Email string `json:"email"` - Type string `json:"type"` - CompanyName string `json:"company_name"` - AllowedDomains string `json:"allowed_domains"` - InviteId string `json:"invite_id"` - AllowOpenInvite bool `json:"allow_open_invite"` - LastTeamIconUpdate int64 `json:"last_team_icon_update,omitempty"` - SchemeId *string `json:"scheme_id"` - GroupConstrained *bool `json:"group_constrained"` - PolicyID *string `json:"policy_id" db:"-"` -} - -type TeamPatch struct { - DisplayName *string `json:"display_name"` - Description *string `json:"description"` - CompanyName *string `json:"company_name"` - AllowedDomains *string `json:"allowed_domains"` - AllowOpenInvite *bool `json:"allow_open_invite"` - GroupConstrained *bool `json:"group_constrained"` -} - -type TeamForExport struct { - Team - SchemeName *string -} - -type Invites struct { - Invites []map[string]string `json:"invites"` -} - -type TeamsWithCount struct { - Teams []*Team `json:"teams"` - TotalCount int64 `json:"total_count"` -} - -func InvitesFromJson(data io.Reader) *Invites { - var o *Invites - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *Invites) ToEmailList() []string { - emailList := make([]string, len(o.Invites)) - for _, invite := range o.Invites { - emailList = append(emailList, invite["email"]) - } - return emailList -} - -func (o *Invites) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func (o *Team) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func TeamFromJson(data io.Reader) *Team { - var o *Team - json.NewDecoder(data).Decode(&o) - return o -} - -func TeamMapToJson(u map[string]*Team) string { - b, _ := json.Marshal(u) - return string(b) -} - -func TeamMapFromJson(data io.Reader) map[string]*Team { - var teams map[string]*Team - json.NewDecoder(data).Decode(&teams) - return teams -} - -func TeamListToJson(t []*Team) string { - b, _ := json.Marshal(t) - return string(b) -} - -func TeamsWithCountToJson(tlc *TeamsWithCount) []byte { - b, _ := json.Marshal(tlc) - return b -} - -func TeamsWithCountFromJson(data io.Reader) *TeamsWithCount { - var twc *TeamsWithCount - json.NewDecoder(data).Decode(&twc) - return twc -} - -func TeamListFromJson(data io.Reader) []*Team { - var teams []*Team - json.NewDecoder(data).Decode(&teams) - return teams -} - -func (o *Team) Etag() string { - return Etag(o.Id, o.UpdateAt) -} - -func (o *Team) IsValid() *AppError { - - if !IsValidId(o.Id) { - return NewAppError("Team.IsValid", "model.team.is_valid.id.app_error", nil, "", http.StatusBadRequest) - } - - if o.CreateAt == 0 { - return NewAppError("Team.IsValid", "model.team.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if o.UpdateAt == 0 { - return NewAppError("Team.IsValid", "model.team.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if len(o.Email) > TEAM_EMAIL_MAX_LENGTH { - return NewAppError("Team.IsValid", "model.team.is_valid.email.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if o.Email != "" && !IsValidEmail(o.Email) { - return NewAppError("Team.IsValid", "model.team.is_valid.email.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if utf8.RuneCountInString(o.DisplayName) == 0 || utf8.RuneCountInString(o.DisplayName) > TEAM_DISPLAY_NAME_MAX_RUNES { - return NewAppError("Team.IsValid", "model.team.is_valid.name.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if len(o.Name) > TEAM_NAME_MAX_LENGTH { - return NewAppError("Team.IsValid", "model.team.is_valid.url.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if len(o.Description) > TEAM_DESCRIPTION_MAX_LENGTH { - return NewAppError("Team.IsValid", "model.team.is_valid.description.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if o.InviteId == "" { - return NewAppError("Team.IsValid", "model.team.is_valid.invite_id.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if IsReservedTeamName(o.Name) { - return NewAppError("Team.IsValid", "model.team.is_valid.reserved.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if !IsValidTeamName(o.Name) { - return NewAppError("Team.IsValid", "model.team.is_valid.characters.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if !(o.Type == TEAM_OPEN || o.Type == TEAM_INVITE) { - return NewAppError("Team.IsValid", "model.team.is_valid.type.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if len(o.CompanyName) > TEAM_COMPANY_NAME_MAX_LENGTH { - return NewAppError("Team.IsValid", "model.team.is_valid.company.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - if len(o.AllowedDomains) > TEAM_ALLOWED_DOMAINS_MAX_LENGTH { - return NewAppError("Team.IsValid", "model.team.is_valid.domains.app_error", nil, "id="+o.Id, http.StatusBadRequest) - } - - return nil -} - -func (o *Team) PreSave() { - if o.Id == "" { - o.Id = NewId() - } - - o.CreateAt = GetMillis() - o.UpdateAt = o.CreateAt - - o.Name = SanitizeUnicode(o.Name) - o.DisplayName = SanitizeUnicode(o.DisplayName) - o.Description = SanitizeUnicode(o.Description) - o.CompanyName = SanitizeUnicode(o.CompanyName) - - if o.InviteId == "" { - o.InviteId = NewId() - } -} - -func (o *Team) PreUpdate() { - o.UpdateAt = GetMillis() - o.Name = SanitizeUnicode(o.Name) - o.DisplayName = SanitizeUnicode(o.DisplayName) - o.Description = SanitizeUnicode(o.Description) - o.CompanyName = SanitizeUnicode(o.CompanyName) -} - -func IsReservedTeamName(s string) bool { - s = strings.ToLower(s) - - for _, value := range reservedName { - if strings.Index(s, value) == 0 { - return true - } - } - - return false -} - -func IsValidTeamName(s string) bool { - if !IsValidAlphaNum(s) { - return false - } - - if len(s) < TEAM_NAME_MIN_LENGTH { - return false - } - - return true -} - -var validTeamNameCharacter = regexp.MustCompile(`^[a-z0-9-]$`) - -func CleanTeamName(s string) string { - s = strings.ToLower(strings.Replace(s, " ", "-", -1)) - - for _, value := range reservedName { - if strings.Index(s, value) == 0 { - s = strings.Replace(s, value, "", -1) - } - } - - s = strings.TrimSpace(s) - - for _, c := range s { - char := fmt.Sprintf("%c", c) - if !validTeamNameCharacter.MatchString(char) { - s = strings.Replace(s, char, "", -1) - } - } - - s = strings.Trim(s, "-") - - if !IsValidTeamName(s) { - s = NewId() - } - - return s -} - -func (o *Team) Sanitize() { - o.Email = "" - o.InviteId = "" -} - -func (o *Team) Patch(patch *TeamPatch) { - if patch.DisplayName != nil { - o.DisplayName = *patch.DisplayName - } - - if patch.Description != nil { - o.Description = *patch.Description - } - - if patch.CompanyName != nil { - o.CompanyName = *patch.CompanyName - } - - if patch.AllowedDomains != nil { - o.AllowedDomains = *patch.AllowedDomains - } - - if patch.AllowOpenInvite != nil { - o.AllowOpenInvite = *patch.AllowOpenInvite - } - - if patch.GroupConstrained != nil { - o.GroupConstrained = patch.GroupConstrained - } -} - -func (o *Team) IsGroupConstrained() bool { - return o.GroupConstrained != nil && *o.GroupConstrained -} - -func (t *TeamPatch) ToJson() string { - b, err := json.Marshal(t) - if err != nil { - return "" - } - - return string(b) -} - -func TeamPatchFromJson(data io.Reader) *TeamPatch { - decoder := json.NewDecoder(data) - var team TeamPatch - err := decoder.Decode(&team) - if err != nil { - return nil - } - - return &team -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/team_member.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team_member.go deleted file mode 100644 index f5f1cc61..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/team_member.go +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "strings" -) - -const ( - USERNAME = "Username" -) - -//msgp:tuple TeamMember -// This struct's serializer methods are auto-generated. If a new field is added/removed, -// please run make gen-serialized. -type TeamMember struct { - TeamId string `json:"team_id"` - UserId string `json:"user_id"` - Roles string `json:"roles"` - DeleteAt int64 `json:"delete_at"` - SchemeGuest bool `json:"scheme_guest"` - SchemeUser bool `json:"scheme_user"` - SchemeAdmin bool `json:"scheme_admin"` - ExplicitRoles string `json:"explicit_roles"` -} - -//msgp:ignore TeamUnread -type TeamUnread struct { - TeamId string `json:"team_id"` - MsgCount int64 `json:"msg_count"` - MentionCount int64 `json:"mention_count"` - MentionCountRoot int64 `json:"mention_count_root"` - MsgCountRoot int64 `json:"msg_count_root"` - ThreadCount int64 `json:"thread_count"` - ThreadMentionCount int64 `json:"thread_mention_count"` -} - -//msgp:ignore TeamMemberForExport -type TeamMemberForExport struct { - TeamMember - TeamName string -} - -//msgp:ignore TeamMemberWithError -type TeamMemberWithError struct { - UserId string `json:"user_id"` - Member *TeamMember `json:"member"` - Error *AppError `json:"error"` -} - -//msgp:ignore EmailInviteWithError -type EmailInviteWithError struct { - Email string `json:"email"` - Error *AppError `json:"error"` -} - -//msgp:ignore TeamMembersGetOptions -type TeamMembersGetOptions struct { - // Sort the team members. Accepts "Username", but defaults to "Id". - Sort string - - // If true, exclude team members whose corresponding user is deleted. - ExcludeDeletedUsers bool - - // Restrict to search in a list of teams and channels - ViewRestrictions *ViewUsersRestrictions -} - -func (o *TeamMember) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func (o *TeamUnread) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func TeamMemberFromJson(data io.Reader) *TeamMember { - var o *TeamMember - json.NewDecoder(data).Decode(&o) - return o -} - -func TeamUnreadFromJson(data io.Reader) *TeamUnread { - var o *TeamUnread - json.NewDecoder(data).Decode(&o) - return o -} - -func EmailInviteWithErrorFromJson(data io.Reader) []*EmailInviteWithError { - var o []*EmailInviteWithError - json.NewDecoder(data).Decode(&o) - return o -} - -func EmailInviteWithErrorToEmails(o []*EmailInviteWithError) []string { - var ret []string - for _, o := range o { - if o.Error == nil { - ret = append(ret, o.Email) - } - } - return ret -} - -func EmailInviteWithErrorToJson(o []*EmailInviteWithError) string { - b, err := json.Marshal(o) - if err != nil { - return "[]" - } - return string(b) -} - -func EmailInviteWithErrorToString(o *EmailInviteWithError) string { - return fmt.Sprintf("%s:%s", o.Email, o.Error.Error()) -} - -func TeamMembersWithErrorToTeamMembers(o []*TeamMemberWithError) []*TeamMember { - var ret []*TeamMember - for _, o := range o { - if o.Error == nil { - ret = append(ret, o.Member) - } - } - return ret -} - -func TeamMembersWithErrorToJson(o []*TeamMemberWithError) string { - b, err := json.Marshal(o) - if err != nil { - return "[]" - } - return string(b) -} - -func TeamMemberWithErrorToString(o *TeamMemberWithError) string { - return fmt.Sprintf("%s:%s", o.UserId, o.Error.Error()) -} - -func TeamMembersWithErrorFromJson(data io.Reader) []*TeamMemberWithError { - var o []*TeamMemberWithError - json.NewDecoder(data).Decode(&o) - return o -} - -func TeamMembersToJson(o []*TeamMember) string { - b, err := json.Marshal(o) - if err != nil { - return "[]" - } - return string(b) -} - -func TeamMembersFromJson(data io.Reader) []*TeamMember { - var o []*TeamMember - json.NewDecoder(data).Decode(&o) - return o -} - -func TeamsUnreadToJson(o []*TeamUnread) string { - b, err := json.Marshal(o) - if err != nil { - return "[]" - } - return string(b) -} - -func TeamsUnreadFromJson(data io.Reader) []*TeamUnread { - var o []*TeamUnread - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *TeamMember) IsValid() *AppError { - - if !IsValidId(o.TeamId) { - return NewAppError("TeamMember.IsValid", "model.team_member.is_valid.team_id.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidId(o.UserId) { - return NewAppError("TeamMember.IsValid", "model.team_member.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (o *TeamMember) PreUpdate() { -} - -func (o *TeamMember) GetRoles() []string { - return strings.Fields(o.Roles) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/team_member_serial_gen.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team_member_serial_gen.go deleted file mode 100644 index 044a608a..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/team_member_serial_gen.go +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -// Code generated by github.com/tinylib/msgp DO NOT EDIT. - -import ( - "github.com/tinylib/msgp/msgp" -) - -// DecodeMsg implements msgp.Decodable -func (z *TeamMember) DecodeMsg(dc *msgp.Reader) (err error) { - var zb0001 uint32 - zb0001, err = dc.ReadArrayHeader() - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0001 != 8 { - err = msgp.ArrayError{Wanted: 8, Got: zb0001} - return - } - z.TeamId, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "TeamId") - return - } - z.UserId, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - z.Roles, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - z.DeleteAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - z.SchemeGuest, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "SchemeGuest") - return - } - z.SchemeUser, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "SchemeUser") - return - } - z.SchemeAdmin, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "SchemeAdmin") - return - } - z.ExplicitRoles, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "ExplicitRoles") - return - } - return -} - -// EncodeMsg implements msgp.Encodable -func (z *TeamMember) EncodeMsg(en *msgp.Writer) (err error) { - // array header, size 8 - err = en.Append(0x98) - if err != nil { - return - } - err = en.WriteString(z.TeamId) - if err != nil { - err = msgp.WrapError(err, "TeamId") - return - } - err = en.WriteString(z.UserId) - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - err = en.WriteString(z.Roles) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - err = en.WriteInt64(z.DeleteAt) - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - err = en.WriteBool(z.SchemeGuest) - if err != nil { - err = msgp.WrapError(err, "SchemeGuest") - return - } - err = en.WriteBool(z.SchemeUser) - if err != nil { - err = msgp.WrapError(err, "SchemeUser") - return - } - err = en.WriteBool(z.SchemeAdmin) - if err != nil { - err = msgp.WrapError(err, "SchemeAdmin") - return - } - err = en.WriteString(z.ExplicitRoles) - if err != nil { - err = msgp.WrapError(err, "ExplicitRoles") - return - } - return -} - -// MarshalMsg implements msgp.Marshaler -func (z *TeamMember) MarshalMsg(b []byte) (o []byte, err error) { - o = msgp.Require(b, z.Msgsize()) - // array header, size 8 - o = append(o, 0x98) - o = msgp.AppendString(o, z.TeamId) - o = msgp.AppendString(o, z.UserId) - o = msgp.AppendString(o, z.Roles) - o = msgp.AppendInt64(o, z.DeleteAt) - o = msgp.AppendBool(o, z.SchemeGuest) - o = msgp.AppendBool(o, z.SchemeUser) - o = msgp.AppendBool(o, z.SchemeAdmin) - o = msgp.AppendString(o, z.ExplicitRoles) - return -} - -// UnmarshalMsg implements msgp.Unmarshaler -func (z *TeamMember) UnmarshalMsg(bts []byte) (o []byte, err error) { - var zb0001 uint32 - zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0001 != 8 { - err = msgp.ArrayError{Wanted: 8, Got: zb0001} - return - } - z.TeamId, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "TeamId") - return - } - z.UserId, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "UserId") - return - } - z.Roles, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - z.DeleteAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - z.SchemeGuest, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "SchemeGuest") - return - } - z.SchemeUser, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "SchemeUser") - return - } - z.SchemeAdmin, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "SchemeAdmin") - return - } - z.ExplicitRoles, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "ExplicitRoles") - return - } - o = bts - return -} - -// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message -func (z *TeamMember) Msgsize() (s int) { - s = 1 + msgp.StringPrefixSize + len(z.TeamId) + msgp.StringPrefixSize + len(z.UserId) + msgp.StringPrefixSize + len(z.Roles) + msgp.Int64Size + msgp.BoolSize + msgp.BoolSize + msgp.BoolSize + msgp.StringPrefixSize + len(z.ExplicitRoles) - return -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/team_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team_search.go deleted file mode 100644 index e24b8438..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/team_search.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type TeamSearch struct { - Term string `json:"term"` - Page *int `json:"page,omitempty"` - PerPage *int `json:"per_page,omitempty"` - AllowOpenInvite *bool `json:"allow_open_invite,omitempty"` - GroupConstrained *bool `json:"group_constrained,omitempty"` - IncludeGroupConstrained *bool `json:"include_group_constrained,omitempty"` - PolicyID *string `json:"policy_id,omitempty"` - ExcludePolicyConstrained *bool `json:"exclude_policy_constrained,omitempty"` - IncludePolicyID *bool `json:"-"` - IncludeDeleted *bool `json:"-"` - TeamType *string `json:"-"` -} - -func (t *TeamSearch) IsPaginated() bool { - return t.Page != nil && t.PerPage != nil -} - -// ToJson convert a TeamSearch to json string -func (t *TeamSearch) ToJson() string { - b, err := json.Marshal(t) - if err != nil { - return "" - } - - return string(b) -} - -// TeamSearchFromJson decodes the input and returns a TeamSearch -func TeamSearchFromJson(data io.Reader) *TeamSearch { - decoder := json.NewDecoder(data) - var cs TeamSearch - err := decoder.Decode(&cs) - if err == nil { - return &cs - } - - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/team_stats.go b/vendor/github.com/mattermost/mattermost-server/v5/model/team_stats.go deleted file mode 100644 index 9209a0cf..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/team_stats.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type TeamStats struct { - TeamId string `json:"team_id"` - TotalMemberCount int64 `json:"total_member_count"` - ActiveMemberCount int64 `json:"active_member_count"` -} - -func (o *TeamStats) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func TeamStatsFromJson(data io.Reader) *TeamStats { - var o *TeamStats - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/terms_of_service.go b/vendor/github.com/mattermost/mattermost-server/v5/model/terms_of_service.go deleted file mode 100644 index 8ce5d350..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/terms_of_service.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "unicode/utf8" -) - -const TERMS_OF_SERVICE_CACHE_SIZE = 1 - -type TermsOfService struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at"` - UserId string `json:"user_id"` - Text string `json:"text"` -} - -func (t *TermsOfService) IsValid() *AppError { - if !IsValidId(t.Id) { - return InvalidTermsOfServiceError("id", "") - } - - if t.CreateAt == 0 { - return InvalidTermsOfServiceError("create_at", t.Id) - } - - if !IsValidId(t.UserId) { - return InvalidTermsOfServiceError("user_id", t.Id) - } - - if utf8.RuneCountInString(t.Text) > POST_MESSAGE_MAX_RUNES_V2 { - return InvalidTermsOfServiceError("text", t.Id) - } - - return nil -} - -func (t *TermsOfService) ToJson() string { - b, _ := json.Marshal(t) - return string(b) -} - -func TermsOfServiceFromJson(data io.Reader) *TermsOfService { - var termsOfService *TermsOfService - json.NewDecoder(data).Decode(&termsOfService) - return termsOfService -} - -func InvalidTermsOfServiceError(fieldName string, termsOfServiceId string) *AppError { - id := fmt.Sprintf("model.terms_of_service.is_valid.%s.app_error", fieldName) - details := "" - if termsOfServiceId != "" { - details = "terms_of_service_id=" + termsOfServiceId - } - return NewAppError("TermsOfService.IsValid", id, map[string]interface{}{"MaxLength": POST_MESSAGE_MAX_RUNES_V2}, details, http.StatusBadRequest) -} - -func (t *TermsOfService) PreSave() { - if t.Id == "" { - t.Id = NewId() - } - - t.CreateAt = GetMillis() -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/thread.go b/vendor/github.com/mattermost/mattermost-server/v5/model/thread.go deleted file mode 100644 index fe4a4014..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/thread.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" -) - -type Thread struct { - PostId string `json:"id"` - ChannelId string `json:"channel_id"` - ReplyCount int64 `json:"reply_count"` - LastReplyAt int64 `json:"last_reply_at"` - Participants StringArray `json:"participants"` -} - -type ThreadResponse struct { - PostId string `json:"id"` - ReplyCount int64 `json:"reply_count"` - LastReplyAt int64 `json:"last_reply_at"` - LastViewedAt int64 `json:"last_viewed_at"` - Participants []*User `json:"participants"` - Post *Post `json:"post"` - UnreadReplies int64 `json:"unread_replies"` - UnreadMentions int64 `json:"unread_mentions"` -} - -type Threads struct { - Total int64 `json:"total"` - TotalUnreadThreads int64 `json:"total_unread_threads"` - TotalUnreadMentions int64 `json:"total_unread_mentions"` - Threads []*ThreadResponse `json:"threads"` -} - -type GetUserThreadsOpts struct { - // PageSize specifies the size of the returned chunk of results. Default = 30 - PageSize uint64 - - // Extended will enrich the response with participant details. Default = false - Extended bool - - // Deleted will specify that even deleted threads should be returned (For mobile sync). Default = false - Deleted bool - - // Since filters the threads based on their LastUpdateAt timestamp. - Since uint64 - - // Before specifies thread id as a cursor for pagination and will return `PageSize` threads before the cursor - Before string - - // After specifies thread id as a cursor for pagination and will return `PageSize` threads after the cursor - After string - - // Unread will make sure that only threads with unread replies are returned - Unread bool - - // TotalsOnly will not fetch any threads and just fetch the total counts - TotalsOnly bool - - // TeamOnly will only fetch threads and unreads for the specified team and excludes DMs/GMs - TeamOnly bool -} - -func (o *ThreadResponse) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func ThreadResponseFromJson(s string) (*ThreadResponse, error) { - var t ThreadResponse - err := json.Unmarshal([]byte(s), &t) - return &t, err -} - -func (o *Threads) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func (o *Thread) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func ThreadFromJson(s string) (*Thread, error) { - var t Thread - err := json.Unmarshal([]byte(s), &t) - return &t, err -} - -func (o *Thread) Etag() string { - return Etag(o.PostId, o.LastReplyAt) -} - -type ThreadMembership struct { - PostId string `json:"post_id"` - UserId string `json:"user_id"` - Following bool `json:"following"` - LastViewed int64 `json:"last_view_at"` - LastUpdated int64 `json:"last_update_at"` - UnreadMentions int64 `json:"unread_mentions"` -} - -func (o *ThreadMembership) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/token.go b/vendor/github.com/mattermost/mattermost-server/v5/model/token.go deleted file mode 100644 index 2dcf4143..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/token.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "net/http" -) - -const ( - TOKEN_SIZE = 64 - MAX_TOKEN_EXIPRY_TIME = 1000 * 60 * 60 * 48 // 48 hour - TOKEN_TYPE_OAUTH = "oauth" -) - -type Token struct { - Token string - CreateAt int64 - Type string - Extra string -} - -func NewToken(tokentype, extra string) *Token { - return &Token{ - Token: NewRandomString(TOKEN_SIZE), - CreateAt: GetMillis(), - Type: tokentype, - Extra: extra, - } -} - -func (t *Token) IsValid() *AppError { - if len(t.Token) != TOKEN_SIZE { - return NewAppError("Token.IsValid", "model.token.is_valid.size", nil, "", http.StatusInternalServerError) - } - - if t.CreateAt == 0 { - return NewAppError("Token.IsValid", "model.token.is_valid.expiry", nil, "", http.StatusInternalServerError) - } - - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/typing_request.go b/vendor/github.com/mattermost/mattermost-server/v5/model/typing_request.go deleted file mode 100644 index e2e9d3bf..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/typing_request.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type TypingRequest struct { - ChannelId string `json:"channel_id"` - ParentId string `json:"parent_id"` -} - -func (o *TypingRequest) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func TypingRequestFromJson(data io.Reader) *TypingRequest { - var o *TypingRequest - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/upload_session.go b/vendor/github.com/mattermost/mattermost-server/v5/model/upload_session.go deleted file mode 100644 index c5f09083..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/upload_session.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "net/http" -) - -// UploadType defines the type of an upload. -type UploadType string - -const ( - UploadTypeAttachment UploadType = "attachment" - UploadTypeImport UploadType = "import" -) - -// UploadNoUserID is a "fake" user id used by the API layer when in local mode. -const UploadNoUserID = "nouser" - -// UploadSession contains information used to keep track of a file upload. -type UploadSession struct { - // The unique identifier for the session. - Id string `json:"id"` - // The type of the upload. - Type UploadType `json:"type"` - // The timestamp of creation. - CreateAt int64 `json:"create_at"` - // The id of the user performing the upload. - UserId string `json:"user_id"` - // The id of the channel to upload to. - ChannelId string `json:"channel_id,omitempty"` - // The name of the file to upload. - Filename string `json:"filename"` - // The path where the file is stored. - Path string `json:"-"` - // The size of the file to upload. - FileSize int64 `json:"file_size"` - // The amount of received data in bytes. If equal to FileSize it means the - // upload has finished. - FileOffset int64 `json:"file_offset"` - // Id of remote cluster if uploading for shared channel - RemoteId string `json:"remote_id"` - // Requested file id if uploading for shared channel - ReqFileId string `json:"req_file_id"` -} - -// ToJson serializes the UploadSession into JSON and returns it as string. -func (us *UploadSession) ToJson() string { - b, _ := json.Marshal(us) - return string(b) -} - -// UploadSessionsToJson serializes a list of UploadSession into JSON and -// returns it as string. -func UploadSessionsToJson(uss []*UploadSession) string { - b, _ := json.Marshal(uss) - return string(b) -} - -// UploadSessionsFromJson deserializes a list of UploadSession from JSON data. -func UploadSessionsFromJson(data io.Reader) []*UploadSession { - decoder := json.NewDecoder(data) - var uss []*UploadSession - if err := decoder.Decode(&uss); err != nil { - return nil - } - return uss -} - -// UploadSessionFromJson deserializes the UploadSession from JSON data. -func UploadSessionFromJson(data io.Reader) *UploadSession { - decoder := json.NewDecoder(data) - var us UploadSession - if err := decoder.Decode(&us); err != nil { - return nil - } - return &us -} - -// PreSave is a utility function used to fill required information. -func (us *UploadSession) PreSave() { - if us.Id == "" { - us.Id = NewId() - } - - if us.CreateAt == 0 { - us.CreateAt = GetMillis() - } -} - -// IsValid validates an UploadType. It returns an error in case of -// failure. -func (t UploadType) IsValid() error { - switch t { - case UploadTypeAttachment: - return nil - case UploadTypeImport: - return nil - default: - } - return fmt.Errorf("invalid UploadType %s", t) -} - -// IsValid validates an UploadSession. It returns an error in case of -// failure. -func (us *UploadSession) IsValid() *AppError { - if !IsValidId(us.Id) { - return NewAppError("UploadSession.IsValid", "model.upload_session.is_valid.id.app_error", nil, "", http.StatusBadRequest) - } - - if err := us.Type.IsValid(); err != nil { - return NewAppError("UploadSession.IsValid", "model.upload_session.is_valid.type.app_error", nil, err.Error(), http.StatusBadRequest) - } - - if !IsValidId(us.UserId) && us.UserId != UploadNoUserID { - return NewAppError("UploadSession.IsValid", "model.upload_session.is_valid.user_id.app_error", nil, "id="+us.Id, http.StatusBadRequest) - } - - if us.Type == UploadTypeAttachment && !IsValidId(us.ChannelId) { - return NewAppError("UploadSession.IsValid", "model.upload_session.is_valid.channel_id.app_error", nil, "id="+us.Id, http.StatusBadRequest) - } - - if us.CreateAt == 0 { - return NewAppError("UploadSession.IsValid", "model.upload_session.is_valid.create_at.app_error", nil, "id="+us.Id, http.StatusBadRequest) - } - - if us.Filename == "" { - return NewAppError("UploadSession.IsValid", "model.upload_session.is_valid.filename.app_error", nil, "id="+us.Id, http.StatusBadRequest) - } - - if us.FileSize <= 0 { - return NewAppError("UploadSession.IsValid", "model.upload_session.is_valid.file_size.app_error", nil, "id="+us.Id, http.StatusBadRequest) - } - - if us.FileOffset < 0 || us.FileOffset > us.FileSize { - return NewAppError("UploadSession.IsValid", "model.upload_session.is_valid.file_offset.app_error", nil, "id="+us.Id, http.StatusBadRequest) - } - - if us.Path == "" { - return NewAppError("UploadSession.IsValid", "model.upload_session.is_valid.path.app_error", nil, "id="+us.Id, http.StatusBadRequest) - } - - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user.go deleted file mode 100644 index 1745d726..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/user.go +++ /dev/null @@ -1,1002 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "crypto/sha256" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "regexp" - "sort" - "strings" - "unicode/utf8" - - "golang.org/x/crypto/bcrypt" - "golang.org/x/text/language" - - "github.com/mattermost/mattermost-server/v5/services/timezones" - "github.com/mattermost/mattermost-server/v5/shared/mlog" -) - -const ( - ME = "me" - USER_NOTIFY_ALL = "all" - USER_NOTIFY_HERE = "here" - USER_NOTIFY_MENTION = "mention" - USER_NOTIFY_NONE = "none" - DESKTOP_NOTIFY_PROP = "desktop" - DESKTOP_SOUND_NOTIFY_PROP = "desktop_sound" - MARK_UNREAD_NOTIFY_PROP = "mark_unread" - PUSH_NOTIFY_PROP = "push" - PUSH_STATUS_NOTIFY_PROP = "push_status" - EMAIL_NOTIFY_PROP = "email" - CHANNEL_MENTIONS_NOTIFY_PROP = "channel" - COMMENTS_NOTIFY_PROP = "comments" - MENTION_KEYS_NOTIFY_PROP = "mention_keys" - COMMENTS_NOTIFY_NEVER = "never" - COMMENTS_NOTIFY_ROOT = "root" - COMMENTS_NOTIFY_ANY = "any" - FIRST_NAME_NOTIFY_PROP = "first_name" - AUTO_RESPONDER_ACTIVE_NOTIFY_PROP = "auto_responder_active" - AUTO_RESPONDER_MESSAGE_NOTIFY_PROP = "auto_responder_message" - - DEFAULT_LOCALE = "en" - USER_AUTH_SERVICE_EMAIL = "email" - - USER_EMAIL_MAX_LENGTH = 128 - USER_NICKNAME_MAX_RUNES = 64 - USER_POSITION_MAX_RUNES = 128 - USER_FIRST_NAME_MAX_RUNES = 64 - USER_LAST_NAME_MAX_RUNES = 64 - USER_AUTH_DATA_MAX_LENGTH = 128 - USER_NAME_MAX_LENGTH = 64 - USER_NAME_MIN_LENGTH = 1 - USER_PASSWORD_MAX_LENGTH = 72 - USER_LOCALE_MAX_LENGTH = 5 - USER_TIMEZONE_MAX_RUNES = 256 -) - -//msgp:tuple User - -// User contains the details about the user. -// This struct's serializer methods are auto-generated. If a new field is added/removed, -// please run make gen-serialized. -type User struct { - Id string `json:"id"` - CreateAt int64 `json:"create_at,omitempty"` - UpdateAt int64 `json:"update_at,omitempty"` - DeleteAt int64 `json:"delete_at"` - Username string `json:"username"` - Password string `json:"password,omitempty"` - AuthData *string `json:"auth_data,omitempty"` - AuthService string `json:"auth_service"` - Email string `json:"email"` - EmailVerified bool `json:"email_verified,omitempty"` - Nickname string `json:"nickname"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Position string `json:"position"` - Roles string `json:"roles"` - AllowMarketing bool `json:"allow_marketing,omitempty"` - Props StringMap `json:"props,omitempty"` - NotifyProps StringMap `json:"notify_props,omitempty"` - LastPasswordUpdate int64 `json:"last_password_update,omitempty"` - LastPictureUpdate int64 `json:"last_picture_update,omitempty"` - FailedAttempts int `json:"failed_attempts,omitempty"` - Locale string `json:"locale"` - Timezone StringMap `json:"timezone"` - MfaActive bool `json:"mfa_active,omitempty"` - MfaSecret string `json:"mfa_secret,omitempty"` - RemoteId *string `json:"remote_id,omitempty"` - LastActivityAt int64 `db:"-" json:"last_activity_at,omitempty"` - IsBot bool `db:"-" json:"is_bot,omitempty"` - BotDescription string `db:"-" json:"bot_description,omitempty"` - BotLastIconUpdate int64 `db:"-" json:"bot_last_icon_update,omitempty"` - TermsOfServiceId string `db:"-" json:"terms_of_service_id,omitempty"` - TermsOfServiceCreateAt int64 `db:"-" json:"terms_of_service_create_at,omitempty"` - DisableWelcomeEmail bool `db:"-" json:"disable_welcome_email"` -} - -//msgp UserMap - -// UserMap is a map from a userId to a user object. -// It is used to generate methods which can be used for fast serialization/de-serialization. -type UserMap map[string]*User - -//msgp:ignore UserUpdate -type UserUpdate struct { - Old *User - New *User -} - -//msgp:ignore UserPatch -type UserPatch struct { - Username *string `json:"username"` - Password *string `json:"password,omitempty"` - Nickname *string `json:"nickname"` - FirstName *string `json:"first_name"` - LastName *string `json:"last_name"` - Position *string `json:"position"` - Email *string `json:"email"` - Props StringMap `json:"props,omitempty"` - NotifyProps StringMap `json:"notify_props,omitempty"` - Locale *string `json:"locale"` - Timezone StringMap `json:"timezone"` - RemoteId *string `json:"remote_id"` -} - -//msgp:ignore UserAuth -type UserAuth struct { - Password string `json:"password,omitempty"` // DEPRECATED: It is not used. - AuthData *string `json:"auth_data,omitempty"` - AuthService string `json:"auth_service,omitempty"` -} - -//msgp:ignore UserForIndexing -type UserForIndexing struct { - Id string `json:"id"` - Username string `json:"username"` - Nickname string `json:"nickname"` - FirstName string `json:"first_name"` - LastName string `json:"last_name"` - Roles string `json:"roles"` - CreateAt int64 `json:"create_at"` - DeleteAt int64 `json:"delete_at"` - TeamsIds []string `json:"team_id"` - ChannelsIds []string `json:"channel_id"` -} - -//msgp:ignore ViewUsersRestrictions -type ViewUsersRestrictions struct { - Teams []string - Channels []string -} - -func (r *ViewUsersRestrictions) Hash() string { - if r == nil { - return "" - } - ids := append(r.Teams, r.Channels...) - sort.Strings(ids) - hash := sha256.New() - hash.Write([]byte(strings.Join(ids, ""))) - return fmt.Sprintf("%x", hash.Sum(nil)) -} - -//msgp:ignore UserSlice -type UserSlice []*User - -func (u UserSlice) Usernames() []string { - usernames := []string{} - for _, user := range u { - usernames = append(usernames, user.Username) - } - sort.Strings(usernames) - return usernames -} - -func (u UserSlice) IDs() []string { - ids := []string{} - for _, user := range u { - ids = append(ids, user.Id) - } - return ids -} - -func (u UserSlice) FilterWithoutBots() UserSlice { - var matches []*User - - for _, user := range u { - if !user.IsBot { - matches = append(matches, user) - } - } - return UserSlice(matches) -} - -func (u UserSlice) FilterByActive(active bool) UserSlice { - var matches []*User - - for _, user := range u { - if user.DeleteAt == 0 && active { - matches = append(matches, user) - } else if user.DeleteAt != 0 && !active { - matches = append(matches, user) - } - } - return UserSlice(matches) -} - -func (u UserSlice) FilterByID(ids []string) UserSlice { - var matches []*User - for _, user := range u { - for _, id := range ids { - if id == user.Id { - matches = append(matches, user) - } - } - } - return UserSlice(matches) -} - -func (u UserSlice) FilterWithoutID(ids []string) UserSlice { - var keep []*User - for _, user := range u { - present := false - for _, id := range ids { - if id == user.Id { - present = true - } - } - if !present { - keep = append(keep, user) - } - } - return UserSlice(keep) -} - -func (u *User) DeepCopy() *User { - copyUser := *u - if u.AuthData != nil { - copyUser.AuthData = NewString(*u.AuthData) - } - if u.Props != nil { - copyUser.Props = CopyStringMap(u.Props) - } - if u.NotifyProps != nil { - copyUser.NotifyProps = CopyStringMap(u.NotifyProps) - } - if u.Timezone != nil { - copyUser.Timezone = CopyStringMap(u.Timezone) - } - return ©User -} - -// IsValid validates the user and returns an error if it isn't configured -// correctly. -func (u *User) IsValid() *AppError { - - if !IsValidId(u.Id) { - return InvalidUserError("id", "") - } - - if u.CreateAt == 0 { - return InvalidUserError("create_at", u.Id) - } - - if u.UpdateAt == 0 { - return InvalidUserError("update_at", u.Id) - } - - if u.IsRemote() { - if !IsValidUsernameAllowRemote(u.Username) { - return InvalidUserError("username", u.Id) - } - } else { - if !IsValidUsername(u.Username) { - return InvalidUserError("username", u.Id) - } - } - - if len(u.Email) > USER_EMAIL_MAX_LENGTH || u.Email == "" || !IsValidEmail(u.Email) { - return InvalidUserError("email", u.Id) - } - - if utf8.RuneCountInString(u.Nickname) > USER_NICKNAME_MAX_RUNES { - return InvalidUserError("nickname", u.Id) - } - - if utf8.RuneCountInString(u.Position) > USER_POSITION_MAX_RUNES { - return InvalidUserError("position", u.Id) - } - - if utf8.RuneCountInString(u.FirstName) > USER_FIRST_NAME_MAX_RUNES { - return InvalidUserError("first_name", u.Id) - } - - if utf8.RuneCountInString(u.LastName) > USER_LAST_NAME_MAX_RUNES { - return InvalidUserError("last_name", u.Id) - } - - if u.AuthData != nil && len(*u.AuthData) > USER_AUTH_DATA_MAX_LENGTH { - return InvalidUserError("auth_data", u.Id) - } - - if u.AuthData != nil && *u.AuthData != "" && u.AuthService == "" { - return InvalidUserError("auth_data_type", u.Id) - } - - if u.Password != "" && u.AuthData != nil && *u.AuthData != "" { - return InvalidUserError("auth_data_pwd", u.Id) - } - - if len(u.Password) > USER_PASSWORD_MAX_LENGTH { - return InvalidUserError("password_limit", u.Id) - } - - if !IsValidLocale(u.Locale) { - return InvalidUserError("locale", u.Id) - } - - if len(u.Timezone) > 0 { - if tzJSON, err := json.Marshal(u.Timezone); err != nil { - return NewAppError("User.IsValid", "model.user.is_valid.marshal.app_error", nil, err.Error(), http.StatusInternalServerError) - } else if utf8.RuneCount(tzJSON) > USER_TIMEZONE_MAX_RUNES { - return InvalidUserError("timezone_limit", u.Id) - } - } - - return nil -} - -func InvalidUserError(fieldName string, userId string) *AppError { - id := fmt.Sprintf("model.user.is_valid.%s.app_error", fieldName) - details := "" - if userId != "" { - details = "user_id=" + userId - } - return NewAppError("User.IsValid", id, nil, details, http.StatusBadRequest) -} - -func NormalizeUsername(username string) string { - return strings.ToLower(username) -} - -func NormalizeEmail(email string) string { - return strings.ToLower(email) -} - -// PreSave will set the Id and Username if missing. It will also fill -// in the CreateAt, UpdateAt times. It will also hash the password. It should -// be run before saving the user to the db. -func (u *User) PreSave() { - if u.Id == "" { - u.Id = NewId() - } - - if u.Username == "" { - u.Username = NewId() - } - - if u.AuthData != nil && *u.AuthData == "" { - u.AuthData = nil - } - - u.Username = SanitizeUnicode(u.Username) - u.FirstName = SanitizeUnicode(u.FirstName) - u.LastName = SanitizeUnicode(u.LastName) - u.Nickname = SanitizeUnicode(u.Nickname) - - u.Username = NormalizeUsername(u.Username) - u.Email = NormalizeEmail(u.Email) - - u.CreateAt = GetMillis() - u.UpdateAt = u.CreateAt - - u.LastPasswordUpdate = u.CreateAt - - u.MfaActive = false - - if u.Locale == "" { - u.Locale = DEFAULT_LOCALE - } - - if u.Props == nil { - u.Props = make(map[string]string) - } - - if u.NotifyProps == nil || len(u.NotifyProps) == 0 { - u.SetDefaultNotifications() - } - - if u.Timezone == nil { - u.Timezone = timezones.DefaultUserTimezone() - } - - if u.Password != "" { - u.Password = HashPassword(u.Password) - } -} - -// PreUpdate should be run before updating the user in the db. -func (u *User) PreUpdate() { - u.Username = SanitizeUnicode(u.Username) - u.FirstName = SanitizeUnicode(u.FirstName) - u.LastName = SanitizeUnicode(u.LastName) - u.Nickname = SanitizeUnicode(u.Nickname) - u.BotDescription = SanitizeUnicode(u.BotDescription) - - u.Username = NormalizeUsername(u.Username) - u.Email = NormalizeEmail(u.Email) - u.UpdateAt = GetMillis() - - u.FirstName = SanitizeUnicode(u.FirstName) - u.LastName = SanitizeUnicode(u.LastName) - u.Nickname = SanitizeUnicode(u.Nickname) - u.BotDescription = SanitizeUnicode(u.BotDescription) - - if u.AuthData != nil && *u.AuthData == "" { - u.AuthData = nil - } - - if u.NotifyProps == nil || len(u.NotifyProps) == 0 { - u.SetDefaultNotifications() - } else if _, ok := u.NotifyProps[MENTION_KEYS_NOTIFY_PROP]; ok { - // Remove any blank mention keys - splitKeys := strings.Split(u.NotifyProps[MENTION_KEYS_NOTIFY_PROP], ",") - goodKeys := []string{} - for _, key := range splitKeys { - if key != "" { - goodKeys = append(goodKeys, strings.ToLower(key)) - } - } - u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = strings.Join(goodKeys, ",") - } -} - -func (u *User) SetDefaultNotifications() { - u.NotifyProps = make(map[string]string) - u.NotifyProps[EMAIL_NOTIFY_PROP] = "true" - u.NotifyProps[PUSH_NOTIFY_PROP] = USER_NOTIFY_MENTION - u.NotifyProps[DESKTOP_NOTIFY_PROP] = USER_NOTIFY_MENTION - u.NotifyProps[DESKTOP_SOUND_NOTIFY_PROP] = "true" - u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = "" - u.NotifyProps[CHANNEL_MENTIONS_NOTIFY_PROP] = "true" - u.NotifyProps[PUSH_STATUS_NOTIFY_PROP] = STATUS_AWAY - u.NotifyProps[COMMENTS_NOTIFY_PROP] = COMMENTS_NOTIFY_NEVER - u.NotifyProps[FIRST_NAME_NOTIFY_PROP] = "false" -} - -func (u *User) UpdateMentionKeysFromUsername(oldUsername string) { - nonUsernameKeys := []string{} - for _, key := range u.GetMentionKeys() { - if key != oldUsername && key != "@"+oldUsername { - nonUsernameKeys = append(nonUsernameKeys, key) - } - } - - u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] = "" - if len(nonUsernameKeys) > 0 { - u.NotifyProps[MENTION_KEYS_NOTIFY_PROP] += "," + strings.Join(nonUsernameKeys, ",") - } -} - -func (u *User) GetMentionKeys() []string { - var keys []string - - for _, key := range strings.Split(u.NotifyProps[MENTION_KEYS_NOTIFY_PROP], ",") { - trimmedKey := strings.TrimSpace(key) - - if trimmedKey == "" { - continue - } - - keys = append(keys, trimmedKey) - } - - return keys -} - -func (u *User) Patch(patch *UserPatch) { - if patch.Username != nil { - u.Username = *patch.Username - } - - if patch.Nickname != nil { - u.Nickname = *patch.Nickname - } - - if patch.FirstName != nil { - u.FirstName = *patch.FirstName - } - - if patch.LastName != nil { - u.LastName = *patch.LastName - } - - if patch.Position != nil { - u.Position = *patch.Position - } - - if patch.Email != nil { - u.Email = *patch.Email - } - - if patch.Props != nil { - u.Props = patch.Props - } - - if patch.NotifyProps != nil { - u.NotifyProps = patch.NotifyProps - } - - if patch.Locale != nil { - u.Locale = *patch.Locale - } - - if patch.Timezone != nil { - u.Timezone = patch.Timezone - } - - if patch.RemoteId != nil { - u.RemoteId = patch.RemoteId - } -} - -// ToJson convert a User to a json string -func (u *User) ToJson() string { - b, _ := json.Marshal(u) - return string(b) -} - -func (u *UserPatch) ToJson() string { - b, _ := json.Marshal(u) - return string(b) -} - -func (u *UserAuth) ToJson() string { - b, _ := json.Marshal(u) - return string(b) -} - -// Generate a valid strong etag so the browser can cache the results -func (u *User) Etag(showFullName, showEmail bool) string { - return Etag(u.Id, u.UpdateAt, u.TermsOfServiceId, u.TermsOfServiceCreateAt, showFullName, showEmail, u.BotLastIconUpdate) -} - -// Remove any private data from the user object -func (u *User) Sanitize(options map[string]bool) { - u.Password = "" - u.AuthData = NewString("") - u.MfaSecret = "" - - if len(options) != 0 && !options["email"] { - u.Email = "" - } - if len(options) != 0 && !options["fullname"] { - u.FirstName = "" - u.LastName = "" - } - if len(options) != 0 && !options["passwordupdate"] { - u.LastPasswordUpdate = 0 - } - if len(options) != 0 && !options["authservice"] { - u.AuthService = "" - } -} - -// Remove any input data from the user object that is not user controlled -func (u *User) SanitizeInput(isAdmin bool) { - if !isAdmin { - u.AuthData = NewString("") - u.AuthService = "" - u.EmailVerified = false - } - u.LastPasswordUpdate = 0 - u.LastPictureUpdate = 0 - u.FailedAttempts = 0 - u.MfaActive = false - u.MfaSecret = "" - u.Email = strings.TrimSpace(u.Email) -} - -func (u *User) ClearNonProfileFields() { - u.Password = "" - u.AuthData = NewString("") - u.MfaSecret = "" - u.EmailVerified = false - u.AllowMarketing = false - u.NotifyProps = StringMap{} - u.LastPasswordUpdate = 0 - u.FailedAttempts = 0 -} - -func (u *User) SanitizeProfile(options map[string]bool) { - u.ClearNonProfileFields() - - u.Sanitize(options) -} - -func (u *User) MakeNonNil() { - if u.Props == nil { - u.Props = make(map[string]string) - } - - if u.NotifyProps == nil { - u.NotifyProps = make(map[string]string) - } -} - -func (u *User) AddNotifyProp(key string, value string) { - u.MakeNonNil() - - u.NotifyProps[key] = value -} - -func (u *User) SetCustomStatus(cs *CustomStatus) { - u.MakeNonNil() - u.Props[UserPropsKeyCustomStatus] = cs.ToJson() -} - -func (u *User) ClearCustomStatus() { - u.MakeNonNil() - u.Props[UserPropsKeyCustomStatus] = "" -} - -func (u *User) GetFullName() string { - if u.FirstName != "" && u.LastName != "" { - return u.FirstName + " " + u.LastName - } else if u.FirstName != "" { - return u.FirstName - } else if u.LastName != "" { - return u.LastName - } else { - return "" - } -} - -func (u *User) getDisplayName(baseName, nameFormat string) string { - displayName := baseName - - if nameFormat == SHOW_NICKNAME_FULLNAME { - if u.Nickname != "" { - displayName = u.Nickname - } else if fullName := u.GetFullName(); fullName != "" { - displayName = fullName - } - } else if nameFormat == SHOW_FULLNAME { - if fullName := u.GetFullName(); fullName != "" { - displayName = fullName - } - } - - return displayName -} - -func (u *User) GetDisplayName(nameFormat string) string { - displayName := u.Username - - return u.getDisplayName(displayName, nameFormat) -} - -func (u *User) GetDisplayNameWithPrefix(nameFormat, prefix string) string { - displayName := prefix + u.Username - - return u.getDisplayName(displayName, nameFormat) -} - -func (u *User) GetRoles() []string { - return strings.Fields(u.Roles) -} - -func (u *User) GetRawRoles() string { - return u.Roles -} - -func IsValidUserRoles(userRoles string) bool { - - roles := strings.Fields(userRoles) - - for _, r := range roles { - if !IsValidRoleName(r) { - return false - } - } - - // Exclude just the system_admin role explicitly to prevent mistakes - if len(roles) == 1 && roles[0] == "system_admin" { - return false - } - - return true -} - -// Make sure you acually want to use this function. In context.go there are functions to check permissions -// This function should not be used to check permissions. -func (u *User) IsGuest() bool { - return IsInRole(u.Roles, SYSTEM_GUEST_ROLE_ID) -} - -func (u *User) IsSystemAdmin() bool { - return IsInRole(u.Roles, SYSTEM_ADMIN_ROLE_ID) -} - -// Make sure you acually want to use this function. In context.go there are functions to check permissions -// This function should not be used to check permissions. -func (u *User) IsInRole(inRole string) bool { - return IsInRole(u.Roles, inRole) -} - -// Make sure you acually want to use this function. In context.go there are functions to check permissions -// This function should not be used to check permissions. -func IsInRole(userRoles string, inRole string) bool { - roles := strings.Split(userRoles, " ") - - for _, r := range roles { - if r == inRole { - return true - } - } - - return false -} - -func (u *User) IsSSOUser() bool { - return u.AuthService != "" && u.AuthService != USER_AUTH_SERVICE_EMAIL -} - -func (u *User) IsOAuthUser() bool { - return u.AuthService == SERVICE_GITLAB || - u.AuthService == SERVICE_GOOGLE || - u.AuthService == SERVICE_OFFICE365 || - u.AuthService == SERVICE_OPENID -} - -func (u *User) IsLDAPUser() bool { - return u.AuthService == USER_AUTH_SERVICE_LDAP -} - -func (u *User) IsSAMLUser() bool { - return u.AuthService == USER_AUTH_SERVICE_SAML -} - -func (u *User) GetPreferredTimezone() string { - return GetPreferredTimezone(u.Timezone) -} - -// IsRemote returns true if the user belongs to a remote cluster (has RemoteId). -func (u *User) IsRemote() bool { - return u.RemoteId != nil && *u.RemoteId != "" -} - -// GetRemoteID returns the remote id for this user or "" if not a remote user. -func (u *User) GetRemoteID() string { - if u.RemoteId != nil { - return *u.RemoteId - } - return "" -} - -// GetProp fetches a prop value by name. -func (u *User) GetProp(name string) (string, bool) { - val, ok := u.Props[name] - return val, ok -} - -// SetProp sets a prop value by name, creating the map if nil. -// Not thread safe. -func (u *User) SetProp(name string, value string) { - if u.Props == nil { - u.Props = make(map[string]string) - } - u.Props[name] = value -} - -func (u *User) ToPatch() *UserPatch { - return &UserPatch{ - Username: &u.Username, Password: &u.Password, - Nickname: &u.Nickname, FirstName: &u.FirstName, LastName: &u.LastName, - Position: &u.Position, Email: &u.Email, - Props: u.Props, NotifyProps: u.NotifyProps, - Locale: &u.Locale, Timezone: u.Timezone, - } -} - -func (u *UserPatch) SetField(fieldName string, fieldValue string) { - switch fieldName { - case "FirstName": - u.FirstName = &fieldValue - case "LastName": - u.LastName = &fieldValue - case "Nickname": - u.Nickname = &fieldValue - case "Email": - u.Email = &fieldValue - case "Position": - u.Position = &fieldValue - case "Username": - u.Username = &fieldValue - } -} - -// UserFromJson will decode the input and return a User -func UserFromJson(data io.Reader) *User { - var user *User - json.NewDecoder(data).Decode(&user) - return user -} - -func UserPatchFromJson(data io.Reader) *UserPatch { - var user *UserPatch - json.NewDecoder(data).Decode(&user) - return user -} - -func UserAuthFromJson(data io.Reader) *UserAuth { - var user *UserAuth - json.NewDecoder(data).Decode(&user) - return user -} - -func UserMapToJson(u map[string]*User) string { - b, _ := json.Marshal(u) - return string(b) -} - -func UserMapFromJson(data io.Reader) map[string]*User { - var users map[string]*User - json.NewDecoder(data).Decode(&users) - return users -} - -func UserListToJson(u []*User) string { - b, _ := json.Marshal(u) - return string(b) -} - -func UserListFromJson(data io.Reader) []*User { - var users []*User - json.NewDecoder(data).Decode(&users) - return users -} - -// HashPassword generates a hash using the bcrypt.GenerateFromPassword -func HashPassword(password string) string { - hash, err := bcrypt.GenerateFromPassword([]byte(password), 10) - if err != nil { - panic(err) - } - - return string(hash) -} - -// ComparePassword compares the hash -// This function is deprecated and will be removed in a future release. -func ComparePassword(hash string, password string) bool { - - if password == "" || hash == "" { - return false - } - - err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) - return err == nil -} - -var validUsernameChars = regexp.MustCompile(`^[a-z0-9\.\-_]+$`) -var validUsernameCharsForRemote = regexp.MustCompile(`^[a-z0-9\.\-_:]+$`) - -var restrictedUsernames = map[string]struct{}{ - "all": {}, - "channel": {}, - "matterbot": {}, - "system": {}, -} - -func IsValidUsername(s string) bool { - if len(s) < USER_NAME_MIN_LENGTH || len(s) > USER_NAME_MAX_LENGTH { - return false - } - - if !validUsernameChars.MatchString(s) { - return false - } - - _, found := restrictedUsernames[s] - return !found -} - -func IsValidUsernameAllowRemote(s string) bool { - if len(s) < USER_NAME_MIN_LENGTH || len(s) > USER_NAME_MAX_LENGTH { - return false - } - - if !validUsernameCharsForRemote.MatchString(s) { - return false - } - - _, found := restrictedUsernames[s] - return !found -} - -func CleanUsername(username string) string { - s := NormalizeUsername(strings.Replace(username, " ", "-", -1)) - - for _, value := range reservedName { - if s == value { - s = strings.Replace(s, value, "", -1) - } - } - - s = strings.TrimSpace(s) - - for _, c := range s { - char := fmt.Sprintf("%c", c) - if !validUsernameChars.MatchString(char) { - s = strings.Replace(s, char, "-", -1) - } - } - - s = strings.Trim(s, "-") - - if !IsValidUsername(s) { - s = "a" + NewId() - mlog.Warn("Generating new username since provided username was invalid", - mlog.String("provided_username", username), mlog.String("new_username", s)) - } - - return s -} - -func IsValidUserNotifyLevel(notifyLevel string) bool { - return notifyLevel == CHANNEL_NOTIFY_ALL || - notifyLevel == CHANNEL_NOTIFY_MENTION || - notifyLevel == CHANNEL_NOTIFY_NONE -} - -func IsValidPushStatusNotifyLevel(notifyLevel string) bool { - return notifyLevel == STATUS_ONLINE || - notifyLevel == STATUS_AWAY || - notifyLevel == STATUS_OFFLINE -} - -func IsValidCommentsNotifyLevel(notifyLevel string) bool { - return notifyLevel == COMMENTS_NOTIFY_ANY || - notifyLevel == COMMENTS_NOTIFY_ROOT || - notifyLevel == COMMENTS_NOTIFY_NEVER -} - -func IsValidEmailBatchingInterval(emailInterval string) bool { - return emailInterval == PREFERENCE_EMAIL_INTERVAL_IMMEDIATELY || - emailInterval == PREFERENCE_EMAIL_INTERVAL_FIFTEEN || - emailInterval == PREFERENCE_EMAIL_INTERVAL_HOUR -} - -func IsValidLocale(locale string) bool { - if locale != "" { - if len(locale) > USER_LOCALE_MAX_LENGTH { - return false - } else if _, err := language.Parse(locale); err != nil { - return false - } - } - - return true -} - -//msgp:ignore UserWithGroups -type UserWithGroups struct { - User - GroupIDs *string `json:"-"` - Groups []*Group `json:"groups"` - SchemeGuest bool `json:"scheme_guest"` - SchemeUser bool `json:"scheme_user"` - SchemeAdmin bool `json:"scheme_admin"` -} - -func (u *UserWithGroups) GetGroupIDs() []string { - if u.GroupIDs == nil { - return nil - } - trimmed := strings.TrimSpace(*u.GroupIDs) - if trimmed == "" { - return nil - } - return strings.Split(trimmed, ",") -} - -//msgp:ignore UsersWithGroupsAndCount -type UsersWithGroupsAndCount struct { - Users []*UserWithGroups `json:"users"` - Count int64 `json:"total_count"` -} - -func UsersWithGroupsAndCountFromJson(data io.Reader) *UsersWithGroupsAndCount { - uwg := &UsersWithGroupsAndCount{} - bodyBytes, _ := ioutil.ReadAll(data) - json.Unmarshal(bodyBytes, uwg) - return uwg -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token.go deleted file mode 100644 index f458a6d9..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - "net/http" -) - -type UserAccessToken struct { - Id string `json:"id"` - Token string `json:"token,omitempty"` - UserId string `json:"user_id"` - Description string `json:"description"` - IsActive bool `json:"is_active"` -} - -func (t *UserAccessToken) IsValid() *AppError { - if !IsValidId(t.Id) { - return NewAppError("UserAccessToken.IsValid", "model.user_access_token.is_valid.id.app_error", nil, "", http.StatusBadRequest) - } - - if len(t.Token) != 26 { - return NewAppError("UserAccessToken.IsValid", "model.user_access_token.is_valid.token.app_error", nil, "", http.StatusBadRequest) - } - - if !IsValidId(t.UserId) { - return NewAppError("UserAccessToken.IsValid", "model.user_access_token.is_valid.user_id.app_error", nil, "", http.StatusBadRequest) - } - - if len(t.Description) > 255 { - return NewAppError("UserAccessToken.IsValid", "model.user_access_token.is_valid.description.app_error", nil, "", http.StatusBadRequest) - } - - return nil -} - -func (t *UserAccessToken) PreSave() { - t.Id = NewId() - t.IsActive = true -} - -func (t *UserAccessToken) ToJson() string { - b, _ := json.Marshal(t) - return string(b) -} - -func UserAccessTokenFromJson(data io.Reader) *UserAccessToken { - var t *UserAccessToken - json.NewDecoder(data).Decode(&t) - return t -} - -func UserAccessTokenListToJson(t []*UserAccessToken) string { - b, _ := json.Marshal(t) - return string(b) -} - -func UserAccessTokenListFromJson(data io.Reader) []*UserAccessToken { - var t []*UserAccessToken - json.NewDecoder(data).Decode(&t) - return t -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token_search.go deleted file mode 100644 index a692f692..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/user_access_token_search.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type UserAccessTokenSearch struct { - Term string `json:"term"` -} - -// ToJson convert a UserAccessTokenSearch to json string -func (c *UserAccessTokenSearch) ToJson() string { - b, err := json.Marshal(c) - if err != nil { - return "" - } - - return string(b) -} - -// UserAccessTokenSearchJson decodes the input and returns a UserAccessTokenSearch -func UserAccessTokenSearchFromJson(data io.Reader) *UserAccessTokenSearch { - decoder := json.NewDecoder(data) - var cs UserAccessTokenSearch - err := decoder.Decode(&cs) - if err == nil { - return &cs - } - - return nil -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_autocomplete.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_autocomplete.go deleted file mode 100644 index 118e138d..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/user_autocomplete.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type UserAutocompleteInChannel struct { - InChannel []*User `json:"in_channel"` - OutOfChannel []*User `json:"out_of_channel"` -} - -type UserAutocompleteInTeam struct { - InTeam []*User `json:"in_team"` -} - -type UserAutocomplete struct { - Users []*User `json:"users"` - OutOfChannel []*User `json:"out_of_channel,omitempty"` -} - -func (o *UserAutocomplete) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func UserAutocompleteFromJson(data io.Reader) *UserAutocomplete { - decoder := json.NewDecoder(data) - autocomplete := new(UserAutocomplete) - err := decoder.Decode(&autocomplete) - if err != nil { - return nil - } - return autocomplete -} - -func (o *UserAutocompleteInChannel) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func UserAutocompleteInChannelFromJson(data io.Reader) *UserAutocompleteInChannel { - var o *UserAutocompleteInChannel - json.NewDecoder(data).Decode(&o) - return o -} - -func (o *UserAutocompleteInTeam) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func UserAutocompleteInTeamFromJson(data io.Reader) *UserAutocompleteInTeam { - var o *UserAutocompleteInTeam - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_count.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_count.go deleted file mode 100644 index ee474883..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/user_count.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -// Options for counting users -type UserCountOptions struct { - // Should include users that are bots - IncludeBotAccounts bool - // Should include deleted users (of any type) - IncludeDeleted bool - // Exclude regular users - ExcludeRegularUsers bool - // Only include users on a specific team. "" for any team. - TeamId string - // Only include users on a specific channel. "" for any channel. - ChannelId string - // Restrict to search in a list of teams and channels - ViewRestrictions *ViewUsersRestrictions - // Only include users matching any of the given system wide roles. - Roles []string - // Only include users matching any of the given channel roles, must be used with ChannelId. - ChannelRoles []string - // Only include users matching any of the given team roles, must be used with TeamId. - TeamRoles []string -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_get.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_get.go deleted file mode 100644 index 2748d735..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/user_get.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -type UserGetOptions struct { - // Filters the users in the team - InTeamId string - // Filters the users not in the team - NotInTeamId string - // Filters the users in the channel - InChannelId string - // Filters the users not in the channel - NotInChannelId string - // Filters the users in the group - InGroupId string - // Filters the users group constrained - GroupConstrained bool - // Filters the users without a team - WithoutTeam bool - // Filters the inactive users - Inactive bool - // Filters the active users - Active bool - // Filters for the given role - Role string - // Filters for users matching any of the given system wide roles - Roles []string - // Filters for users matching any of the given channel roles, must be used with InChannelId - ChannelRoles []string - // Filters for users matching any of the given team roles, must be used with InTeamId - TeamRoles []string - // Sorting option - Sort string - // Restrict to search in a list of teams and channels - ViewRestrictions *ViewUsersRestrictions - // Page - Page int - // Page size - PerPage int -} - -type UserGetByIdsOptions struct { - // Since filters the users based on their UpdateAt timestamp. - Since int64 -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_search.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_search.go deleted file mode 100644 index 0a721eac..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/user_search.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -const USER_SEARCH_MAX_LIMIT = 1000 -const USER_SEARCH_DEFAULT_LIMIT = 100 - -// UserSearch captures the parameters provided by a client for initiating a user search. -type UserSearch struct { - Term string `json:"term"` - TeamId string `json:"team_id"` - NotInTeamId string `json:"not_in_team_id"` - InChannelId string `json:"in_channel_id"` - NotInChannelId string `json:"not_in_channel_id"` - InGroupId string `json:"in_group_id"` - GroupConstrained bool `json:"group_constrained"` - AllowInactive bool `json:"allow_inactive"` - WithoutTeam bool `json:"without_team"` - Limit int `json:"limit"` - Role string `json:"role"` - Roles []string `json:"roles"` - ChannelRoles []string `json:"channel_roles"` - TeamRoles []string `json:"team_roles"` -} - -// ToJson convert a User to a json string -func (u *UserSearch) ToJson() []byte { - b, _ := json.Marshal(u) - return b -} - -// UserSearchFromJson will decode the input and return a User -func UserSearchFromJson(data io.Reader) *UserSearch { - us := UserSearch{} - json.NewDecoder(data).Decode(&us) - - if us.Limit == 0 { - us.Limit = USER_SEARCH_DEFAULT_LIMIT - } - - return &us -} - -// UserSearchOptions captures internal parameters derived from the user's permissions and a -// UserSearch request. -type UserSearchOptions struct { - // IsAdmin tracks whether or not the search is being conducted by an administrator. - IsAdmin bool - // AllowEmails allows search to examine the emails of users. - AllowEmails bool - // AllowFullNames allows search to examine the full names of users, vs. just usernames and nicknames. - AllowFullNames bool - // AllowInactive configures whether or not to return inactive users in the search results. - AllowInactive bool - // Narrows the search to the group constrained users - GroupConstrained bool - // Limit limits the total number of results returned. - Limit int - // Filters for the given role - Role string - // Filters for users that have any of the given system roles - Roles []string - // Filters for users that have the given channel roles to be used when searching in a channel - ChannelRoles []string - // Filters for users that have the given team roles to be used when searching in a team - TeamRoles []string - // Restrict to search in a list of teams and channels - ViewRestrictions *ViewUsersRestrictions - // List of allowed channels - ListOfAllowedChannels []string -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_serial_gen.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_serial_gen.go deleted file mode 100644 index fb40b577..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/user_serial_gen.go +++ /dev/null @@ -1,826 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -// Code generated by github.com/tinylib/msgp DO NOT EDIT. - -import ( - "github.com/tinylib/msgp/msgp" -) - -// DecodeMsg implements msgp.Decodable -func (z *User) DecodeMsg(dc *msgp.Reader) (err error) { - var zb0001 uint32 - zb0001, err = dc.ReadArrayHeader() - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0001 != 32 { - err = msgp.ArrayError{Wanted: 32, Got: zb0001} - return - } - z.Id, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - z.CreateAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - z.UpdateAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "UpdateAt") - return - } - z.DeleteAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - z.Username, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Username") - return - } - z.Password, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Password") - return - } - if dc.IsNil() { - err = dc.ReadNil() - if err != nil { - err = msgp.WrapError(err, "AuthData") - return - } - z.AuthData = nil - } else { - if z.AuthData == nil { - z.AuthData = new(string) - } - *z.AuthData, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "AuthData") - return - } - } - z.AuthService, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "AuthService") - return - } - z.Email, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Email") - return - } - z.EmailVerified, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "EmailVerified") - return - } - z.Nickname, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Nickname") - return - } - z.FirstName, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "FirstName") - return - } - z.LastName, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "LastName") - return - } - z.Position, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Position") - return - } - z.Roles, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - z.AllowMarketing, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "AllowMarketing") - return - } - err = z.Props.DecodeMsg(dc) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - err = z.NotifyProps.DecodeMsg(dc) - if err != nil { - err = msgp.WrapError(err, "NotifyProps") - return - } - z.LastPasswordUpdate, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "LastPasswordUpdate") - return - } - z.LastPictureUpdate, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "LastPictureUpdate") - return - } - z.FailedAttempts, err = dc.ReadInt() - if err != nil { - err = msgp.WrapError(err, "FailedAttempts") - return - } - z.Locale, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "Locale") - return - } - err = z.Timezone.DecodeMsg(dc) - if err != nil { - err = msgp.WrapError(err, "Timezone") - return - } - z.MfaActive, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "MfaActive") - return - } - z.MfaSecret, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "MfaSecret") - return - } - if dc.IsNil() { - err = dc.ReadNil() - if err != nil { - err = msgp.WrapError(err, "RemoteId") - return - } - z.RemoteId = nil - } else { - if z.RemoteId == nil { - z.RemoteId = new(string) - } - *z.RemoteId, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "RemoteId") - return - } - } - z.LastActivityAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - z.IsBot, err = dc.ReadBool() - if err != nil { - err = msgp.WrapError(err, "IsBot") - return - } - z.BotDescription, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "BotDescription") - return - } - z.BotLastIconUpdate, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "BotLastIconUpdate") - return - } - z.TermsOfServiceId, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceId") - return - } - z.TermsOfServiceCreateAt, err = dc.ReadInt64() - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceCreateAt") - return - } - return -} - -// EncodeMsg implements msgp.Encodable -func (z *User) EncodeMsg(en *msgp.Writer) (err error) { - // array header, size 32 - err = en.Append(0xdc, 0x0, 0x20) - if err != nil { - return - } - err = en.WriteString(z.Id) - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - err = en.WriteInt64(z.CreateAt) - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - err = en.WriteInt64(z.UpdateAt) - if err != nil { - err = msgp.WrapError(err, "UpdateAt") - return - } - err = en.WriteInt64(z.DeleteAt) - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - err = en.WriteString(z.Username) - if err != nil { - err = msgp.WrapError(err, "Username") - return - } - err = en.WriteString(z.Password) - if err != nil { - err = msgp.WrapError(err, "Password") - return - } - if z.AuthData == nil { - err = en.WriteNil() - if err != nil { - return - } - } else { - err = en.WriteString(*z.AuthData) - if err != nil { - err = msgp.WrapError(err, "AuthData") - return - } - } - err = en.WriteString(z.AuthService) - if err != nil { - err = msgp.WrapError(err, "AuthService") - return - } - err = en.WriteString(z.Email) - if err != nil { - err = msgp.WrapError(err, "Email") - return - } - err = en.WriteBool(z.EmailVerified) - if err != nil { - err = msgp.WrapError(err, "EmailVerified") - return - } - err = en.WriteString(z.Nickname) - if err != nil { - err = msgp.WrapError(err, "Nickname") - return - } - err = en.WriteString(z.FirstName) - if err != nil { - err = msgp.WrapError(err, "FirstName") - return - } - err = en.WriteString(z.LastName) - if err != nil { - err = msgp.WrapError(err, "LastName") - return - } - err = en.WriteString(z.Position) - if err != nil { - err = msgp.WrapError(err, "Position") - return - } - err = en.WriteString(z.Roles) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - err = en.WriteBool(z.AllowMarketing) - if err != nil { - err = msgp.WrapError(err, "AllowMarketing") - return - } - err = z.Props.EncodeMsg(en) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - err = z.NotifyProps.EncodeMsg(en) - if err != nil { - err = msgp.WrapError(err, "NotifyProps") - return - } - err = en.WriteInt64(z.LastPasswordUpdate) - if err != nil { - err = msgp.WrapError(err, "LastPasswordUpdate") - return - } - err = en.WriteInt64(z.LastPictureUpdate) - if err != nil { - err = msgp.WrapError(err, "LastPictureUpdate") - return - } - err = en.WriteInt(z.FailedAttempts) - if err != nil { - err = msgp.WrapError(err, "FailedAttempts") - return - } - err = en.WriteString(z.Locale) - if err != nil { - err = msgp.WrapError(err, "Locale") - return - } - err = z.Timezone.EncodeMsg(en) - if err != nil { - err = msgp.WrapError(err, "Timezone") - return - } - err = en.WriteBool(z.MfaActive) - if err != nil { - err = msgp.WrapError(err, "MfaActive") - return - } - err = en.WriteString(z.MfaSecret) - if err != nil { - err = msgp.WrapError(err, "MfaSecret") - return - } - if z.RemoteId == nil { - err = en.WriteNil() - if err != nil { - return - } - } else { - err = en.WriteString(*z.RemoteId) - if err != nil { - err = msgp.WrapError(err, "RemoteId") - return - } - } - err = en.WriteInt64(z.LastActivityAt) - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - err = en.WriteBool(z.IsBot) - if err != nil { - err = msgp.WrapError(err, "IsBot") - return - } - err = en.WriteString(z.BotDescription) - if err != nil { - err = msgp.WrapError(err, "BotDescription") - return - } - err = en.WriteInt64(z.BotLastIconUpdate) - if err != nil { - err = msgp.WrapError(err, "BotLastIconUpdate") - return - } - err = en.WriteString(z.TermsOfServiceId) - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceId") - return - } - err = en.WriteInt64(z.TermsOfServiceCreateAt) - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceCreateAt") - return - } - return -} - -// MarshalMsg implements msgp.Marshaler -func (z *User) MarshalMsg(b []byte) (o []byte, err error) { - o = msgp.Require(b, z.Msgsize()) - // array header, size 32 - o = append(o, 0xdc, 0x0, 0x20) - o = msgp.AppendString(o, z.Id) - o = msgp.AppendInt64(o, z.CreateAt) - o = msgp.AppendInt64(o, z.UpdateAt) - o = msgp.AppendInt64(o, z.DeleteAt) - o = msgp.AppendString(o, z.Username) - o = msgp.AppendString(o, z.Password) - if z.AuthData == nil { - o = msgp.AppendNil(o) - } else { - o = msgp.AppendString(o, *z.AuthData) - } - o = msgp.AppendString(o, z.AuthService) - o = msgp.AppendString(o, z.Email) - o = msgp.AppendBool(o, z.EmailVerified) - o = msgp.AppendString(o, z.Nickname) - o = msgp.AppendString(o, z.FirstName) - o = msgp.AppendString(o, z.LastName) - o = msgp.AppendString(o, z.Position) - o = msgp.AppendString(o, z.Roles) - o = msgp.AppendBool(o, z.AllowMarketing) - o, err = z.Props.MarshalMsg(o) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - o, err = z.NotifyProps.MarshalMsg(o) - if err != nil { - err = msgp.WrapError(err, "NotifyProps") - return - } - o = msgp.AppendInt64(o, z.LastPasswordUpdate) - o = msgp.AppendInt64(o, z.LastPictureUpdate) - o = msgp.AppendInt(o, z.FailedAttempts) - o = msgp.AppendString(o, z.Locale) - o, err = z.Timezone.MarshalMsg(o) - if err != nil { - err = msgp.WrapError(err, "Timezone") - return - } - o = msgp.AppendBool(o, z.MfaActive) - o = msgp.AppendString(o, z.MfaSecret) - if z.RemoteId == nil { - o = msgp.AppendNil(o) - } else { - o = msgp.AppendString(o, *z.RemoteId) - } - o = msgp.AppendInt64(o, z.LastActivityAt) - o = msgp.AppendBool(o, z.IsBot) - o = msgp.AppendString(o, z.BotDescription) - o = msgp.AppendInt64(o, z.BotLastIconUpdate) - o = msgp.AppendString(o, z.TermsOfServiceId) - o = msgp.AppendInt64(o, z.TermsOfServiceCreateAt) - return -} - -// UnmarshalMsg implements msgp.Unmarshaler -func (z *User) UnmarshalMsg(bts []byte) (o []byte, err error) { - var zb0001 uint32 - zb0001, bts, err = msgp.ReadArrayHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0001 != 32 { - err = msgp.ArrayError{Wanted: 32, Got: zb0001} - return - } - z.Id, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Id") - return - } - z.CreateAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "CreateAt") - return - } - z.UpdateAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "UpdateAt") - return - } - z.DeleteAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "DeleteAt") - return - } - z.Username, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Username") - return - } - z.Password, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Password") - return - } - if msgp.IsNil(bts) { - bts, err = msgp.ReadNilBytes(bts) - if err != nil { - return - } - z.AuthData = nil - } else { - if z.AuthData == nil { - z.AuthData = new(string) - } - *z.AuthData, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "AuthData") - return - } - } - z.AuthService, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "AuthService") - return - } - z.Email, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Email") - return - } - z.EmailVerified, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "EmailVerified") - return - } - z.Nickname, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Nickname") - return - } - z.FirstName, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "FirstName") - return - } - z.LastName, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "LastName") - return - } - z.Position, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Position") - return - } - z.Roles, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Roles") - return - } - z.AllowMarketing, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "AllowMarketing") - return - } - bts, err = z.Props.UnmarshalMsg(bts) - if err != nil { - err = msgp.WrapError(err, "Props") - return - } - bts, err = z.NotifyProps.UnmarshalMsg(bts) - if err != nil { - err = msgp.WrapError(err, "NotifyProps") - return - } - z.LastPasswordUpdate, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "LastPasswordUpdate") - return - } - z.LastPictureUpdate, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "LastPictureUpdate") - return - } - z.FailedAttempts, bts, err = msgp.ReadIntBytes(bts) - if err != nil { - err = msgp.WrapError(err, "FailedAttempts") - return - } - z.Locale, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "Locale") - return - } - bts, err = z.Timezone.UnmarshalMsg(bts) - if err != nil { - err = msgp.WrapError(err, "Timezone") - return - } - z.MfaActive, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "MfaActive") - return - } - z.MfaSecret, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "MfaSecret") - return - } - if msgp.IsNil(bts) { - bts, err = msgp.ReadNilBytes(bts) - if err != nil { - return - } - z.RemoteId = nil - } else { - if z.RemoteId == nil { - z.RemoteId = new(string) - } - *z.RemoteId, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "RemoteId") - return - } - } - z.LastActivityAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "LastActivityAt") - return - } - z.IsBot, bts, err = msgp.ReadBoolBytes(bts) - if err != nil { - err = msgp.WrapError(err, "IsBot") - return - } - z.BotDescription, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "BotDescription") - return - } - z.BotLastIconUpdate, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "BotLastIconUpdate") - return - } - z.TermsOfServiceId, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceId") - return - } - z.TermsOfServiceCreateAt, bts, err = msgp.ReadInt64Bytes(bts) - if err != nil { - err = msgp.WrapError(err, "TermsOfServiceCreateAt") - return - } - o = bts - return -} - -// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message -func (z *User) Msgsize() (s int) { - s = 3 + msgp.StringPrefixSize + len(z.Id) + msgp.Int64Size + msgp.Int64Size + msgp.Int64Size + msgp.StringPrefixSize + len(z.Username) + msgp.StringPrefixSize + len(z.Password) - if z.AuthData == nil { - s += msgp.NilSize - } else { - s += msgp.StringPrefixSize + len(*z.AuthData) - } - s += msgp.StringPrefixSize + len(z.AuthService) + msgp.StringPrefixSize + len(z.Email) + msgp.BoolSize + msgp.StringPrefixSize + len(z.Nickname) + msgp.StringPrefixSize + len(z.FirstName) + msgp.StringPrefixSize + len(z.LastName) + msgp.StringPrefixSize + len(z.Position) + msgp.StringPrefixSize + len(z.Roles) + msgp.BoolSize + z.Props.Msgsize() + z.NotifyProps.Msgsize() + msgp.Int64Size + msgp.Int64Size + msgp.IntSize + msgp.StringPrefixSize + len(z.Locale) + z.Timezone.Msgsize() + msgp.BoolSize + msgp.StringPrefixSize + len(z.MfaSecret) - if z.RemoteId == nil { - s += msgp.NilSize - } else { - s += msgp.StringPrefixSize + len(*z.RemoteId) - } - s += msgp.Int64Size + msgp.BoolSize + msgp.StringPrefixSize + len(z.BotDescription) + msgp.Int64Size + msgp.StringPrefixSize + len(z.TermsOfServiceId) + msgp.Int64Size - return -} - -// DecodeMsg implements msgp.Decodable -func (z *UserMap) DecodeMsg(dc *msgp.Reader) (err error) { - var zb0003 uint32 - zb0003, err = dc.ReadMapHeader() - if err != nil { - err = msgp.WrapError(err) - return - } - if (*z) == nil { - (*z) = make(UserMap, zb0003) - } else if len((*z)) > 0 { - for key := range *z { - delete((*z), key) - } - } - for zb0003 > 0 { - zb0003-- - var zb0001 string - var zb0002 *User - zb0001, err = dc.ReadString() - if err != nil { - err = msgp.WrapError(err) - return - } - if dc.IsNil() { - err = dc.ReadNil() - if err != nil { - err = msgp.WrapError(err, zb0001) - return - } - zb0002 = nil - } else { - if zb0002 == nil { - zb0002 = new(User) - } - err = zb0002.DecodeMsg(dc) - if err != nil { - err = msgp.WrapError(err, zb0001) - return - } - } - (*z)[zb0001] = zb0002 - } - return -} - -// EncodeMsg implements msgp.Encodable -func (z UserMap) EncodeMsg(en *msgp.Writer) (err error) { - err = en.WriteMapHeader(uint32(len(z))) - if err != nil { - err = msgp.WrapError(err) - return - } - for zb0004, zb0005 := range z { - err = en.WriteString(zb0004) - if err != nil { - err = msgp.WrapError(err) - return - } - if zb0005 == nil { - err = en.WriteNil() - if err != nil { - return - } - } else { - err = zb0005.EncodeMsg(en) - if err != nil { - err = msgp.WrapError(err, zb0004) - return - } - } - } - return -} - -// MarshalMsg implements msgp.Marshaler -func (z UserMap) MarshalMsg(b []byte) (o []byte, err error) { - o = msgp.Require(b, z.Msgsize()) - o = msgp.AppendMapHeader(o, uint32(len(z))) - for zb0004, zb0005 := range z { - o = msgp.AppendString(o, zb0004) - if zb0005 == nil { - o = msgp.AppendNil(o) - } else { - o, err = zb0005.MarshalMsg(o) - if err != nil { - err = msgp.WrapError(err, zb0004) - return - } - } - } - return -} - -// UnmarshalMsg implements msgp.Unmarshaler -func (z *UserMap) UnmarshalMsg(bts []byte) (o []byte, err error) { - var zb0003 uint32 - zb0003, bts, err = msgp.ReadMapHeaderBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - if (*z) == nil { - (*z) = make(UserMap, zb0003) - } else if len((*z)) > 0 { - for key := range *z { - delete((*z), key) - } - } - for zb0003 > 0 { - var zb0001 string - var zb0002 *User - zb0003-- - zb0001, bts, err = msgp.ReadStringBytes(bts) - if err != nil { - err = msgp.WrapError(err) - return - } - if msgp.IsNil(bts) { - bts, err = msgp.ReadNilBytes(bts) - if err != nil { - return - } - zb0002 = nil - } else { - if zb0002 == nil { - zb0002 = new(User) - } - bts, err = zb0002.UnmarshalMsg(bts) - if err != nil { - err = msgp.WrapError(err, zb0001) - return - } - } - (*z)[zb0001] = zb0002 - } - o = bts - return -} - -// Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message -func (z UserMap) Msgsize() (s int) { - s = msgp.MapHeaderSize - if z != nil { - for zb0004, zb0005 := range z { - _ = zb0005 - s += msgp.StringPrefixSize + len(zb0004) - if zb0005 == nil { - s += msgp.NilSize - } else { - s += zb0005.Msgsize() - } - } - } - return -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/user_terms_of_service.go b/vendor/github.com/mattermost/mattermost-server/v5/model/user_terms_of_service.go deleted file mode 100644 index 9a0f4f18..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/user_terms_of_service.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "fmt" - "io" - "net/http" -) - -type UserTermsOfService struct { - UserId string `json:"user_id"` - TermsOfServiceId string `json:"terms_of_service_id"` - CreateAt int64 `json:"create_at"` -} - -func (ut *UserTermsOfService) IsValid() *AppError { - if !IsValidId(ut.UserId) { - return InvalidUserTermsOfServiceError("user_id", ut.UserId) - } - - if !IsValidId(ut.TermsOfServiceId) { - return InvalidUserTermsOfServiceError("terms_of_service_id", ut.UserId) - } - - if ut.CreateAt == 0 { - return InvalidUserTermsOfServiceError("create_at", ut.UserId) - } - - return nil -} - -func (ut *UserTermsOfService) ToJson() string { - b, _ := json.Marshal(ut) - return string(b) -} - -func (ut *UserTermsOfService) PreSave() { - if ut.UserId == "" { - ut.UserId = NewId() - } - - ut.CreateAt = GetMillis() -} - -func UserTermsOfServiceFromJson(data io.Reader) *UserTermsOfService { - var userTermsOfService *UserTermsOfService - json.NewDecoder(data).Decode(&userTermsOfService) - return userTermsOfService -} - -func InvalidUserTermsOfServiceError(fieldName string, userTermsOfServiceId string) *AppError { - id := fmt.Sprintf("model.user_terms_of_service.is_valid.%s.app_error", fieldName) - details := "" - if userTermsOfServiceId != "" { - details = "user_terms_of_service_user_id=" + userTermsOfServiceId - } - return NewAppError("UserTermsOfService.IsValid", id, nil, details, http.StatusBadRequest) -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/users_stats.go b/vendor/github.com/mattermost/mattermost-server/v5/model/users_stats.go deleted file mode 100644 index 3e18296e..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/users_stats.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" -) - -type UsersStats struct { - TotalUsersCount int64 `json:"total_users_count"` -} - -func (o *UsersStats) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func UsersStatsFromJson(data io.Reader) *UsersStats { - var o *UsersStats - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/utils.go b/vendor/github.com/mattermost/mattermost-server/v5/model/utils.go deleted file mode 100644 index 0c5a272c..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/utils.go +++ /dev/null @@ -1,726 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "bytes" - "crypto/rand" - "encoding/base32" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "net/mail" - "net/url" - "regexp" - "strconv" - "strings" - "sync" - "time" - "unicode" - - "github.com/mattermost/mattermost-server/v5/shared/i18n" - "github.com/pborman/uuid" -) - -const ( - LOWERCASE_LETTERS = "abcdefghijklmnopqrstuvwxyz" - UPPERCASE_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - NUMBERS = "0123456789" - SYMBOLS = " !\"\\#$%&'()*+,-./:;<=>?@[]^_`|~" - MB = 1 << 20 -) - -type StringInterface map[string]interface{} -type StringArray []string - -func (sa StringArray) Remove(input string) StringArray { - for index := range sa { - if sa[index] == input { - ret := make(StringArray, 0, len(sa)-1) - ret = append(ret, sa[:index]...) - return append(ret, sa[index+1:]...) - } - } - return sa -} - -func (sa StringArray) Contains(input string) bool { - for index := range sa { - if sa[index] == input { - return true - } - } - - return false -} -func (sa StringArray) Equals(input StringArray) bool { - - if len(sa) != len(input) { - return false - } - - for index := range sa { - - if sa[index] != input[index] { - return false - } - } - - return true -} - -var translateFunc i18n.TranslateFunc -var translateFuncOnce sync.Once - -func AppErrorInit(t i18n.TranslateFunc) { - translateFuncOnce.Do(func() { - translateFunc = t - }) -} - -type AppError struct { - Id string `json:"id"` - Message string `json:"message"` // Message to be display to the end user without debugging information - DetailedError string `json:"detailed_error"` // Internal error string to help the developer - RequestId string `json:"request_id,omitempty"` // The RequestId that's also set in the header - StatusCode int `json:"status_code,omitempty"` // The http status code - Where string `json:"-"` // The function where it happened in the form of Struct.Func - IsOAuth bool `json:"is_oauth,omitempty"` // Whether the error is OAuth specific - params map[string]interface{} -} - -func (er *AppError) Error() string { - return er.Where + ": " + er.Message + ", " + er.DetailedError -} - -func (er *AppError) Translate(T i18n.TranslateFunc) { - if T == nil { - er.Message = er.Id - return - } - - if er.params == nil { - er.Message = T(er.Id) - } else { - er.Message = T(er.Id, er.params) - } -} - -func (er *AppError) SystemMessage(T i18n.TranslateFunc) string { - if er.params == nil { - return T(er.Id) - } - return T(er.Id, er.params) -} - -func (er *AppError) ToJson() string { - b, _ := json.Marshal(er) - return string(b) -} - -// AppErrorFromJson will decode the input and return an AppError -func AppErrorFromJson(data io.Reader) *AppError { - str := "" - bytes, rerr := ioutil.ReadAll(data) - if rerr != nil { - str = rerr.Error() - } else { - str = string(bytes) - } - - decoder := json.NewDecoder(strings.NewReader(str)) - var er AppError - err := decoder.Decode(&er) - if err != nil { - return NewAppError("AppErrorFromJson", "model.utils.decode_json.app_error", nil, "body: "+str, http.StatusInternalServerError) - } - return &er -} - -func NewAppError(where string, id string, params map[string]interface{}, details string, status int) *AppError { - ap := &AppError{} - ap.Id = id - ap.params = params - ap.Message = id - ap.Where = where - ap.DetailedError = details - ap.StatusCode = status - ap.IsOAuth = false - ap.Translate(translateFunc) - return ap -} - -var encoding = base32.NewEncoding("ybndrfg8ejkmcpqxot1uwisza345h769") - -// NewId is a globally unique identifier. It is a [A-Z0-9] string 26 -// characters long. It is a UUID version 4 Guid that is zbased32 encoded -// with the padding stripped off. -func NewId() string { - var b bytes.Buffer - encoder := base32.NewEncoder(encoding, &b) - encoder.Write(uuid.NewRandom()) - encoder.Close() - b.Truncate(26) // removes the '==' padding - return b.String() -} - -// NewRandomTeamName is a NewId that will be a valid team name. -func NewRandomTeamName() string { - teamName := NewId() - for IsReservedTeamName(teamName) { - teamName = NewId() - } - return teamName -} - -// NewRandomString returns a random string of the given length. -// The resulting entropy will be (5 * length) bits. -func NewRandomString(length int) string { - data := make([]byte, 1+(length*5/8)) - rand.Read(data) - return encoding.EncodeToString(data)[:length] -} - -// GetMillis is a convenience method to get milliseconds since epoch. -func GetMillis() int64 { - return time.Now().UnixNano() / int64(time.Millisecond) -} - -// GetMillisForTime is a convenience method to get milliseconds since epoch for provided Time. -func GetMillisForTime(thisTime time.Time) int64 { - return thisTime.UnixNano() / int64(time.Millisecond) -} - -// GetTimeForMillis is a convenience method to get time.Time for milliseconds since epoch. -func GetTimeForMillis(millis int64) time.Time { - return time.Unix(0, millis*int64(time.Millisecond)) -} - -// PadDateStringZeros is a convenience method to pad 2 digit date parts with zeros to meet ISO 8601 format -func PadDateStringZeros(dateString string) string { - parts := strings.Split(dateString, "-") - for index, part := range parts { - if len(part) == 1 { - parts[index] = "0" + part - } - } - dateString = strings.Join(parts[:], "-") - return dateString -} - -// GetStartOfDayMillis is a convenience method to get milliseconds since epoch for provided date's start of day -func GetStartOfDayMillis(thisTime time.Time, timeZoneOffset int) int64 { - localSearchTimeZone := time.FixedZone("Local Search Time Zone", timeZoneOffset) - resultTime := time.Date(thisTime.Year(), thisTime.Month(), thisTime.Day(), 0, 0, 0, 0, localSearchTimeZone) - return GetMillisForTime(resultTime) -} - -// GetEndOfDayMillis is a convenience method to get milliseconds since epoch for provided date's end of day -func GetEndOfDayMillis(thisTime time.Time, timeZoneOffset int) int64 { - localSearchTimeZone := time.FixedZone("Local Search Time Zone", timeZoneOffset) - resultTime := time.Date(thisTime.Year(), thisTime.Month(), thisTime.Day(), 23, 59, 59, 999999999, localSearchTimeZone) - return GetMillisForTime(resultTime) -} - -func CopyStringMap(originalMap map[string]string) map[string]string { - copyMap := make(map[string]string) - for k, v := range originalMap { - copyMap[k] = v - } - return copyMap -} - -// MapToJson converts a map to a json string -func MapToJson(objmap map[string]string) string { - b, _ := json.Marshal(objmap) - return string(b) -} - -// MapBoolToJson converts a map to a json string -func MapBoolToJson(objmap map[string]bool) string { - b, _ := json.Marshal(objmap) - return string(b) -} - -// MapFromJson will decode the key/value pair map -func MapFromJson(data io.Reader) map[string]string { - decoder := json.NewDecoder(data) - - var objmap map[string]string - if err := decoder.Decode(&objmap); err != nil { - return make(map[string]string) - } - return objmap -} - -// MapFromJson will decode the key/value pair map -func MapBoolFromJson(data io.Reader) map[string]bool { - decoder := json.NewDecoder(data) - - var objmap map[string]bool - if err := decoder.Decode(&objmap); err != nil { - return make(map[string]bool) - } - return objmap -} - -func ArrayToJson(objmap []string) string { - b, _ := json.Marshal(objmap) - return string(b) -} - -func ArrayFromJson(data io.Reader) []string { - decoder := json.NewDecoder(data) - - var objmap []string - if err := decoder.Decode(&objmap); err != nil { - return make([]string, 0) - } - return objmap -} - -func ArrayFromInterface(data interface{}) []string { - stringArray := []string{} - - dataArray, ok := data.([]interface{}) - if !ok { - return stringArray - } - - for _, v := range dataArray { - if str, ok := v.(string); ok { - stringArray = append(stringArray, str) - } - } - - return stringArray -} - -func StringInterfaceToJson(objmap map[string]interface{}) string { - b, _ := json.Marshal(objmap) - return string(b) -} - -func StringInterfaceFromJson(data io.Reader) map[string]interface{} { - decoder := json.NewDecoder(data) - - var objmap map[string]interface{} - if err := decoder.Decode(&objmap); err != nil { - return make(map[string]interface{}) - } - return objmap -} - -func StringToJson(s string) string { - b, _ := json.Marshal(s) - return string(b) -} - -func StringFromJson(data io.Reader) string { - decoder := json.NewDecoder(data) - - var s string - if err := decoder.Decode(&s); err != nil { - return "" - } - return s -} - -// ToJson serializes an arbitrary data type to JSON, discarding the error. -func ToJson(v interface{}) []byte { - b, _ := json.Marshal(v) - return b -} - -func GetServerIpAddress(iface string) string { - var addrs []net.Addr - if iface == "" { - var err error - addrs, err = net.InterfaceAddrs() - if err != nil { - return "" - } - } else { - interfaces, err := net.Interfaces() - if err != nil { - return "" - } - for _, i := range interfaces { - if i.Name == iface { - addrs, err = i.Addrs() - if err != nil { - return "" - } - break - } - } - } - - for _, addr := range addrs { - - if ip, ok := addr.(*net.IPNet); ok && !ip.IP.IsLoopback() && !ip.IP.IsLinkLocalUnicast() && !ip.IP.IsLinkLocalMulticast() { - if ip.IP.To4() != nil { - return ip.IP.String() - } - } - } - - return "" -} - -func IsLower(s string) bool { - return strings.ToLower(s) == s -} - -func IsValidEmail(email string) bool { - if !IsLower(email) { - return false - } - - if addr, err := mail.ParseAddress(email); err != nil { - return false - } else if addr.Name != "" { - // mail.ParseAddress accepts input of the form "Billy Bob <billy@example.com>" which we don't allow - return false - } - - return true -} - -var reservedName = []string{ - "admin", - "api", - "channel", - "claim", - "error", - "files", - "help", - "landing", - "login", - "mfa", - "oauth", - "plug", - "plugins", - "post", - "signup", -} - -func IsValidChannelIdentifier(s string) bool { - - if !IsValidAlphaNumHyphenUnderscore(s, true) { - return false - } - - if len(s) < CHANNEL_NAME_MIN_LENGTH { - return false - } - - return true -} - -func IsValidAlphaNum(s string) bool { - validAlphaNum := regexp.MustCompile(`^[a-z0-9]+([a-z\-0-9]+|(__)?)[a-z0-9]+$`) - - return validAlphaNum.MatchString(s) -} - -func IsValidAlphaNumHyphenUnderscore(s string, withFormat bool) bool { - if withFormat { - validAlphaNumHyphenUnderscore := regexp.MustCompile(`^[a-z0-9]+([a-z\-\_0-9]+|(__)?)[a-z0-9]+$`) - return validAlphaNumHyphenUnderscore.MatchString(s) - } - - validSimpleAlphaNumHyphenUnderscore := regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`) - return validSimpleAlphaNumHyphenUnderscore.MatchString(s) -} - -func IsValidAlphaNumHyphenUnderscorePlus(s string) bool { - - validSimpleAlphaNumHyphenUnderscorePlus := regexp.MustCompile(`^[a-zA-Z0-9+_-]+$`) - return validSimpleAlphaNumHyphenUnderscorePlus.MatchString(s) -} - -func Etag(parts ...interface{}) string { - - etag := CurrentVersion - - for _, part := range parts { - etag += fmt.Sprintf(".%v", part) - } - - return etag -} - -var validHashtag = regexp.MustCompile(`^(#\pL[\pL\d\-_.]*[\pL\d])$`) -var puncStart = regexp.MustCompile(`^[^\pL\d\s#]+`) -var hashtagStart = regexp.MustCompile(`^#{2,}`) -var puncEnd = regexp.MustCompile(`[^\pL\d\s]+$`) - -func ParseHashtags(text string) (string, string) { - words := strings.Fields(text) - - hashtagString := "" - plainString := "" - for _, word := range words { - // trim off surrounding punctuation - word = puncStart.ReplaceAllString(word, "") - word = puncEnd.ReplaceAllString(word, "") - - // and remove extra pound #s - word = hashtagStart.ReplaceAllString(word, "#") - - if validHashtag.MatchString(word) { - hashtagString += " " + word - } else { - plainString += " " + word - } - } - - if len(hashtagString) > 1000 { - hashtagString = hashtagString[:999] - lastSpace := strings.LastIndex(hashtagString, " ") - if lastSpace > -1 { - hashtagString = hashtagString[:lastSpace] - } else { - hashtagString = "" - } - } - - return strings.TrimSpace(hashtagString), strings.TrimSpace(plainString) -} - -func ClearMentionTags(post string) string { - post = strings.Replace(post, "<mention>", "", -1) - post = strings.Replace(post, "</mention>", "", -1) - return post -} - -func IsValidHttpUrl(rawUrl string) bool { - if strings.Index(rawUrl, "http://") != 0 && strings.Index(rawUrl, "https://") != 0 { - return false - } - - if u, err := url.ParseRequestURI(rawUrl); err != nil || u.Scheme == "" || u.Host == "" { - return false - } - - return true -} - -func IsValidTurnOrStunServer(rawUri string) bool { - if strings.Index(rawUri, "turn:") != 0 && strings.Index(rawUri, "stun:") != 0 { - return false - } - - if _, err := url.ParseRequestURI(rawUri); err != nil { - return false - } - - return true -} - -func IsSafeLink(link *string) bool { - if link != nil { - if IsValidHttpUrl(*link) { - return true - } else if strings.HasPrefix(*link, "/") { - return true - } else { - return false - } - } - - return true -} - -func IsValidWebsocketUrl(rawUrl string) bool { - if strings.Index(rawUrl, "ws://") != 0 && strings.Index(rawUrl, "wss://") != 0 { - return false - } - - if _, err := url.ParseRequestURI(rawUrl); err != nil { - return false - } - - return true -} - -func IsValidTrueOrFalseString(value string) bool { - return value == "true" || value == "false" -} - -func IsValidNumberString(value string) bool { - if _, err := strconv.Atoi(value); err != nil { - return false - } - - return true -} - -func IsValidId(value string) bool { - if len(value) != 26 { - return false - } - - for _, r := range value { - if !unicode.IsLetter(r) && !unicode.IsNumber(r) { - return false - } - } - - return true -} - -// Copied from https://golang.org/src/net/dnsclient.go#L119 -func IsDomainName(s string) bool { - // See RFC 1035, RFC 3696. - // Presentation format has dots before every label except the first, and the - // terminal empty label is optional here because we assume fully-qualified - // (absolute) input. We must therefore reserve space for the first and last - // labels' length octets in wire format, where they are necessary and the - // maximum total length is 255. - // So our _effective_ maximum is 253, but 254 is not rejected if the last - // character is a dot. - l := len(s) - if l == 0 || l > 254 || l == 254 && s[l-1] != '.' { - return false - } - - last := byte('.') - ok := false // Ok once we've seen a letter. - partlen := 0 - for i := 0; i < len(s); i++ { - c := s[i] - switch { - default: - return false - case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_': - ok = true - partlen++ - case '0' <= c && c <= '9': - // fine - partlen++ - case c == '-': - // Byte before dash cannot be dot. - if last == '.' { - return false - } - partlen++ - case c == '.': - // Byte before dot cannot be dot, dash. - if last == '.' || last == '-' { - return false - } - if partlen > 63 || partlen == 0 { - return false - } - partlen = 0 - } - last = c - } - if last == '-' || partlen > 63 { - return false - } - - return ok -} - -func RemoveDuplicateStrings(in []string) []string { - out := []string{} - seen := make(map[string]bool, len(in)) - - for _, item := range in { - if !seen[item] { - out = append(out, item) - - seen[item] = true - } - } - - return out -} - -func GetPreferredTimezone(timezone StringMap) string { - if timezone["useAutomaticTimezone"] == "true" { - return timezone["automaticTimezone"] - } - - return timezone["manualTimezone"] -} - -// IsSamlFile checks if filename is a SAML file. -func IsSamlFile(saml *SamlSettings, filename string) bool { - return filename == *saml.PublicCertificateFile || filename == *saml.PrivateKeyFile || filename == *saml.IdpCertificateFile -} - -func AsStringBoolMap(list []string) map[string]bool { - listMap := map[string]bool{} - for _, p := range list { - listMap[p] = true - } - return listMap -} - -// SanitizeUnicode will remove undesirable Unicode characters from a string. -func SanitizeUnicode(s string) string { - return strings.Map(filterBlocklist, s) -} - -// filterBlocklist returns `r` if it is not in the blocklist, otherwise drop (-1). -// Blocklist is taken from https://www.w3.org/TR/unicode-xml/#Charlist -func filterBlocklist(r rune) rune { - const drop = -1 - switch r { - case '\u0340', '\u0341': // clones of grave and acute; deprecated in Unicode - return drop - case '\u17A3', '\u17D3': // obsolete characters for Khmer; deprecated in Unicode - return drop - case '\u2028', '\u2029': // line and paragraph separator - return drop - case '\u202A', '\u202B', '\u202C', '\u202D', '\u202E': // BIDI embedding controls - return drop - case '\u206A', '\u206B': // activate/inhibit symmetric swapping; deprecated in Unicode - return drop - case '\u206C', '\u206D': // activate/inhibit Arabic form shaping; deprecated in Unicode - return drop - case '\u206E', '\u206F': // activate/inhibit national digit shapes; deprecated in Unicode - return drop - case '\uFFF9', '\uFFFA', '\uFFFB': // interlinear annotation characters - return drop - case '\uFEFF': // byte order mark - return drop - case '\uFFFC': // object replacement character - return drop - } - - // Scoping for musical notation - if r >= 0x0001D173 && r <= 0x0001D17A { - return drop - } - - // Language tag code points - if r >= 0x000E0000 && r <= 0x000E007F { - return drop - } - - return r -} - -// UniqueStrings returns a unique subset of the string slice provided. -func UniqueStrings(input []string) []string { - u := make([]string, 0, len(input)) - m := make(map[string]bool) - - for _, val := range input { - if _, ok := m[val]; !ok { - m[val] = true - u = append(u, val) - } - } - - return u -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/version.go b/vendor/github.com/mattermost/mattermost-server/v5/model/version.go deleted file mode 100644 index 28904965..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/version.go +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "fmt" - "strconv" - "strings" -) - -// This is a list of all the current versions including any patches. -// It should be maintained in chronological order with most current -// release at the front of the list. -var versions = []string{ - "5.39.3", - "5.39.2", - "5.39.1", - "5.39.0", - "5.38.2", - "5.38.1", - "5.38.0", - "5.37.0", - "5.36.0", - "5.35.0", - "5.34.0", - "5.33.0", - "5.32.0", - "5.31.0", - "5.30.0", - "5.29.0", - "5.28.0", - "5.27.0", - "5.26.0", - "5.25.0", - "5.24.0", - "5.23.0", - "5.22.0", - "5.21.0", - "5.20.0", - "5.19.0", - "5.18.0", - "5.17.0", - "5.16.0", - "5.15.0", - "5.14.0", - "5.13.0", - "5.12.0", - "5.11.0", - "5.10.0", - "5.9.0", - "5.8.0", - "5.7.0", - "5.6.0", - "5.5.0", - "5.4.0", - "5.3.0", - "5.2.0", - "5.1.0", - "5.0.0", - "4.10.0", - "4.9.0", - "4.8.1", - "4.8.0", - "4.7.2", - "4.7.1", - "4.7.0", - "4.6.0", - "4.5.0", - "4.4.0", - "4.3.0", - "4.2.0", - "4.1.0", - "4.0.0", - "3.10.0", - "3.9.0", - "3.8.0", - "3.7.0", - "3.6.0", - "3.5.0", - "3.4.0", - "3.3.0", - "3.2.0", - "3.1.0", - "3.0.0", - "2.2.0", - "2.1.0", - "2.0.0", - "1.4.0", - "1.3.0", - "1.2.1", - "1.2.0", - "1.1.0", - "1.0.0", - "0.7.1", - "0.7.0", - "0.6.0", - "0.5.0", -} - -var CurrentVersion string = versions[0] -var BuildNumber string -var BuildDate string -var BuildHash string -var BuildHashEnterprise string -var BuildEnterpriseReady string -var versionsWithoutHotFixes []string - -func init() { - versionsWithoutHotFixes = make([]string, 0, len(versions)) - seen := make(map[string]string) - - for _, version := range versions { - maj, min, _ := SplitVersion(version) - verStr := fmt.Sprintf("%v.%v.0", maj, min) - - if seen[verStr] == "" { - versionsWithoutHotFixes = append(versionsWithoutHotFixes, verStr) - seen[verStr] = verStr - } - } -} - -func SplitVersion(version string) (int64, int64, int64) { - parts := strings.Split(version, ".") - - major := int64(0) - minor := int64(0) - patch := int64(0) - - if len(parts) > 0 { - major, _ = strconv.ParseInt(parts[0], 10, 64) - } - - if len(parts) > 1 { - minor, _ = strconv.ParseInt(parts[1], 10, 64) - } - - if len(parts) > 2 { - patch, _ = strconv.ParseInt(parts[2], 10, 64) - } - - return major, minor, patch -} - -func GetPreviousVersion(version string) string { - verMajor, verMinor, _ := SplitVersion(version) - verStr := fmt.Sprintf("%v.%v.0", verMajor, verMinor) - - for index, v := range versionsWithoutHotFixes { - if v == verStr && len(versionsWithoutHotFixes) > index+1 { - return versionsWithoutHotFixes[index+1] - } - } - - return "" -} - -func IsCurrentVersion(versionToCheck string) bool { - currentMajor, currentMinor, _ := SplitVersion(CurrentVersion) - toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck) - - if toCheckMajor == currentMajor && toCheckMinor == currentMinor { - return true - } - return false -} - -func IsPreviousVersionsSupported(versionToCheck string) bool { - toCheckMajor, toCheckMinor, _ := SplitVersion(versionToCheck) - versionToCheckStr := fmt.Sprintf("%v.%v.0", toCheckMajor, toCheckMinor) - - // Current Supported - if versionsWithoutHotFixes[0] == versionToCheckStr { - return true - } - - // Current - 1 Supported - if versionsWithoutHotFixes[1] == versionToCheckStr { - return true - } - - // Current - 2 Supported - if versionsWithoutHotFixes[2] == versionToCheckStr { - return true - } - - // Current - 3 Supported - if versionsWithoutHotFixes[3] == versionToCheckStr { - return true - } - - return false -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_client.go b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_client.go deleted file mode 100644 index cd89e2d8..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_client.go +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "bytes" - "encoding/json" - "net/http" - "sync/atomic" - "time" - - "github.com/gorilla/websocket" -) - -const ( - SOCKET_MAX_MESSAGE_SIZE_KB = 8 * 1024 // 8KB - PING_TIMEOUT_BUFFER_SECONDS = 5 -) - -type msgType int - -const ( - msgTypeJSON msgType = iota + 1 - msgTypePong -) - -type writeMessage struct { - msgType msgType - data interface{} -} - -const avgReadMsgSizeBytes = 1024 - -// WebSocketClient stores the necessary information required to -// communicate with a WebSocket endpoint. -// A client must read from PingTimeoutChannel, EventChannel and ResponseChannel to prevent -// deadlocks from occurring in the program. -type WebSocketClient struct { - Url string // The location of the server like "ws://localhost:8065" - ApiUrl string // The API location of the server like "ws://localhost:8065/api/v3" - ConnectUrl string // The WebSocket URL to connect to like "ws://localhost:8065/api/v3/path/to/websocket" - Conn *websocket.Conn // The WebSocket connection - AuthToken string // The token used to open the WebSocket connection - Sequence int64 // The ever-incrementing sequence attached to each WebSocket action - PingTimeoutChannel chan bool // The channel used to signal ping timeouts - EventChannel chan *WebSocketEvent // The channel used to receive various events pushed from the server. For example: typing, posted - ResponseChannel chan *WebSocketResponse // The channel used to receive responses for requests made to the server - ListenError *AppError // A field that is set if there was an abnormal closure of the WebSocket connection - writeChan chan writeMessage - - pingTimeoutTimer *time.Timer - quitPingWatchdog chan struct{} - - quitWriterChan chan struct{} - resetTimerChan chan struct{} - closed int32 -} - -// NewWebSocketClient constructs a new WebSocket client with convenience -// methods for talking to the server. -func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) { - return NewWebSocketClientWithDialer(websocket.DefaultDialer, url, authToken) -} - -// NewWebSocketClientWithDialer constructs a new WebSocket client with convenience -// methods for talking to the server using a custom dialer. -func NewWebSocketClientWithDialer(dialer *websocket.Dialer, url, authToken string) (*WebSocketClient, *AppError) { - conn, _, err := dialer.Dial(url+API_URL_SUFFIX+"/websocket", nil) - if err != nil { - return nil, NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError) - } - - client := &WebSocketClient{ - Url: url, - ApiUrl: url + API_URL_SUFFIX, - ConnectUrl: url + API_URL_SUFFIX + "/websocket", - Conn: conn, - AuthToken: authToken, - Sequence: 1, - PingTimeoutChannel: make(chan bool, 1), - EventChannel: make(chan *WebSocketEvent, 100), - ResponseChannel: make(chan *WebSocketResponse, 100), - writeChan: make(chan writeMessage), - quitPingWatchdog: make(chan struct{}), - quitWriterChan: make(chan struct{}), - resetTimerChan: make(chan struct{}), - } - - client.configurePingHandling() - go client.writer() - - client.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": authToken}) - - return client, nil -} - -// NewWebSocketClient4 constructs a new WebSocket client with convenience -// methods for talking to the server. Uses the v4 endpoint. -func NewWebSocketClient4(url, authToken string) (*WebSocketClient, *AppError) { - return NewWebSocketClient4WithDialer(websocket.DefaultDialer, url, authToken) -} - -// NewWebSocketClient4WithDialer constructs a new WebSocket client with convenience -// methods for talking to the server using a custom dialer. Uses the v4 endpoint. -func NewWebSocketClient4WithDialer(dialer *websocket.Dialer, url, authToken string) (*WebSocketClient, *AppError) { - return NewWebSocketClientWithDialer(dialer, url, authToken) -} - -// Connect creates a websocket connection with the given ConnectUrl. -// This is racy and error-prone should not be used. Use any of the New* functions to create a websocket. -func (wsc *WebSocketClient) Connect() *AppError { - return wsc.ConnectWithDialer(websocket.DefaultDialer) -} - -// ConnectWithDialer creates a websocket connection with the given ConnectUrl using the dialer. -// This is racy and error-prone and should not be used. Use any of the New* functions to create a websocket. -func (wsc *WebSocketClient) ConnectWithDialer(dialer *websocket.Dialer) *AppError { - var err error - wsc.Conn, _, err = dialer.Dial(wsc.ConnectUrl, nil) - if err != nil { - return NewAppError("Connect", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError) - } - // Super racy and should not be done anyways. - // All of this needs to be redesigned for v6. - wsc.configurePingHandling() - // If it has been closed before, we just restart the writer. - if atomic.CompareAndSwapInt32(&wsc.closed, 1, 0) { - wsc.writeChan = make(chan writeMessage) - wsc.quitWriterChan = make(chan struct{}) - go wsc.writer() - wsc.resetTimerChan = make(chan struct{}) - wsc.quitPingWatchdog = make(chan struct{}) - } - - wsc.EventChannel = make(chan *WebSocketEvent, 100) - wsc.ResponseChannel = make(chan *WebSocketResponse, 100) - - wsc.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": wsc.AuthToken}) - - return nil -} - -// Close closes the websocket client. It is recommended that a closed client should not be -// reused again. Rather a new client should be created anew. -func (wsc *WebSocketClient) Close() { - // CAS to 1 and proceed. Return if already 1. - if !atomic.CompareAndSwapInt32(&wsc.closed, 0, 1) { - return - } - wsc.quitWriterChan <- struct{}{} - close(wsc.writeChan) - // We close the connection, which breaks the reader loop. - // Then we let the defer block in the reader do further cleanup. - wsc.Conn.Close() -} - -// TODO: un-export the Conn so that Write methods go through the writer -func (wsc *WebSocketClient) writer() { - for { - select { - case msg := <-wsc.writeChan: - switch msg.msgType { - case msgTypeJSON: - wsc.Conn.WriteJSON(msg.data) - case msgTypePong: - wsc.Conn.WriteMessage(websocket.PongMessage, []byte{}) - } - case <-wsc.quitWriterChan: - return - } - } -} - -// Listen starts the read loop of the websocket client. -func (wsc *WebSocketClient) Listen() { - // This loop can exit in 2 conditions: - // 1. Either the connection breaks naturally. - // 2. Close was explicitly called, which closes the connection manually. - // - // Due to the way the API is written, there is a requirement that a client may NOT - // call Listen at all and can still call Close and Connect. - // Therefore, we let the cleanup of the reader stuff rely on closing the connection - // and then we do the cleanup in the defer block. - // - // First, we close some channels and then CAS to 1 and proceed to close the writer chan also. - // This is needed because then the defer clause does not double-close the writer when (2) happens. - // But if (1) happens, we set the closed bit, and close the rest of the stuff. - go func() { - defer func() { - close(wsc.EventChannel) - close(wsc.ResponseChannel) - close(wsc.quitPingWatchdog) - close(wsc.resetTimerChan) - // We CAS to 1 and proceed. - if !atomic.CompareAndSwapInt32(&wsc.closed, 0, 1) { - return - } - wsc.quitWriterChan <- struct{}{} - close(wsc.writeChan) - wsc.Conn.Close() // This can most likely be removed. Needs to be checked. - }() - - var buf bytes.Buffer - buf.Grow(avgReadMsgSizeBytes) - - for { - // Reset buffer. - buf.Reset() - _, r, err := wsc.Conn.NextReader() - if err != nil { - if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) { - wsc.ListenError = NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError) - } - return - } - // Use pre-allocated buffer. - _, err = buf.ReadFrom(r) - if err != nil { - // This should use a different error ID, but en.json is not imported anyways. - // It's a different bug altogether but we let it be for now. - // See MM-24520. - wsc.ListenError = NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError) - return - } - - event := WebSocketEventFromJson(bytes.NewReader(buf.Bytes())) - if event == nil { - continue - } - if event.IsValid() { - wsc.EventChannel <- event - continue - } - - var response WebSocketResponse - if err := json.Unmarshal(buf.Bytes(), &response); err == nil && response.IsValid() { - wsc.ResponseChannel <- &response - continue - } - } - }() -} - -func (wsc *WebSocketClient) SendMessage(action string, data map[string]interface{}) { - req := &WebSocketRequest{} - req.Seq = wsc.Sequence - req.Action = action - req.Data = data - - wsc.Sequence++ - wsc.writeChan <- writeMessage{ - msgType: msgTypeJSON, - data: req, - } -} - -// UserTyping will push a user_typing event out to all connected users -// who are in the specified channel -func (wsc *WebSocketClient) UserTyping(channelId, parentId string) { - data := map[string]interface{}{ - "channel_id": channelId, - "parent_id": parentId, - } - - wsc.SendMessage("user_typing", data) -} - -// GetStatuses will return a map of string statuses using user id as the key -func (wsc *WebSocketClient) GetStatuses() { - wsc.SendMessage("get_statuses", nil) -} - -// GetStatusesByIds will fetch certain user statuses based on ids and return -// a map of string statuses using user id as the key -func (wsc *WebSocketClient) GetStatusesByIds(userIds []string) { - data := map[string]interface{}{ - "user_ids": userIds, - } - wsc.SendMessage("get_statuses_by_ids", data) -} - -func (wsc *WebSocketClient) configurePingHandling() { - wsc.Conn.SetPingHandler(wsc.pingHandler) - wsc.pingTimeoutTimer = time.NewTimer(time.Second * (60 + PING_TIMEOUT_BUFFER_SECONDS)) - go wsc.pingWatchdog() -} - -func (wsc *WebSocketClient) pingHandler(appData string) error { - if atomic.LoadInt32(&wsc.closed) == 1 { - return nil - } - wsc.resetTimerChan <- struct{}{} - wsc.writeChan <- writeMessage{ - msgType: msgTypePong, - } - return nil -} - -// pingWatchdog is used to send values to the PingTimeoutChannel whenever a timeout occurs. -// We use the resetTimerChan from the pingHandler to pass the signal, and then reset the timer -// after draining it. And if the timer naturally expires, we also extend it to prevent it from -// being deadlocked when the resetTimerChan case runs. Because timer.Stop would return false, -// and the code would be forever stuck trying to read from C. -func (wsc *WebSocketClient) pingWatchdog() { - for { - select { - case <-wsc.resetTimerChan: - if !wsc.pingTimeoutTimer.Stop() { - <-wsc.pingTimeoutTimer.C - } - wsc.pingTimeoutTimer.Reset(time.Second * (60 + PING_TIMEOUT_BUFFER_SECONDS)) - - case <-wsc.pingTimeoutTimer.C: - wsc.PingTimeoutChannel <- true - wsc.pingTimeoutTimer.Reset(time.Second * (60 + PING_TIMEOUT_BUFFER_SECONDS)) - case <-wsc.quitPingWatchdog: - return - } - } -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_message.go b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_message.go deleted file mode 100644 index 9a845d36..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_message.go +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "bytes" - "encoding/json" - "fmt" - "io" -) - -const ( - WEBSOCKET_EVENT_TYPING = "typing" - WEBSOCKET_EVENT_POSTED = "posted" - WEBSOCKET_EVENT_POST_EDITED = "post_edited" - WEBSOCKET_EVENT_POST_DELETED = "post_deleted" - WEBSOCKET_EVENT_POST_UNREAD = "post_unread" - WEBSOCKET_EVENT_CHANNEL_CONVERTED = "channel_converted" - WEBSOCKET_EVENT_CHANNEL_CREATED = "channel_created" - WEBSOCKET_EVENT_CHANNEL_DELETED = "channel_deleted" - WEBSOCKET_EVENT_CHANNEL_RESTORED = "channel_restored" - WEBSOCKET_EVENT_CHANNEL_UPDATED = "channel_updated" - WEBSOCKET_EVENT_CHANNEL_MEMBER_UPDATED = "channel_member_updated" - WEBSOCKET_EVENT_CHANNEL_SCHEME_UPDATED = "channel_scheme_updated" - WEBSOCKET_EVENT_DIRECT_ADDED = "direct_added" - WEBSOCKET_EVENT_GROUP_ADDED = "group_added" - WEBSOCKET_EVENT_NEW_USER = "new_user" - WEBSOCKET_EVENT_ADDED_TO_TEAM = "added_to_team" - WEBSOCKET_EVENT_LEAVE_TEAM = "leave_team" - WEBSOCKET_EVENT_UPDATE_TEAM = "update_team" - WEBSOCKET_EVENT_DELETE_TEAM = "delete_team" - WEBSOCKET_EVENT_RESTORE_TEAM = "restore_team" - WEBSOCKET_EVENT_UPDATE_TEAM_SCHEME = "update_team_scheme" - WEBSOCKET_EVENT_USER_ADDED = "user_added" - WEBSOCKET_EVENT_USER_UPDATED = "user_updated" - WEBSOCKET_EVENT_USER_ROLE_UPDATED = "user_role_updated" - WEBSOCKET_EVENT_MEMBERROLE_UPDATED = "memberrole_updated" - WEBSOCKET_EVENT_USER_REMOVED = "user_removed" - WEBSOCKET_EVENT_PREFERENCE_CHANGED = "preference_changed" - WEBSOCKET_EVENT_PREFERENCES_CHANGED = "preferences_changed" - WEBSOCKET_EVENT_PREFERENCES_DELETED = "preferences_deleted" - WEBSOCKET_EVENT_EPHEMERAL_MESSAGE = "ephemeral_message" - WEBSOCKET_EVENT_STATUS_CHANGE = "status_change" - WEBSOCKET_EVENT_HELLO = "hello" - WEBSOCKET_AUTHENTICATION_CHALLENGE = "authentication_challenge" - WEBSOCKET_EVENT_REACTION_ADDED = "reaction_added" - WEBSOCKET_EVENT_REACTION_REMOVED = "reaction_removed" - WEBSOCKET_EVENT_RESPONSE = "response" - WEBSOCKET_EVENT_EMOJI_ADDED = "emoji_added" - WEBSOCKET_EVENT_CHANNEL_VIEWED = "channel_viewed" - WEBSOCKET_EVENT_PLUGIN_STATUSES_CHANGED = "plugin_statuses_changed" - WEBSOCKET_EVENT_PLUGIN_ENABLED = "plugin_enabled" - WEBSOCKET_EVENT_PLUGIN_DISABLED = "plugin_disabled" - WEBSOCKET_EVENT_ROLE_UPDATED = "role_updated" - WEBSOCKET_EVENT_LICENSE_CHANGED = "license_changed" - WEBSOCKET_EVENT_CONFIG_CHANGED = "config_changed" - WEBSOCKET_EVENT_OPEN_DIALOG = "open_dialog" - WEBSOCKET_EVENT_GUESTS_DEACTIVATED = "guests_deactivated" - WEBSOCKET_EVENT_USER_ACTIVATION_STATUS_CHANGE = "user_activation_status_change" - WEBSOCKET_EVENT_RECEIVED_GROUP = "received_group" - WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_TEAM = "received_group_associated_to_team" - WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_TEAM = "received_group_not_associated_to_team" - WEBSOCKET_EVENT_RECEIVED_GROUP_ASSOCIATED_TO_CHANNEL = "received_group_associated_to_channel" - WEBSOCKET_EVENT_RECEIVED_GROUP_NOT_ASSOCIATED_TO_CHANNEL = "received_group_not_associated_to_channel" - WEBSOCKET_EVENT_SIDEBAR_CATEGORY_CREATED = "sidebar_category_created" - WEBSOCKET_EVENT_SIDEBAR_CATEGORY_UPDATED = "sidebar_category_updated" - WEBSOCKET_EVENT_SIDEBAR_CATEGORY_DELETED = "sidebar_category_deleted" - WEBSOCKET_EVENT_SIDEBAR_CATEGORY_ORDER_UPDATED = "sidebar_category_order_updated" - WEBSOCKET_WARN_METRIC_STATUS_RECEIVED = "warn_metric_status_received" - WEBSOCKET_WARN_METRIC_STATUS_REMOVED = "warn_metric_status_removed" - WEBSOCKET_EVENT_CLOUD_PAYMENT_STATUS_UPDATED = "cloud_payment_status_updated" - WEBSOCKET_EVENT_THREAD_UPDATED = "thread_updated" - WEBSOCKET_EVENT_THREAD_FOLLOW_CHANGED = "thread_follow_changed" - WEBSOCKET_EVENT_THREAD_READ_CHANGED = "thread_read_changed" - WEBSOCKET_FIRST_ADMIN_VISIT_MARKETPLACE_STATUS_RECEIVED = "first_admin_visit_marketplace_status_received" -) - -type WebSocketMessage interface { - ToJson() string - IsValid() bool - EventType() string -} - -type WebsocketBroadcast struct { - OmitUsers map[string]bool `json:"omit_users"` // broadcast is omitted for users listed here - UserId string `json:"user_id"` // broadcast only occurs for this user - ChannelId string `json:"channel_id"` // broadcast only occurs for users in this channel - TeamId string `json:"team_id"` // broadcast only occurs for users in this team - ContainsSanitizedData bool `json:"-"` - ContainsSensitiveData bool `json:"-"` -} - -type precomputedWebSocketEventJSON struct { - Event json.RawMessage - Data json.RawMessage - Broadcast json.RawMessage -} - -// webSocketEventJSON mirrors WebSocketEvent to make some of its unexported fields serializable -type webSocketEventJSON struct { - Event string `json:"event"` - Data map[string]interface{} `json:"data"` - Broadcast *WebsocketBroadcast `json:"broadcast"` - Sequence int64 `json:"seq"` -} - -// **NOTE**: Direct access to WebSocketEvent fields is deprecated. They will be -// made unexported in next major version release. Provided getter functions should be used instead. -type WebSocketEvent struct { - Event string // Deprecated: use EventType() - Data map[string]interface{} // Deprecated: use GetData() - Broadcast *WebsocketBroadcast // Deprecated: use GetBroadcast() - Sequence int64 // Deprecated: use GetSequence() - precomputedJSON *precomputedWebSocketEventJSON -} - -// PrecomputeJSON precomputes and stores the serialized JSON for all fields other than Sequence. -// This makes ToJson much more efficient when sending the same event to multiple connections. -func (ev *WebSocketEvent) PrecomputeJSON() *WebSocketEvent { - copy := ev.Copy() - event, _ := json.Marshal(copy.Event) - data, _ := json.Marshal(copy.Data) - broadcast, _ := json.Marshal(copy.Broadcast) - copy.precomputedJSON = &precomputedWebSocketEventJSON{ - Event: json.RawMessage(event), - Data: json.RawMessage(data), - Broadcast: json.RawMessage(broadcast), - } - return copy -} - -func (ev *WebSocketEvent) Add(key string, value interface{}) { - ev.Data[key] = value -} - -func NewWebSocketEvent(event, teamId, channelId, userId string, omitUsers map[string]bool) *WebSocketEvent { - return &WebSocketEvent{Event: event, Data: make(map[string]interface{}), - Broadcast: &WebsocketBroadcast{TeamId: teamId, ChannelId: channelId, UserId: userId, OmitUsers: omitUsers}} -} - -func (ev *WebSocketEvent) Copy() *WebSocketEvent { - copy := &WebSocketEvent{ - Event: ev.Event, - Data: ev.Data, - Broadcast: ev.Broadcast, - Sequence: ev.Sequence, - precomputedJSON: ev.precomputedJSON, - } - return copy -} - -func (ev *WebSocketEvent) GetData() map[string]interface{} { - return ev.Data -} - -func (ev *WebSocketEvent) GetBroadcast() *WebsocketBroadcast { - return ev.Broadcast -} - -func (ev *WebSocketEvent) GetSequence() int64 { - return ev.Sequence -} - -func (ev *WebSocketEvent) SetEvent(event string) *WebSocketEvent { - copy := ev.Copy() - copy.Event = event - return copy -} - -func (ev *WebSocketEvent) SetData(data map[string]interface{}) *WebSocketEvent { - copy := ev.Copy() - copy.Data = data - return copy -} - -func (ev *WebSocketEvent) SetBroadcast(broadcast *WebsocketBroadcast) *WebSocketEvent { - copy := ev.Copy() - copy.Broadcast = broadcast - return copy -} - -func (ev *WebSocketEvent) SetSequence(seq int64) *WebSocketEvent { - copy := ev.Copy() - copy.Sequence = seq - return copy -} - -func (ev *WebSocketEvent) IsValid() bool { - return ev.Event != "" -} - -func (ev *WebSocketEvent) EventType() string { - return ev.Event -} - -func (ev *WebSocketEvent) ToJson() string { - if ev.precomputedJSON != nil { - return fmt.Sprintf(`{"event": %s, "data": %s, "broadcast": %s, "seq": %d}`, ev.precomputedJSON.Event, ev.precomputedJSON.Data, ev.precomputedJSON.Broadcast, ev.Sequence) - } - b, _ := json.Marshal(webSocketEventJSON{ - ev.Event, - ev.Data, - ev.Broadcast, - ev.Sequence, - }) - return string(b) -} - -// Encode encodes the event to the given encoder. -func (ev *WebSocketEvent) Encode(enc *json.Encoder) error { - if ev.precomputedJSON != nil { - return enc.Encode(json.RawMessage( - fmt.Sprintf(`{"event": %s, "data": %s, "broadcast": %s, "seq": %d}`, ev.precomputedJSON.Event, ev.precomputedJSON.Data, ev.precomputedJSON.Broadcast, ev.Sequence), - )) - } - - return enc.Encode(webSocketEventJSON{ - ev.Event, - ev.Data, - ev.Broadcast, - ev.Sequence, - }) -} - -func WebSocketEventFromJson(data io.Reader) *WebSocketEvent { - var ev WebSocketEvent - var o webSocketEventJSON - if err := json.NewDecoder(data).Decode(&o); err != nil { - return nil - } - ev.Event = o.Event - if u, ok := o.Data["user"]; ok { - // We need to convert to and from JSON again - // because the user is in the form of a map[string]interface{}. - buf, err := json.Marshal(u) - if err != nil { - return nil - } - o.Data["user"] = UserFromJson(bytes.NewReader(buf)) - } - ev.Data = o.Data - ev.Broadcast = o.Broadcast - ev.Sequence = o.Sequence - return &ev -} - -// WebSocketResponse represents a response received through the WebSocket -// for a request made to the server. This is available through the ResponseChannel -// channel in WebSocketClient. -type WebSocketResponse struct { - Status string `json:"status"` // The status of the response. For example: OK, FAIL. - SeqReply int64 `json:"seq_reply,omitempty"` // A counter which is incremented for every response sent. - Data map[string]interface{} `json:"data,omitempty"` // The data contained in the response. - Error *AppError `json:"error,omitempty"` // A field that is set if any error has occurred. -} - -func (m *WebSocketResponse) Add(key string, value interface{}) { - m.Data[key] = value -} - -func NewWebSocketResponse(status string, seqReply int64, data map[string]interface{}) *WebSocketResponse { - return &WebSocketResponse{Status: status, SeqReply: seqReply, Data: data} -} - -func NewWebSocketError(seqReply int64, err *AppError) *WebSocketResponse { - return &WebSocketResponse{Status: STATUS_FAIL, SeqReply: seqReply, Error: err} -} - -func (m *WebSocketResponse) IsValid() bool { - return m.Status != "" -} - -func (m *WebSocketResponse) EventType() string { - return WEBSOCKET_EVENT_RESPONSE -} - -func (m *WebSocketResponse) ToJson() string { - b, _ := json.Marshal(m) - return string(b) -} - -func WebSocketResponseFromJson(data io.Reader) *WebSocketResponse { - var o *WebSocketResponse - json.NewDecoder(data).Decode(&o) - return o -} diff --git a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_request.go b/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_request.go deleted file mode 100644 index f18f1285..00000000 --- a/vendor/github.com/mattermost/mattermost-server/v5/model/websocket_request.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -package model - -import ( - "encoding/json" - "io" - - "github.com/mattermost/mattermost-server/v5/shared/i18n" -) - -// WebSocketRequest represents a request made to the server through a websocket. -type WebSocketRequest struct { - // Client-provided fields - Seq int64 `json:"seq"` // A counter which is incremented for every request made. - Action string `json:"action"` // The action to perform for a request. For example: get_statuses, user_typing. - Data map[string]interface{} `json:"data"` // The metadata for an action. - - // Server-provided fields - Session Session `json:"-"` - T i18n.TranslateFunc `json:"-"` - Locale string `json:"-"` -} - -func (o *WebSocketRequest) ToJson() string { - b, _ := json.Marshal(o) - return string(b) -} - -func WebSocketRequestFromJson(data io.Reader) *WebSocketRequest { - var o *WebSocketRequest - json.NewDecoder(data).Decode(&o) - return o -} |