summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/platform/model
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mattermost/platform/model')
-rw-r--r--vendor/github.com/mattermost/platform/model/authorization.go55
-rw-r--r--vendor/github.com/mattermost/platform/model/channel.go47
-rw-r--r--vendor/github.com/mattermost/platform/model/channel_member.go28
-rw-r--r--vendor/github.com/mattermost/platform/model/client.go76
-rw-r--r--vendor/github.com/mattermost/platform/model/client4.go1006
-rw-r--r--vendor/github.com/mattermost/platform/model/command_response.go30
-rw-r--r--vendor/github.com/mattermost/platform/model/config.go245
-rw-r--r--vendor/github.com/mattermost/platform/model/file.go4
-rw-r--r--vendor/github.com/mattermost/platform/model/gitlab/gitlab.go9
-rw-r--r--vendor/github.com/mattermost/platform/model/incoming_webhook.go46
-rw-r--r--vendor/github.com/mattermost/platform/model/job.go4
-rw-r--r--vendor/github.com/mattermost/platform/model/license.go5
-rw-r--r--vendor/github.com/mattermost/platform/model/post.go14
-rw-r--r--vendor/github.com/mattermost/platform/model/post_list.go17
-rw-r--r--vendor/github.com/mattermost/platform/model/push_notification.go18
-rw-r--r--vendor/github.com/mattermost/platform/model/push_response.go57
-rw-r--r--vendor/github.com/mattermost/platform/model/session.go5
-rw-r--r--vendor/github.com/mattermost/platform/model/slack_attachment.go29
-rw-r--r--vendor/github.com/mattermost/platform/model/status.go2
-rw-r--r--vendor/github.com/mattermost/platform/model/team.go80
-rw-r--r--vendor/github.com/mattermost/platform/model/user.go143
-rw-r--r--vendor/github.com/mattermost/platform/model/utils.go32
-rw-r--r--vendor/github.com/mattermost/platform/model/version.go1
-rw-r--r--vendor/github.com/mattermost/platform/model/websocket_client.go8
-rw-r--r--vendor/github.com/mattermost/platform/model/websocket_message.go3
25 files changed, 1760 insertions, 204 deletions
diff --git a/vendor/github.com/mattermost/platform/model/authorization.go b/vendor/github.com/mattermost/platform/model/authorization.go
index 75aebf55..a7a6f374 100644
--- a/vendor/github.com/mattermost/platform/model/authorization.go
+++ b/vendor/github.com/mattermost/platform/model/authorization.go
@@ -27,7 +27,10 @@ var PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS *Permission
var PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS *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_TEAM_CHANNELS *Permission
@@ -46,9 +49,13 @@ var PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH *Permission
var PERMISSION_CREATE_POST *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
// General permission that encompases all system admin functions
// in the future this could be broken up to allow access to some
@@ -123,6 +130,16 @@ func InitalizePermissions() {
"authentication.permissions.manage_roles.name",
"authentication.permissions.manage_roles.description",
}
+ PERMISSION_MANAGE_TEAM_ROLES = &Permission{
+ "manage_team_roles",
+ "authentication.permissions.manage_team_roles.name",
+ "authentication.permissions.manage_team_roles.description",
+ }
+ PERMISSION_MANAGE_CHANNEL_ROLES = &Permission{
+ "manage_channel_roles",
+ "authentication.permissions.manage_channel_roles.name",
+ "authentication.permissions.manage_channel_roles.description",
+ }
PERMISSION_MANAGE_SYSTEM = &Permission{
"manage_system",
"authentication.permissions.manage_system.name",
@@ -133,6 +150,11 @@ func InitalizePermissions() {
"authentication.permissions.create_direct_channel.name",
"authentication.permissions.create_direct_channel.description",
}
+ PERMISSION_CREATE_GROUP_CHANNEL = &Permission{
+ "create_group_channel",
+ "authentication.permissions.create_group_channel.name",
+ "authentication.permissions.create_group_channel.description",
+ }
PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES = &Permission{
"manage__publicchannel_properties",
"authentication.permissions.manage_public_channel_properties.name",
@@ -223,11 +245,26 @@ func InitalizePermissions() {
"authentication.permissions.edit_others_posts.name",
"authentication.permissions.edit_others_posts.description",
}
+ PERMISSION_DELETE_POST = &Permission{
+ "delete_post",
+ "authentication.permissions.delete_post.name",
+ "authentication.permissions.delete_post.description",
+ }
+ PERMISSION_DELETE_OTHERS_POSTS = &Permission{
+ "delete_others_posts",
+ "authentication.permissions.delete_others_posts.name",
+ "authentication.permissions.delete_others_posts.description",
+ }
PERMISSION_REMOVE_USER_FROM_TEAM = &Permission{
"remove_user_from_team",
"authentication.permissions.remove_user_from_team.name",
"authentication.permissions.remove_user_from_team.description",
}
+ PERMISSION_CREATE_TEAM = &Permission{
+ "create_team",
+ "authentication.permissions.create_team.name",
+ "authentication.permissions.create_team.description",
+ }
PERMISSION_MANAGE_TEAM = &Permission{
"manage_team",
"authentication.permissions.manage_team.name",
@@ -238,6 +275,11 @@ func InitalizePermissions() {
"authentication.permissions.import_team.name",
"authentication.permissions.import_team.description",
}
+ PERMISSION_VIEW_TEAM = &Permission{
+ "view_team",
+ "authentication.permissions.view_team.name",
+ "authentication.permissions.view_team.description",
+ }
}
func InitalizeRoles() {
@@ -264,7 +306,9 @@ func InitalizeRoles() {
"channel_admin",
"authentication.roles.channel_admin.name",
"authentication.roles.channel_admin.description",
- []string{},
+ []string{
+ PERMISSION_MANAGE_CHANNEL_ROLES.Id,
+ },
}
BuiltInRoles[ROLE_CHANNEL_ADMIN.Id] = ROLE_CHANNEL_ADMIN
ROLE_CHANNEL_GUEST = &Role{
@@ -282,6 +326,7 @@ func InitalizeRoles() {
[]string{
PERMISSION_LIST_TEAM_CHANNELS.Id,
PERMISSION_JOIN_PUBLIC_CHANNELS.Id,
+ PERMISSION_VIEW_TEAM.Id,
},
}
BuiltInRoles[ROLE_TEAM_USER.Id] = ROLE_TEAM_USER
@@ -295,7 +340,8 @@ func InitalizeRoles() {
PERMISSION_REMOVE_USER_FROM_TEAM.Id,
PERMISSION_MANAGE_TEAM.Id,
PERMISSION_IMPORT_TEAM.Id,
- PERMISSION_MANAGE_ROLES.Id,
+ PERMISSION_MANAGE_TEAM_ROLES.Id,
+ PERMISSION_MANAGE_CHANNEL_ROLES.Id,
PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id,
PERMISSION_MANAGE_SLASH_COMMANDS.Id,
PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id,
@@ -310,6 +356,7 @@ func InitalizeRoles() {
"authentication.roles.global_user.description",
[]string{
PERMISSION_CREATE_DIRECT_CHANNEL.Id,
+ PERMISSION_CREATE_GROUP_CHANNEL.Id,
PERMISSION_PERMANENT_DELETE_USER.Id,
PERMISSION_MANAGE_OAUTH.Id,
},
@@ -329,6 +376,7 @@ func InitalizeRoles() {
[]string{
PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE.Id,
PERMISSION_MANAGE_SYSTEM.Id,
+ PERMISSION_MANAGE_ROLES.Id,
PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id,
PERMISSION_DELETE_PUBLIC_CHANNEL.Id,
PERMISSION_CREATE_PUBLIC_CHANNEL.Id,
@@ -340,6 +388,9 @@ func InitalizeRoles() {
PERMISSION_EDIT_OTHER_USERS.Id,
PERMISSION_MANAGE_OAUTH.Id,
PERMISSION_INVITE_USER.Id,
+ PERMISSION_DELETE_POST.Id,
+ PERMISSION_DELETE_OTHERS_POSTS.Id,
+ PERMISSION_CREATE_TEAM.Id,
},
ROLE_TEAM_USER.Permissions...,
),
diff --git a/vendor/github.com/mattermost/platform/model/channel.go b/vendor/github.com/mattermost/platform/model/channel.go
index 2ad257cc..d24fdb2b 100644
--- a/vendor/github.com/mattermost/platform/model/channel.go
+++ b/vendor/github.com/mattermost/platform/model/channel.go
@@ -4,8 +4,12 @@
package model
import (
+ "crypto/sha1"
+ "encoding/hex"
"encoding/json"
"io"
+ "sort"
+ "strings"
"unicode/utf8"
)
@@ -13,11 +17,16 @@ 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
)
type Channel struct {
@@ -83,15 +92,11 @@ func (o *Channel) IsValid() *AppError {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.display_name.app_error", nil, "id="+o.Id)
}
- if len(o.Name) > CHANNEL_NAME_MAX_LENGTH {
- return NewLocAppError("Channel.IsValid", "model.channel.is_valid.name.app_error", nil, "id="+o.Id)
- }
-
if !IsValidChannelIdentifier(o.Name) {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.2_or_more.app_error", nil, "id="+o.Id)
}
- if !(o.Type == CHANNEL_OPEN || o.Type == CHANNEL_PRIVATE || o.Type == CHANNEL_DIRECT) {
+ if !(o.Type == CHANNEL_OPEN || o.Type == CHANNEL_PRIVATE || o.Type == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP) {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.type.app_error", nil, "id="+o.Id)
}
@@ -128,6 +133,10 @@ func (o *Channel) ExtraUpdated() {
o.ExtraUpdateAt = GetMillis()
}
+func (o *Channel) IsGroupOrDirect() bool {
+ return o.Type == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP
+}
+
func GetDMNameFromIds(userId1, userId2 string) string {
if userId1 > userId2 {
return userId2 + "__" + userId1
@@ -135,3 +144,31 @@ func GetDMNameFromIds(userId1, userId2 string) string {
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/platform/model/channel_member.go b/vendor/github.com/mattermost/platform/model/channel_member.go
index a607a505..5de58bc4 100644
--- a/vendor/github.com/mattermost/platform/model/channel_member.go
+++ b/vendor/github.com/mattermost/platform/model/channel_member.go
@@ -88,18 +88,32 @@ func (o *ChannelMember) IsValid() *AppError {
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.user_id.app_error", nil, "")
}
- notifyLevel := o.NotifyProps["desktop"]
+ notifyLevel := o.NotifyProps[DESKTOP_NOTIFY_PROP]
if len(notifyLevel) > 20 || !IsChannelNotifyLevelValid(notifyLevel) {
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.notify_level.app_error",
nil, "notify_level="+notifyLevel)
}
- markUnreadLevel := o.NotifyProps["mark_unread"]
+ markUnreadLevel := o.NotifyProps[MARK_UNREAD_NOTIFY_PROP]
if len(markUnreadLevel) > 20 || !IsChannelMarkUnreadLevelValid(markUnreadLevel) {
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.unread_level.app_error",
nil, "mark_unread_level="+markUnreadLevel)
}
+ if pushLevel, ok := o.NotifyProps[PUSH_NOTIFY_PROP]; ok {
+ if len(pushLevel) > 20 || !IsChannelNotifyLevelValid(pushLevel) {
+ return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.push_level.app_error",
+ nil, "push_notification_level="+pushLevel)
+ }
+ }
+
+ if sendEmail, ok := o.NotifyProps[EMAIL_NOTIFY_PROP]; ok {
+ if len(sendEmail) > 20 || !IsSendEmailValid(sendEmail) {
+ return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.email_value.app_error",
+ nil, "push_notification_level="+sendEmail)
+ }
+ }
+
return nil
}
@@ -126,9 +140,15 @@ 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 GetDefaultChannelNotifyProps() StringMap {
return StringMap{
- "desktop": CHANNEL_NOTIFY_DEFAULT,
- "mark_unread": CHANNEL_MARK_UNREAD_ALL,
+ 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,
}
}
diff --git a/vendor/github.com/mattermost/platform/model/client.go b/vendor/github.com/mattermost/platform/model/client.go
index 540bc747..24ee2c2b 100644
--- a/vendor/github.com/mattermost/platform/model/client.go
+++ b/vendor/github.com/mattermost/platform/model/client.go
@@ -35,12 +35,14 @@ const (
STATUS = "status"
STATUS_OK = "OK"
STATUS_FAIL = "FAIL"
+ STATUS_REMOVE = "REMOVE"
CLIENT_DIR = "webapp/dist"
API_URL_SUFFIX_V1 = "/api/v1"
API_URL_SUFFIX_V3 = "/api/v3"
- API_URL_SUFFIX = API_URL_SUFFIX_V3
+ API_URL_SUFFIX_V4 = "/api/v4"
+ API_URL_SUFFIX = API_URL_SUFFIX_V4
)
type Result struct {
@@ -71,7 +73,7 @@ type Client struct {
// NewClient constructs a new client with convienence methods for talking to
// the server.
func NewClient(url string) *Client {
- return &Client{url, url + API_URL_SUFFIX, &http.Client{}, "", "", "", "", "", ""}
+ return &Client{url, url + API_URL_SUFFIX_V3, &http.Client{}, "", "", "", "", "", ""}
}
func closeBody(r *http.Response) {
@@ -782,7 +784,7 @@ func (c *Client) GetSessions(id string) (*Result, *AppError) {
}
func (c *Client) EmailToOAuth(m map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/claim/email_to_sso", MapToJson(m)); err != nil {
+ if r, err := c.DoApiPost("/users/claim/email_to_oauth", MapToJson(m)); err != nil {
return nil, err
} else {
defer closeBody(r)
@@ -1119,6 +1121,16 @@ func (c *Client) CreateDirectChannel(userId string) (*Result, *AppError) {
}
}
+func (c *Client) CreateGroupChannel(userIds []string) (*Result, *AppError) {
+ if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create_group", ArrayToJson(userIds)); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
+ }
+}
+
func (c *Client) UpdateChannel(channel *Channel) (*Result, *AppError) {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update", channel.ToJson()); err != nil {
return nil, err
@@ -1471,6 +1483,21 @@ func (c *Client) GetPostById(postId string, etag string) (*PostList, *ResponseMe
}
}
+// GetPermalink returns a post list, based on the provided channel and post ID.
+func (c *Client) GetPermalink(channelId string, postId string, etag string) (*PostList, *ResponseMetadata) {
+ if r, err := c.DoApiGet(c.GetTeamRoute()+fmt.Sprintf("/pltmp/%v", postId), "", etag); err != nil {
+ return nil, &ResponseMetadata{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return PostListFromJson(r.Body),
+ &ResponseMetadata{
+ StatusCode: r.StatusCode,
+ RequestId: r.Header.Get(HEADER_REQUEST_ID),
+ Etag: r.Header.Get(HEADER_ETAG_SERVER),
+ }
+ }
+}
+
func (c *Client) DeletePost(channelId string, postId string) (*Result, *AppError) {
if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/delete", postId), ""); err != nil {
return nil, err
@@ -1991,6 +2018,16 @@ func (c *Client) CreateIncomingWebhook(hook *IncomingWebhook) (*Result, *AppErro
}
}
+func (c *Client) UpdateIncomingWebhook(hook *IncomingWebhook) (*Result, *AppError) {
+ if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/update", hook.ToJson()); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), IncomingWebhookFromJson(r.Body)}, nil
+ }
+}
+
func (c *Client) PostToWebhook(id, payload string) (*Result, *AppError) {
if r, err := c.DoPost("/hooks/"+id, payload, "application/x-www-form-urlencoded"); err != nil {
return nil, err
@@ -2082,6 +2119,16 @@ func (c *Client) CreateOutgoingWebhook(hook *OutgoingWebhook) (*Result, *AppErro
}
}
+func (c *Client) UpdateOutgoingWebhook(hook *OutgoingWebhook) (*Result, *AppError) {
+ if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/update", hook.ToJson()); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookFromJson(r.Body)}, nil
+ }
+}
+
func (c *Client) DeleteOutgoingWebhook(id string) (*Result, *AppError) {
data := make(map[string]string)
data["id"] = id
@@ -2319,3 +2366,26 @@ func (c *Client) ListReactions(channelId string, postId string) ([]*Reaction, *A
return ReactionsFromJson(r.Body), nil
}
}
+
+// Updates the user's roles in the channel by replacing them with the roles provided.
+func (c *Client) UpdateChannelRoles(channelId string, userId string, roles string) (map[string]string, *ResponseMetadata) {
+ data := make(map[string]string)
+ data["new_roles"] = roles
+ data["user_id"] = userId
+
+ if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/update_member_roles", MapToJson(data)); err != nil {
+ metadata := ResponseMetadata{Error: err}
+ if r != nil {
+ metadata.StatusCode = r.StatusCode
+ }
+ return nil, &metadata
+ } else {
+ defer closeBody(r)
+ return MapFromJson(r.Body),
+ &ResponseMetadata{
+ StatusCode: r.StatusCode,
+ RequestId: r.Header.Get(HEADER_REQUEST_ID),
+ Etag: r.Header.Get(HEADER_ETAG_SERVER),
+ }
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/client4.go b/vendor/github.com/mattermost/platform/model/client4.go
new file mode 100644
index 00000000..d3bb6534
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/client4.go
@@ -0,0 +1,1006 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "mime/multipart"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+)
+
+type Response struct {
+ StatusCode int
+ Error *AppError
+ RequestId string
+ Etag string
+ ServerVersion string
+}
+
+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
+}
+
+func NewAPIv4Client(url string) *Client4 {
+ return &Client4{url, url + API_URL_SUFFIX, &http.Client{}, "", ""}
+}
+
+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),
+ }
+}
+
+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 fmt.Sprintf("/users")
+}
+
+func (c *Client4) GetUserRoute(userId string) string {
+ return fmt.Sprintf(c.GetUsersRoute()+"/%v", userId)
+}
+
+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) GetTeamsRoute() string {
+ return fmt.Sprintf("/teams")
+}
+
+func (c *Client4) GetTeamRoute(teamId string) string {
+ return fmt.Sprintf(c.GetTeamsRoute()+"/%v", 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) GetChannelsRoute() string {
+ return fmt.Sprintf("/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) 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 fmt.Sprintf("/posts")
+}
+
+func (c *Client4) GetPostRoute(postId string) string {
+ return fmt.Sprintf(c.GetPostsRoute()+"/%v", postId)
+}
+
+func (c *Client4) GetFilesRoute() string {
+ return fmt.Sprintf("/files")
+}
+
+func (c *Client4) GetFileRoute(fileId string) string {
+ return fmt.Sprintf(c.GetFilesRoute()+"/%v", fileId)
+}
+
+func (c *Client4) GetSystemRoute() string {
+ return fmt.Sprintf("/system")
+}
+
+func (c *Client4) GetIncomingWebhooksRoute() string {
+ return fmt.Sprintf("/hooks/incoming")
+}
+
+func (c *Client4) GetPreferencesRoute(userId string) string {
+ return fmt.Sprintf(c.GetUserRoute(userId) + "/preferences")
+}
+
+func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) {
+ return c.DoApiRequest(http.MethodGet, url, "", etag)
+}
+
+func (c *Client4) DoApiPost(url string, data string) (*http.Response, *AppError) {
+ return c.DoApiRequest(http.MethodPost, url, data, "")
+}
+
+func (c *Client4) DoApiPut(url string, data string) (*http.Response, *AppError) {
+ return c.DoApiRequest(http.MethodPut, url, data, "")
+}
+
+func (c *Client4) DoApiDelete(url string) (*http.Response, *AppError) {
+ return c.DoApiRequest(http.MethodDelete, url, "", "")
+}
+
+func (c *Client4) DoApiRequest(method, url, data, etag string) (*http.Response, *AppError) {
+ rq, _ := http.NewRequest(method, c.ApiUrl+url, strings.NewReader(data))
+ rq.Close = true
+
+ if len(etag) > 0 {
+ rq.Header.Set(HEADER_ETAG_CLIENT, etag)
+ }
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ if rp, err := c.HttpClient.Do(rq); err != nil {
+ return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
+ } else if rp.StatusCode == 304 {
+ return rp, nil
+ } else if rp.StatusCode >= 300 {
+ defer closeBody(rp)
+ return rp, AppErrorFromJson(rp.Body)
+ } else {
+ return rp, nil
+ }
+}
+
+func (c *Client4) DoUploadFile(url string, data []byte, contentType string) (*FileUploadResponse, *Response) {
+ rq, _ := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
+ rq.Header.Set("Content-Type", contentType)
+ rq.Close = true
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ if rp, err := c.HttpClient.Do(rq); err != nil {
+ return nil, &Response{Error: NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)}
+ } else if rp.StatusCode >= 300 {
+ return nil, &Response{StatusCode: rp.StatusCode, Error: AppErrorFromJson(rp.Body)}
+ } else {
+ defer closeBody(rp)
+ return FileUploadResponseFromJson(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"] = "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)
+}
+
+func (c *Client4) login(m map[string]string) (*User, *Response) {
+ if r, err := c.DoApiPost("/users/login", MapToJson(m)); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ c.AuthToken = r.Header.Get(HEADER_TOKEN)
+ c.AuthType = HEADER_BEARER
+ defer closeBody(r)
+ return UserFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// Logout terminates the current user's session.
+func (c *Client4) Logout() (bool, *Response) {
+ if r, err := c.DoApiPost("/users/logout", ""); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ c.AuthToken = ""
+ c.AuthType = HEADER_BEARER
+
+ defer closeBody(r)
+ return CheckStatusOK(r), 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) {
+ if r, err := c.DoApiPost(c.GetUsersRoute(), user.ToJson()); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiGet(c.GetUserRoute(userId), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiGet(c.GetUserByUsernameRoute(userName), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiGet(c.GetUserByEmailRoute(email), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return UserFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// GetProfileImage gets user's profile image. Must be logged in or be a system administrator.
+func (c *Client4) GetProfileImage(userId, etag string) ([]byte, *Response) {
+ if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/image", etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else if data, err := ioutil.ReadAll(r.Body); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: NewAppError("GetProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)}
+ } else {
+ 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)
+ if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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)
+ if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// GetUsersInChannel returns a page of users on a team. 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)
+ if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return UserListFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// GetUsersNotInChannel returns a page of users on a team. 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&not_in_channel=%v&page=%v&per_page=%v", teamId, channelId, page, perPage)
+ if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiPost(c.GetUsersRoute()+"/ids", ArrayToJson(userIds)); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiPut(c.GetUserRoute(user.Id), user.ToJson()); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/patch", patch.ToJson()); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return UserFromJson(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}
+ if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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}
+ if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/roles", MapToJson(requestBody)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiDelete(c.GetUserRoute(userId)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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}
+ if r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset/send", MapToJson(requestBody)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+ }
+}
+
+// ResetPassword uses a recovery code to update reset a user's password.
+func (c *Client4) ResetPassword(code, newPassword string) (bool, *Response) {
+ requestBody := map[string]string{"code": code, "new_password": newPassword}
+ if r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset", MapToJson(requestBody)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/sessions", etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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}
+ if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke", MapToJson(requestBody)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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. Must be authenticated.
+func (c *Client4) GetTeamsUnreadForUser(userId, teamIdToExclude string) ([]*TeamUnread, *Response) {
+ optional := ""
+ if teamIdToExclude != "" {
+ optional += fmt.Sprintf("?exclude_team=%s", url.QueryEscape(teamIdToExclude))
+ }
+
+ if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread"+optional, ""); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return TeamsUnreadFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// GetAudits returns a list of audit based on the provided user id string.
+func (c *Client4) GetAudits(userId string, page int, perPage int, etag string) (Audits, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/audits"+query, etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return AuditsFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// Verify user email user id and hash strings.
+func (c *Client4) VerifyUserEmail(userId, hashId string) (bool, *Response) {
+ requestBody := map[string]string{"uid": userId, "hid": hashId}
+ if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/email/verify", MapToJson(requestBody)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ 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)
+
+ if part, err := writer.CreateFormFile("image", "profile.png"); err != nil {
+ return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ } else 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, _ := http.NewRequest("POST", c.ApiUrl+c.GetUserRoute(userId)+"/image", bytes.NewReader(body.Bytes()))
+ rq.Header.Set("Content-Type", writer.FormDataContentType())
+ rq.Close = true
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
+ }
+
+ if rp, err := c.HttpClient.Do(rq); err != nil {
+ // set to http.StatusForbidden(403)
+ return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetUserRoute(userId)+"/image", "model.client.connecting.app_error", nil, err.Error(), 403)}
+ } else if rp.StatusCode >= 300 {
+ return false, &Response{StatusCode: rp.StatusCode, Error: AppErrorFromJson(rp.Body)}
+ } else {
+ defer closeBody(rp)
+ return CheckStatusOK(rp), BuildResponse(rp)
+ }
+}
+
+// Team Section
+
+// CreateTeam creates a team in the system based on the provided team struct.
+func (c *Client4) CreateTeam(team *Team) (*Team, *Response) {
+ if r, err := c.DoApiPost(c.GetTeamsRoute(), team.ToJson()); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiGet(c.GetTeamRoute(teamId), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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)
+ if r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiGet(c.GetTeamByNameRoute(name), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return TeamFromJson(r.Body), 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) {
+ if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams", etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiGet(c.GetTeamMemberRoute(teamId, userId), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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}
+ if r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/roles", MapToJson(requestBody)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return CheckStatusOK(r), 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)
+ if r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return TeamMembersFromJson(r.Body), 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) {
+ if r, err := c.DoApiGet(c.GetTeamStatsRoute(teamId), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return TeamStatsFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// Channel Section
+
+// CreateChannel creates a channel based on the provided channel struct.
+func (c *Client4) CreateChannel(channel *Channel) (*Channel, *Response) {
+ if r, err := c.DoApiPost(c.GetChannelsRoute(), channel.ToJson()); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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}
+ if r, err := c.DoApiPost(c.GetChannelsRoute()+"/direct", ArrayToJson(requestBody)); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiGet(c.GetChannelRoute(channelId), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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)
+ if r, err := c.DoApiGet(c.GetChannelMembersRoute(channelId)+query, etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return ChannelMembersFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// GetChannelMember gets a channel member.
+func (c *Client4) GetChannelMember(channelId, userId, etag string) (*ChannelMember, *Response) {
+ if r, err := c.DoApiGet(c.GetChannelMemberRoute(channelId, userId), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiGet(fmt.Sprintf(c.GetUserRoute(userId)+"/teams/%v/channels/members", teamId), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) (bool, *Response) {
+ url := fmt.Sprintf(c.GetChannelsRoute()+"/members/%v/view", userId)
+ if r, err := c.DoApiPost(url, view.ToJson()); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return CheckStatusOK(r), 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}
+ if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/roles", MapToJson(requestBody)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return CheckStatusOK(r), 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) {
+ if r, err := c.DoApiDelete(c.GetChannelMemberRoute(channelId, userId)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+ }
+}
+
+// Post Section
+
+// CreatePost creates a post based on the provided post struct.
+func (c *Client4) CreatePost(post *Post) (*Post, *Response) {
+ if r, err := c.DoApiPost(c.GetPostsRoute(), post.ToJson()); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToJson()); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return PostFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// GetPost gets a single post.
+func (c *Client4) GetPost(postId string, etag string) (*Post, *Response) {
+ if r, err := c.DoApiGet(c.GetPostRoute(postId), etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) {
+ if r, err := c.DoApiDelete(c.GetPostRoute(postId)); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) (*PostList, *Response) {
+ if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/thread", etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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) (*PostList, *Response) {
+ query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
+ if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// SearchPosts returns any posts with matching terms string.
+func (c *Client4) SearchPosts(teamId string, terms string, isOrSearch bool) (*PostList, *Response) {
+ requestBody := map[string]string{"terms": terms, "is_or_search": strconv.FormatBool(isOrSearch)}
+ if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", MapToJson(requestBody)); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return PostListFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// File Section
+
+// UploadFile will upload a file to a channel, to be later attached to a post.
+func (c *Client4) UploadFile(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) {
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ if part, err := writer.CreateFormFile("files", filename); err != nil {
+ return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
+ return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if part, err := writer.CreateFormField("channel_id"); err != nil {
+ return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
+ } else if _, err = io.Copy(part, strings.NewReader(channelId)); err != nil {
+ return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
+ }
+
+ if err := writer.Close(); 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())
+}
+
+// GetFile gets the bytes for a file by id.
+func (c *Client4) GetFile(fileId string) ([]byte, *Response) {
+ if r, err := c.DoApiGet(c.GetFileRoute(fileId), ""); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else if data, err := ioutil.ReadAll(r.Body); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: NewAppError("GetFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)}
+ } else {
+ return data, BuildResponse(r)
+ }
+}
+
+// GetFileThumbnail gets the bytes for a file by id.
+func (c *Client4) GetFileThumbnail(fileId string) ([]byte, *Response) {
+ if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/thumbnail", ""); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else if data, err := ioutil.ReadAll(r.Body); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: NewAppError("GetFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode)}
+ } else {
+ return data, BuildResponse(r)
+ }
+}
+
+// GetFileInfosForPost gets all the file info objects attached to a post.
+func (c *Client4) GetFileInfosForPost(postId string, etag string) ([]*FileInfo, *Response) {
+ if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/files/info", etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return FileInfosFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// General Section
+
+// GetPing will ping the server and to see if it is up and running.
+func (c *Client4) GetPing() (bool, *Response) {
+ if r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", ""); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return CheckStatusOK(r), BuildResponse(r)
+ }
+}
+
+// Webhooks Section
+
+// CreateIncomingWebhook creates an incoming webhook for a channel.
+func (c *Client4) CreateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) {
+ if r, err := c.DoApiPost(c.GetIncomingWebhooksRoute(), hook.ToJson()); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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)
+ if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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)
+ if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
+ }
+}
+
+// Preferences Section
+
+// GetPreferences returns the user's preferences
+func (c *Client4) GetPreferences(userId string) (Preferences, *Response) {
+ if r, err := c.DoApiGet(c.GetPreferencesRoute(userId), ""); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ preferences, _ := PreferencesFromJson(r.Body)
+ defer closeBody(r)
+ return preferences, BuildResponse(r)
+ }
+}
+
+// UpdatePreferences saves the user's preferences
+func (c *Client4) UpdatePreferences(userId string, preferences *Preferences) (bool, *Response) {
+ if r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson()); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return true, BuildResponse(r)
+ }
+}
+
+// DeletePreferences deletes the user's preferences
+func (c *Client4) DeletePreferences(userId string, preferences *Preferences) (bool, *Response) {
+ if r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson()); err != nil {
+ return false, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ 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)
+ if r, err := c.DoApiGet(url, ""); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ preferences, _ := PreferencesFromJson(r.Body)
+ defer closeBody(r)
+ 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)
+ if r, err := c.DoApiGet(url, ""); err != nil {
+ return nil, &Response{StatusCode: r.StatusCode, Error: err}
+ } else {
+ defer closeBody(r)
+ return PreferenceFromJson(r.Body), BuildResponse(r)
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/command_response.go b/vendor/github.com/mattermost/platform/model/command_response.go
index bbb70418..f6977235 100644
--- a/vendor/github.com/mattermost/platform/model/command_response.go
+++ b/vendor/github.com/mattermost/platform/model/command_response.go
@@ -5,6 +5,7 @@ package model
import (
"encoding/json"
+ "fmt"
"io"
)
@@ -14,12 +15,12 @@ const (
)
type CommandResponse struct {
- ResponseType string `json:"response_type"`
- Text string `json:"text"`
- Username string `json:"username"`
- IconURL string `json:"icon_url"`
- GotoLocation string `json:"goto_location"`
- Attachments interface{} `json:"attachments"`
+ ResponseType string `json:"response_type"`
+ Text string `json:"text"`
+ Username string `json:"username"`
+ IconURL string `json:"icon_url"`
+ GotoLocation string `json:"goto_location"`
+ Attachments []*SlackAttachment `json:"attachments"`
}
func (o *CommandResponse) ToJson() string {
@@ -34,10 +35,19 @@ func (o *CommandResponse) ToJson() string {
func CommandResponseFromJson(data io.Reader) *CommandResponse {
decoder := json.NewDecoder(data)
var o CommandResponse
- err := decoder.Decode(&o)
- if err == nil {
- return &o
- } else {
+
+ if err := decoder.Decode(&o); err != nil {
return nil
}
+
+ // Ensure attachment fields are stored as strings
+ for _, attachment := range o.Attachments {
+ for _, field := range attachment.Fields {
+ if field.Value != nil {
+ field.Value = fmt.Sprintf("%v", field.Value)
+ }
+ }
+ }
+
+ return &o
}
diff --git a/vendor/github.com/mattermost/platform/model/config.go b/vendor/github.com/mattermost/platform/model/config.go
index 0134e1a3..86693b57 100644
--- a/vendor/github.com/mattermost/platform/model/config.go
+++ b/vendor/github.com/mattermost/platform/model/config.go
@@ -49,49 +49,109 @@ const (
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"
+
EMAIL_BATCHING_BUFFER_SIZE = 256
EMAIL_BATCHING_INTERVAL = 30
SITENAME_MAX_LENGTH = 30
+
+ SERVICE_SETTINGS_DEFAULT_SITE_URL = ""
+ 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_ALLOW_CORS_FROM = ""
+
+ TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT = ""
+ TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT = ""
+ TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT = 300
+
+ EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION = ""
+
+ SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK = "https://about.mattermost.com/default-terms/"
+ SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK = "https://about.mattermost.com/default-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 = "feedback@mattermost.com"
+
+ 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 = ""
+
+ 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 = ""
+
+ NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK = "https://about.mattermost.com/downloads/"
+ 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/"
+
+ WEBRTC_SETTINGS_DEFAULT_STUN_URI = ""
+ WEBRTC_SETTINGS_DEFAULT_TURN_URI = ""
+
+ ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS = 2500
)
type ServiceSettings struct {
- SiteURL *string
- ListenAddress string
- ConnectionSecurity *string
- TLSCertFile *string
- TLSKeyFile *string
- UseLetsEncrypt *bool
- LetsEncryptCertificateCacheFile *string
- Forward80To443 *bool
- ReadTimeout *int
- WriteTimeout *int
- MaximumLoginAttempts int
- SegmentDeveloperKey string
- GoogleDeveloperKey string
- EnableOAuthServiceProvider bool
- EnableIncomingWebhooks bool
- EnableOutgoingWebhooks bool
- EnableCommands *bool
- EnableOnlyAdminIntegrations *bool
- EnablePostUsernameOverride bool
- EnablePostIconOverride bool
- EnableTesting bool
- EnableDeveloper *bool
- EnableSecurityFixAlert *bool
- EnableInsecureOutgoingConnections *bool
- EnableMultifactorAuthentication *bool
- EnforceMultifactorAuthentication *bool
- AllowCorsFrom *string
- SessionLengthWebInDays *int
- SessionLengthMobileInDays *int
- SessionLengthSSOInDays *int
- SessionCacheInMinutes *int
- WebsocketSecurePort *int
- WebsocketPort *int
- WebserverMode *string
- EnableCustomEmoji *bool
- RestrictCustomEmojiCreation *string
+ SiteURL *string
+ ListenAddress string
+ ConnectionSecurity *string
+ TLSCertFile *string
+ TLSKeyFile *string
+ UseLetsEncrypt *bool
+ LetsEncryptCertificateCacheFile *string
+ Forward80To443 *bool
+ ReadTimeout *int
+ WriteTimeout *int
+ MaximumLoginAttempts int
+ GoogleDeveloperKey string
+ EnableOAuthServiceProvider bool
+ EnableIncomingWebhooks bool
+ EnableOutgoingWebhooks bool
+ EnableCommands *bool
+ EnableOnlyAdminIntegrations *bool
+ EnablePostUsernameOverride bool
+ EnablePostIconOverride bool
+ EnableLinkPreviews *bool
+ EnableTesting bool
+ EnableDeveloper *bool
+ EnableSecurityFixAlert *bool
+ EnableInsecureOutgoingConnections *bool
+ EnableMultifactorAuthentication *bool
+ EnforceMultifactorAuthentication *bool
+ AllowCorsFrom *string
+ SessionLengthWebInDays *int
+ SessionLengthMobileInDays *int
+ SessionLengthSSOInDays *int
+ SessionCacheInMinutes *int
+ WebsocketSecurePort *int
+ WebsocketPort *int
+ WebserverMode *string
+ EnableCustomEmoji *bool
+ RestrictCustomEmojiCreation *string
+ RestrictPostDelete *string
+ AllowEditPost *string
+ PostEditTimeLimit *int
+ TimeBetweenUserTypingUpdatesMilliseconds *int64
+ EnableUserTypingMessages *bool
+ ClusterLogTimeoutMilliseconds *int
}
type ClusterSettings struct {
@@ -433,7 +493,12 @@ func (o *Config) SetDefaults() {
if o.ServiceSettings.SiteURL == nil {
o.ServiceSettings.SiteURL = new(string)
- *o.ServiceSettings.SiteURL = ""
+ *o.ServiceSettings.SiteURL = SERVICE_SETTINGS_DEFAULT_SITE_URL
+ }
+
+ if o.ServiceSettings.EnableLinkPreviews == nil {
+ o.ServiceSettings.EnableLinkPreviews = new(bool)
+ *o.ServiceSettings.EnableLinkPreviews = false
}
if o.ServiceSettings.EnableDeveloper == nil {
@@ -493,12 +558,12 @@ func (o *Config) SetDefaults() {
if o.TeamSettings.CustomBrandText == nil {
o.TeamSettings.CustomBrandText = new(string)
- *o.TeamSettings.CustomBrandText = ""
+ *o.TeamSettings.CustomBrandText = TEAM_SETTINGS_DEFAULT_CUSTOM_BRAND_TEXT
}
if o.TeamSettings.CustomDescriptionText == nil {
o.TeamSettings.CustomDescriptionText = new(string)
- *o.TeamSettings.CustomDescriptionText = ""
+ *o.TeamSettings.CustomDescriptionText = TEAM_SETTINGS_DEFAULT_CUSTOM_DESCRIPTION_TEXT
}
if o.TeamSettings.EnableOpenServer == nil {
@@ -552,7 +617,7 @@ func (o *Config) SetDefaults() {
if o.TeamSettings.UserStatusAwayTimeout == nil {
o.TeamSettings.UserStatusAwayTimeout = new(int64)
- *o.TeamSettings.UserStatusAwayTimeout = 300
+ *o.TeamSettings.UserStatusAwayTimeout = TEAM_SETTINGS_DEFAULT_USER_STATUS_AWAY_TIMEOUT
}
if o.TeamSettings.MaxChannelsPerTeam == nil {
@@ -597,7 +662,7 @@ func (o *Config) SetDefaults() {
if o.EmailSettings.FeedbackOrganization == nil {
o.EmailSettings.FeedbackOrganization = new(string)
- *o.EmailSettings.FeedbackOrganization = ""
+ *o.EmailSettings.FeedbackOrganization = EMAIL_SETTINGS_DEFAULT_FEEDBACK_ORGANIZATION
}
if o.EmailSettings.EnableEmailBatching == nil {
@@ -621,7 +686,7 @@ func (o *Config) SetDefaults() {
if o.SupportSettings.TermsOfServiceLink == nil {
o.SupportSettings.TermsOfServiceLink = new(string)
- *o.SupportSettings.TermsOfServiceLink = "https://about.mattermost.com/default-terms/"
+ *o.SupportSettings.TermsOfServiceLink = SUPPORT_SETTINGS_DEFAULT_TERMS_OF_SERVICE_LINK
}
if !IsSafeLink(o.SupportSettings.PrivacyPolicyLink) {
@@ -630,7 +695,7 @@ func (o *Config) SetDefaults() {
if o.SupportSettings.PrivacyPolicyLink == nil {
o.SupportSettings.PrivacyPolicyLink = new(string)
- *o.SupportSettings.PrivacyPolicyLink = ""
+ *o.SupportSettings.PrivacyPolicyLink = SUPPORT_SETTINGS_DEFAULT_PRIVACY_POLICY_LINK
}
if !IsSafeLink(o.SupportSettings.AboutLink) {
@@ -639,7 +704,7 @@ func (o *Config) SetDefaults() {
if o.SupportSettings.AboutLink == nil {
o.SupportSettings.AboutLink = new(string)
- *o.SupportSettings.AboutLink = ""
+ *o.SupportSettings.AboutLink = SUPPORT_SETTINGS_DEFAULT_ABOUT_LINK
}
if !IsSafeLink(o.SupportSettings.HelpLink) {
@@ -648,7 +713,7 @@ func (o *Config) SetDefaults() {
if o.SupportSettings.HelpLink == nil {
o.SupportSettings.HelpLink = new(string)
- *o.SupportSettings.HelpLink = ""
+ *o.SupportSettings.HelpLink = SUPPORT_SETTINGS_DEFAULT_HELP_LINK
}
if !IsSafeLink(o.SupportSettings.ReportAProblemLink) {
@@ -657,12 +722,12 @@ func (o *Config) SetDefaults() {
if o.SupportSettings.ReportAProblemLink == nil {
o.SupportSettings.ReportAProblemLink = new(string)
- *o.SupportSettings.ReportAProblemLink = ""
+ *o.SupportSettings.ReportAProblemLink = SUPPORT_SETTINGS_DEFAULT_REPORT_A_PROBLEM_LINK
}
if o.SupportSettings.SupportEmail == nil {
o.SupportSettings.SupportEmail = new(string)
- *o.SupportSettings.SupportEmail = "feedback@mattermost.com"
+ *o.SupportSettings.SupportEmail = SUPPORT_SETTINGS_DEFAULT_SUPPORT_EMAIL
}
if o.LdapSettings.Enable == nil {
@@ -707,37 +772,37 @@ func (o *Config) SetDefaults() {
if o.LdapSettings.FirstNameAttribute == nil {
o.LdapSettings.FirstNameAttribute = new(string)
- *o.LdapSettings.FirstNameAttribute = ""
+ *o.LdapSettings.FirstNameAttribute = LDAP_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE
}
if o.LdapSettings.LastNameAttribute == nil {
o.LdapSettings.LastNameAttribute = new(string)
- *o.LdapSettings.LastNameAttribute = ""
+ *o.LdapSettings.LastNameAttribute = LDAP_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE
}
if o.LdapSettings.EmailAttribute == nil {
o.LdapSettings.EmailAttribute = new(string)
- *o.LdapSettings.EmailAttribute = ""
+ *o.LdapSettings.EmailAttribute = LDAP_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE
}
if o.LdapSettings.UsernameAttribute == nil {
o.LdapSettings.UsernameAttribute = new(string)
- *o.LdapSettings.UsernameAttribute = ""
+ *o.LdapSettings.UsernameAttribute = LDAP_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE
}
if o.LdapSettings.NicknameAttribute == nil {
o.LdapSettings.NicknameAttribute = new(string)
- *o.LdapSettings.NicknameAttribute = ""
+ *o.LdapSettings.NicknameAttribute = LDAP_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE
}
if o.LdapSettings.IdAttribute == nil {
o.LdapSettings.IdAttribute = new(string)
- *o.LdapSettings.IdAttribute = ""
+ *o.LdapSettings.IdAttribute = LDAP_SETTINGS_DEFAULT_ID_ATTRIBUTE
}
if o.LdapSettings.PositionAttribute == nil {
o.LdapSettings.PositionAttribute = new(string)
- *o.LdapSettings.PositionAttribute = ""
+ *o.LdapSettings.PositionAttribute = LDAP_SETTINGS_DEFAULT_POSITION_ATTRIBUTE
}
if o.LdapSettings.SyncIntervalMinutes == nil {
@@ -762,7 +827,7 @@ func (o *Config) SetDefaults() {
if o.LdapSettings.LoginFieldName == nil {
o.LdapSettings.LoginFieldName = new(string)
- *o.LdapSettings.LoginFieldName = ""
+ *o.LdapSettings.LoginFieldName = LDAP_SETTINGS_DEFAULT_LOGIN_FIELD_NAME
}
if o.ServiceSettings.SessionLengthWebInDays == nil {
@@ -807,7 +872,7 @@ func (o *Config) SetDefaults() {
if o.ServiceSettings.AllowCorsFrom == nil {
o.ServiceSettings.AllowCorsFrom = new(string)
- *o.ServiceSettings.AllowCorsFrom = ""
+ *o.ServiceSettings.AllowCorsFrom = SERVICE_SETTINGS_DEFAULT_ALLOW_CORS_FROM
}
if o.ServiceSettings.WebserverMode == nil {
@@ -827,6 +892,21 @@ func (o *Config) SetDefaults() {
*o.ServiceSettings.RestrictCustomEmojiCreation = RESTRICT_EMOJI_CREATION_ALL
}
+ if o.ServiceSettings.RestrictPostDelete == nil {
+ o.ServiceSettings.RestrictPostDelete = new(string)
+ *o.ServiceSettings.RestrictPostDelete = PERMISSIONS_DELETE_POST_ALL
+ }
+
+ if o.ServiceSettings.AllowEditPost == nil {
+ o.ServiceSettings.AllowEditPost = new(string)
+ *o.ServiceSettings.AllowEditPost = ALLOW_EDIT_POST_ALWAYS
+ }
+
+ if o.ServiceSettings.PostEditTimeLimit == nil {
+ o.ServiceSettings.PostEditTimeLimit = new(int)
+ *o.ServiceSettings.PostEditTimeLimit = 300
+ }
+
if o.ClusterSettings.InterNodeListenAddress == nil {
o.ClusterSettings.InterNodeListenAddress = new(string)
*o.ClusterSettings.InterNodeListenAddress = ":8075"
@@ -853,7 +933,7 @@ func (o *Config) SetDefaults() {
if o.AnalyticsSettings.MaxUsersForStatistics == nil {
o.AnalyticsSettings.MaxUsersForStatistics = new(int)
- *o.AnalyticsSettings.MaxUsersForStatistics = 2500
+ *o.AnalyticsSettings.MaxUsersForStatistics = ANALYTICS_SETTINGS_DEFAULT_MAX_USERS_FOR_STATISTICS
}
if o.ComplianceSettings.Enable == nil {
@@ -943,52 +1023,52 @@ func (o *Config) SetDefaults() {
if o.SamlSettings.FirstNameAttribute == nil {
o.SamlSettings.FirstNameAttribute = new(string)
- *o.SamlSettings.FirstNameAttribute = ""
+ *o.SamlSettings.FirstNameAttribute = SAML_SETTINGS_DEFAULT_FIRST_NAME_ATTRIBUTE
}
if o.SamlSettings.LastNameAttribute == nil {
o.SamlSettings.LastNameAttribute = new(string)
- *o.SamlSettings.LastNameAttribute = ""
+ *o.SamlSettings.LastNameAttribute = SAML_SETTINGS_DEFAULT_LAST_NAME_ATTRIBUTE
}
if o.SamlSettings.EmailAttribute == nil {
o.SamlSettings.EmailAttribute = new(string)
- *o.SamlSettings.EmailAttribute = ""
+ *o.SamlSettings.EmailAttribute = SAML_SETTINGS_DEFAULT_EMAIL_ATTRIBUTE
}
if o.SamlSettings.UsernameAttribute == nil {
o.SamlSettings.UsernameAttribute = new(string)
- *o.SamlSettings.UsernameAttribute = ""
+ *o.SamlSettings.UsernameAttribute = SAML_SETTINGS_DEFAULT_USERNAME_ATTRIBUTE
}
if o.SamlSettings.NicknameAttribute == nil {
o.SamlSettings.NicknameAttribute = new(string)
- *o.SamlSettings.NicknameAttribute = ""
+ *o.SamlSettings.NicknameAttribute = SAML_SETTINGS_DEFAULT_NICKNAME_ATTRIBUTE
}
if o.SamlSettings.PositionAttribute == nil {
o.SamlSettings.PositionAttribute = new(string)
- *o.SamlSettings.PositionAttribute = ""
+ *o.SamlSettings.PositionAttribute = SAML_SETTINGS_DEFAULT_POSITION_ATTRIBUTE
}
if o.SamlSettings.LocaleAttribute == nil {
o.SamlSettings.LocaleAttribute = new(string)
- *o.SamlSettings.LocaleAttribute = ""
+ *o.SamlSettings.LocaleAttribute = SAML_SETTINGS_DEFAULT_LOCALE_ATTRIBUTE
}
if o.NativeAppSettings.AppDownloadLink == nil {
o.NativeAppSettings.AppDownloadLink = new(string)
- *o.NativeAppSettings.AppDownloadLink = "https://about.mattermost.com/downloads/"
+ *o.NativeAppSettings.AppDownloadLink = NATIVEAPP_SETTINGS_DEFAULT_APP_DOWNLOAD_LINK
}
if o.NativeAppSettings.AndroidAppDownloadLink == nil {
o.NativeAppSettings.AndroidAppDownloadLink = new(string)
- *o.NativeAppSettings.AndroidAppDownloadLink = "https://about.mattermost.com/mattermost-android-app/"
+ *o.NativeAppSettings.AndroidAppDownloadLink = NATIVEAPP_SETTINGS_DEFAULT_ANDROID_APP_DOWNLOAD_LINK
}
if o.NativeAppSettings.IosAppDownloadLink == nil {
o.NativeAppSettings.IosAppDownloadLink = new(string)
- *o.NativeAppSettings.IosAppDownloadLink = "https://about.mattermost.com/mattermost-ios-app/"
+ *o.NativeAppSettings.IosAppDownloadLink = NATIVEAPP_SETTINGS_DEFAULT_IOS_APP_DOWNLOAD_LINK
}
if o.RateLimitSettings.Enable == nil {
@@ -1008,12 +1088,12 @@ func (o *Config) SetDefaults() {
if o.ServiceSettings.TLSKeyFile == nil {
o.ServiceSettings.TLSKeyFile = new(string)
- *o.ServiceSettings.TLSKeyFile = ""
+ *o.ServiceSettings.TLSKeyFile = SERVICE_SETTINGS_DEFAULT_TLS_KEY_FILE
}
if o.ServiceSettings.TLSCertFile == nil {
o.ServiceSettings.TLSCertFile = new(string)
- *o.ServiceSettings.TLSCertFile = ""
+ *o.ServiceSettings.TLSCertFile = SERVICE_SETTINGS_DEFAULT_TLS_CERT_FILE
}
if o.ServiceSettings.UseLetsEncrypt == nil {
@@ -1028,12 +1108,12 @@ func (o *Config) SetDefaults() {
if o.ServiceSettings.ReadTimeout == nil {
o.ServiceSettings.ReadTimeout = new(int)
- *o.ServiceSettings.ReadTimeout = 300
+ *o.ServiceSettings.ReadTimeout = SERVICE_SETTINGS_DEFAULT_READ_TIMEOUT
}
if o.ServiceSettings.WriteTimeout == nil {
o.ServiceSettings.WriteTimeout = new(int)
- *o.ServiceSettings.WriteTimeout = 300
+ *o.ServiceSettings.WriteTimeout = SERVICE_SETTINGS_DEFAULT_WRITE_TIMEOUT
}
if o.ServiceSettings.Forward80To443 == nil {
@@ -1046,6 +1126,21 @@ func (o *Config) SetDefaults() {
*o.MetricsSettings.BlockProfileRate = 0
}
+ if o.ServiceSettings.TimeBetweenUserTypingUpdatesMilliseconds == nil {
+ o.ServiceSettings.TimeBetweenUserTypingUpdatesMilliseconds = new(int64)
+ *o.ServiceSettings.TimeBetweenUserTypingUpdatesMilliseconds = 5000
+ }
+
+ if o.ServiceSettings.EnableUserTypingMessages == nil {
+ o.ServiceSettings.EnableUserTypingMessages = new(bool)
+ *o.ServiceSettings.EnableUserTypingMessages = true
+ }
+
+ if o.ServiceSettings.ClusterLogTimeoutMilliseconds == nil {
+ o.ServiceSettings.ClusterLogTimeoutMilliseconds = new(int)
+ *o.ServiceSettings.ClusterLogTimeoutMilliseconds = 2000
+ }
+
o.defaultWebrtcSettings()
}
@@ -1277,6 +1372,10 @@ func (o *Config) IsValid() *AppError {
return NewLocAppError("Config.IsValid", "model.config.is_valid.write_timeout.app_error", nil, "")
}
+ if *o.ServiceSettings.TimeBetweenUserTypingUpdatesMilliseconds < 1000 {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.time_between_user_typing.app_error", nil, "")
+ }
+
return nil
}
@@ -1339,12 +1438,12 @@ func (o *Config) defaultWebrtcSettings() {
if o.WebrtcSettings.StunURI == nil {
o.WebrtcSettings.StunURI = new(string)
- *o.WebrtcSettings.StunURI = ""
+ *o.WebrtcSettings.StunURI = WEBRTC_SETTINGS_DEFAULT_STUN_URI
}
if o.WebrtcSettings.TurnURI == nil {
o.WebrtcSettings.TurnURI = new(string)
- *o.WebrtcSettings.TurnURI = ""
+ *o.WebrtcSettings.TurnURI = WEBRTC_SETTINGS_DEFAULT_TURN_URI
}
if o.WebrtcSettings.TurnUsername == nil {
diff --git a/vendor/github.com/mattermost/platform/model/file.go b/vendor/github.com/mattermost/platform/model/file.go
index c218c424..20f6236d 100644
--- a/vendor/github.com/mattermost/platform/model/file.go
+++ b/vendor/github.com/mattermost/platform/model/file.go
@@ -8,6 +8,10 @@ import (
"io"
)
+const (
+ MaxImageSize = 6048 * 4032 // 24 megapixels, roughly 36MB as a raw image
+)
+
var (
IMAGE_EXTENSIONS = [5]string{".jpg", ".jpeg", ".gif", ".bmp", ".png"}
IMAGE_MIME_TYPES = map[string]string{".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".bmp": "image/bmp", ".png": "image/png", ".tiff": "image/tiff"}
diff --git a/vendor/github.com/mattermost/platform/model/gitlab/gitlab.go b/vendor/github.com/mattermost/platform/model/gitlab/gitlab.go
index e189ee68..270d62d8 100644
--- a/vendor/github.com/mattermost/platform/model/gitlab/gitlab.go
+++ b/vendor/github.com/mattermost/platform/model/gitlab/gitlab.go
@@ -65,6 +65,15 @@ func gitLabUserFromJson(data io.Reader) *GitLabUser {
}
}
+func (glu *GitLabUser) ToJson() string {
+ b, err := json.Marshal(glu)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
func (glu *GitLabUser) IsValid() bool {
if glu.Id == 0 {
return false
diff --git a/vendor/github.com/mattermost/platform/model/incoming_webhook.go b/vendor/github.com/mattermost/platform/model/incoming_webhook.go
index 72fa3e54..2cc26cbc 100644
--- a/vendor/github.com/mattermost/platform/model/incoming_webhook.go
+++ b/vendor/github.com/mattermost/platform/model/incoming_webhook.go
@@ -29,13 +29,13 @@ type IncomingWebhook struct {
}
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 interface{} `json:"attachments"`
- Type string `json:"type"`
+ 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"`
}
func (o *IncomingWebhook) ToJson() string {
@@ -212,31 +212,15 @@ func expandAnnouncement(text string) string {
func expandAnnouncements(i *IncomingWebhookRequest) {
i.Text = expandAnnouncement(i.Text)
- if i.Attachments != nil {
- attachments := i.Attachments.([]interface{})
- for _, attachment := range attachments {
- a := attachment.(map[string]interface{})
+ for _, attachment := range i.Attachments {
+ attachment.Pretext = expandAnnouncement(attachment.Pretext)
+ attachment.Text = expandAnnouncement(attachment.Text)
+ attachment.Title = expandAnnouncement(attachment.Title)
- if a["pretext"] != nil {
- a["pretext"] = expandAnnouncement(a["pretext"].(string))
- }
-
- if a["text"] != nil {
- a["text"] = expandAnnouncement(a["text"].(string))
- }
-
- if a["title"] != nil {
- a["title"] = expandAnnouncement(a["title"].(string))
- }
-
- if a["fields"] != nil {
- fields := a["fields"].([]interface{})
- for _, field := range fields {
- f := field.(map[string]interface{})
- if f["value"] != nil {
- f["value"] = expandAnnouncement(fmt.Sprintf("%v", f["value"]))
- }
- }
+ for _, field := range attachment.Fields {
+ if field.Value != nil {
+ // Ensure the value is set to a string if it is set
+ field.Value = expandAnnouncement(fmt.Sprintf("%v", field.Value))
}
}
}
diff --git a/vendor/github.com/mattermost/platform/model/job.go b/vendor/github.com/mattermost/platform/model/job.go
index 229d5efd..09d74aa0 100644
--- a/vendor/github.com/mattermost/platform/model/job.go
+++ b/vendor/github.com/mattermost/platform/model/job.go
@@ -14,8 +14,8 @@ type ScheduledTask struct {
Name string `json:"name"`
Interval time.Duration `json:"interval"`
Recurring bool `json:"recurring"`
- function TaskFunc `json:",omitempty"`
- timer *time.Timer `json:",omitempty"`
+ function TaskFunc
+ timer *time.Timer
}
var tasks = make(map[string]*ScheduledTask)
diff --git a/vendor/github.com/mattermost/platform/model/license.go b/vendor/github.com/mattermost/platform/model/license.go
index 7115aa1a..09da61eb 100644
--- a/vendor/github.com/mattermost/platform/model/license.go
+++ b/vendor/github.com/mattermost/platform/model/license.go
@@ -8,6 +8,11 @@ import (
"io"
)
+const (
+ EXPIRED_LICENSE_ERROR = "api.license.add_license.expired.app_error"
+ INVALID_LICENSE_ERROR = "api.license.add_license.invalid.app_error"
+)
+
type LicenseRecord struct {
Id string `json:"id"`
CreateAt int64 `json:"create_at"`
diff --git a/vendor/github.com/mattermost/platform/model/post.go b/vendor/github.com/mattermost/platform/model/post.go
index 7097e031..a7729e0c 100644
--- a/vendor/github.com/mattermost/platform/model/post.go
+++ b/vendor/github.com/mattermost/platform/model/post.go
@@ -14,10 +14,15 @@ const (
POST_DEFAULT = ""
POST_SLACK_ATTACHMENT = "slack_attachment"
POST_SYSTEM_GENERIC = "system_generic"
- POST_JOIN_LEAVE = "system_join_leave"
- POST_ADD_REMOVE = "system_add_remove"
+ POST_JOIN_LEAVE = "system_join_leave" // Deprecated, use POST_JOIN_CHANNEL or POST_LEAVE_CHANNEL instead
+ POST_JOIN_CHANNEL = "system_join_channel"
+ POST_LEAVE_CHANNEL = "system_leave_channel"
+ 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_REMOVE_FROM_CHANNEL = "system_remove_from_channel"
POST_HEADER_CHANGE = "system_header_change"
POST_DISPLAYNAME_CHANGE = "system_displayname_change"
+ POST_PURPOSE_CHANGE = "system_purpose_change"
POST_CHANNEL_DELETED = "system_channel_deleted"
POST_EPHEMERAL = "system_ephemeral"
POST_FILEIDS_MAX_RUNES = 150
@@ -31,6 +36,7 @@ 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"`
UserId string `json:"user_id"`
ChannelId string `json:"channel_id"`
@@ -119,7 +125,9 @@ func (o *Post) IsValid() *AppError {
// should be removed once more message types are supported
if !(o.Type == POST_DEFAULT || o.Type == POST_JOIN_LEAVE || o.Type == POST_ADD_REMOVE ||
- o.Type == POST_SLACK_ATTACHMENT || o.Type == POST_HEADER_CHANGE ||
+ o.Type == POST_JOIN_CHANNEL || o.Type == POST_LEAVE_CHANNEL ||
+ o.Type == POST_REMOVE_FROM_CHANNEL || o.Type == POST_ADD_TO_CHANNEL ||
+ o.Type == POST_SLACK_ATTACHMENT || o.Type == POST_HEADER_CHANGE || o.Type == POST_PURPOSE_CHANGE ||
o.Type == POST_DISPLAYNAME_CHANGE || o.Type == POST_CHANNEL_DELETED) {
return NewLocAppError("Post.IsValid", "model.post.is_valid.type.app_error", nil, "id="+o.Type)
}
diff --git a/vendor/github.com/mattermost/platform/model/post_list.go b/vendor/github.com/mattermost/platform/model/post_list.go
index 4c0f5408..9b56f023 100644
--- a/vendor/github.com/mattermost/platform/model/post_list.go
+++ b/vendor/github.com/mattermost/platform/model/post_list.go
@@ -13,6 +13,13 @@ type PostList struct {
Posts map[string]*Post `json:"posts"`
}
+func NewPostList() *PostList {
+ return &PostList{
+ Order: make([]string, 0),
+ Posts: make(map[string]*Post),
+ }
+}
+
func (o *PostList) ToJson() string {
b, err := json.Marshal(o)
if err != nil {
@@ -72,10 +79,18 @@ func (o *PostList) Etag() string {
if v.UpdateAt > t {
t = v.UpdateAt
id = v.Id
+ } else if v.UpdateAt == t && v.Id > id {
+ t = v.UpdateAt
+ id = v.Id
}
}
- return Etag(id, t)
+ orderId := ""
+ if len(o.Order) > 0 {
+ orderId = o.Order[0]
+ }
+
+ return Etag(orderId, id, t)
}
func (o *PostList) IsChannelId(channelId string) bool {
diff --git a/vendor/github.com/mattermost/platform/model/push_notification.go b/vendor/github.com/mattermost/platform/model/push_notification.go
index 3c010fb7..753495b2 100644
--- a/vendor/github.com/mattermost/platform/model/push_notification.go
+++ b/vendor/github.com/mattermost/platform/model/push_notification.go
@@ -10,8 +10,10 @@ import (
)
const (
- PUSH_NOTIFY_APPLE = "apple"
- PUSH_NOTIFY_ANDROID = "android"
+ 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"
@@ -46,12 +48,12 @@ func (me *PushNotification) ToJson() string {
}
func (me *PushNotification) SetDeviceIdAndPlatform(deviceId string) {
- if strings.HasPrefix(deviceId, PUSH_NOTIFY_APPLE+":") {
- me.Platform = PUSH_NOTIFY_APPLE
- me.DeviceId = strings.TrimPrefix(deviceId, PUSH_NOTIFY_APPLE+":")
- } else if strings.HasPrefix(deviceId, PUSH_NOTIFY_ANDROID+":") {
- me.Platform = PUSH_NOTIFY_ANDROID
- me.DeviceId = strings.TrimPrefix(deviceId, PUSH_NOTIFY_ANDROID+":")
+
+ index := strings.Index(deviceId, ":")
+
+ if index > -1 {
+ me.Platform = deviceId[:index]
+ me.DeviceId = deviceId[index+1:]
}
}
diff --git a/vendor/github.com/mattermost/platform/model/push_response.go b/vendor/github.com/mattermost/platform/model/push_response.go
new file mode 100644
index 00000000..0271bc94
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/push_response.go
@@ -0,0 +1,57 @@
+// Copyright (c) 2015 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 (me *PushResponse) ToJson() string {
+ if b, err := json.Marshal(me); err != nil {
+ return ""
+ } else {
+ 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)
+ } else {
+ return objmap
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/session.go b/vendor/github.com/mattermost/platform/model/session.go
index a6a753e7..277e910f 100644
--- a/vendor/github.com/mattermost/platform/model/session.go
+++ b/vendor/github.com/mattermost/platform/model/session.go
@@ -11,7 +11,7 @@ import (
const (
SESSION_COOKIE_TOKEN = "MMAUTHTOKEN"
- SESSION_CACHE_SIZE = 25000
+ SESSION_CACHE_SIZE = 35000
SESSION_PROP_PLATFORM = "platform"
SESSION_PROP_OS = "os"
SESSION_PROP_BROWSER = "browser"
@@ -111,8 +111,7 @@ func (me *Session) GetTeamByTeamId(teamId string) *TeamMember {
}
func (me *Session) IsMobileApp() bool {
- return len(me.DeviceId) > 0 &&
- (strings.HasPrefix(me.DeviceId, PUSH_NOTIFY_APPLE+":") || strings.HasPrefix(me.DeviceId, PUSH_NOTIFY_ANDROID+":"))
+ return len(me.DeviceId) > 0
}
func (me *Session) GetUserRoles() []string {
diff --git a/vendor/github.com/mattermost/platform/model/slack_attachment.go b/vendor/github.com/mattermost/platform/model/slack_attachment.go
new file mode 100644
index 00000000..e1639f2a
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/slack_attachment.go
@@ -0,0 +1,29 @@
+// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+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
+}
+
+type SlackAttachmentField struct {
+ Title string `json:"title"`
+ Value interface{} `json:"value"`
+ Short bool `json:"short"`
+}
diff --git a/vendor/github.com/mattermost/platform/model/status.go b/vendor/github.com/mattermost/platform/model/status.go
index fec3a5f7..fc155788 100644
--- a/vendor/github.com/mattermost/platform/model/status.go
+++ b/vendor/github.com/mattermost/platform/model/status.go
@@ -12,7 +12,7 @@ const (
STATUS_OFFLINE = "offline"
STATUS_AWAY = "away"
STATUS_ONLINE = "online"
- STATUS_CACHE_SIZE = 25000
+ STATUS_CACHE_SIZE = SESSION_CACHE_SIZE
STATUS_CHANNEL_TIMEOUT = 20000 // 20 seconds
STATUS_MIN_UPDATE_TIME = 120000 // 2 minutes
)
diff --git a/vendor/github.com/mattermost/platform/model/team.go b/vendor/github.com/mattermost/platform/model/team.go
index 3f05ce83..99444bc5 100644
--- a/vendor/github.com/mattermost/platform/model/team.go
+++ b/vendor/github.com/mattermost/platform/model/team.go
@@ -7,14 +7,22 @@ import (
"encoding/json"
"fmt"
"io"
+ "net/http"
"regexp"
"strings"
"unicode/utf8"
)
const (
- TEAM_OPEN = "O"
- TEAM_INVITE = "I"
+ 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 {
@@ -48,6 +56,14 @@ func InvitesFromJson(data io.Reader) *Invites {
}
}
+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, err := json.Marshal(o)
if err != nil {
@@ -97,6 +113,26 @@ func TeamMapFromJson(data io.Reader) map[string]*Team {
}
}
+func TeamListToJson(t []*Team) string {
+ b, err := json.Marshal(t)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func TeamListFromJson(data io.Reader) []*Team {
+ decoder := json.NewDecoder(data)
+ var teams []*Team
+ err := decoder.Decode(&teams)
+ if err == nil {
+ return teams
+ } else {
+ return nil
+ }
+}
+
func (o *Team) Etag() string {
return Etag(o.Id, o.UpdateAt)
}
@@ -104,55 +140,55 @@ func (o *Team) Etag() string {
func (o *Team) IsValid() *AppError {
if len(o.Id) != 26 {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.id.app_error", nil, "")
+ return NewAppError("Team.IsValid", "model.team.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
if o.CreateAt == 0 {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.create_at.app_error", nil, "id="+o.Id)
+ return NewAppError("Team.IsValid", "model.team.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if o.UpdateAt == 0 {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.update_at.app_error", nil, "id="+o.Id)
+ return NewAppError("Team.IsValid", "model.team.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
- if len(o.Email) > 128 {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.email.app_error", nil, "id="+o.Id)
+ 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 len(o.Email) > 0 && !IsValidEmail(o.Email) {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.email.app_error", nil, "id="+o.Id)
+ 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) > 64 {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.name.app_error", nil, "id="+o.Id)
+ 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) > 64 {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.url.app_error", nil, "id="+o.Id)
+ 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) > 255 {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.description.app_error", nil, "id="+o.Id)
+ 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 IsReservedTeamName(o.Name) {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.reserved.app_error", nil, "id="+o.Id)
+ return NewAppError("Team.IsValid", "model.team.is_valid.reserved.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if !IsValidTeamName(o.Name) {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.characters.app_error", nil, "id="+o.Id)
+ 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 NewLocAppError("Team.IsValid", "model.team.is_valid.type.app_error", nil, "id="+o.Id)
+ return NewAppError("Team.IsValid", "model.team.is_valid.type.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
- if len(o.CompanyName) > 64 {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.company.app_error", nil, "id="+o.Id)
+ 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) > 500 {
- return NewLocAppError("Team.IsValid", "model.team.is_valid.domains.app_error", nil, "id="+o.Id)
+ 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
@@ -193,7 +229,7 @@ func IsValidTeamName(s string) bool {
return false
}
- if len(s) <= 1 {
+ if len(s) < TEAM_NAME_MIN_LENGTH {
return false
}
diff --git a/vendor/github.com/mattermost/platform/model/user.go b/vendor/github.com/mattermost/platform/model/user.go
index 76c3772c..d62ccccd 100644
--- a/vendor/github.com/mattermost/platform/model/user.go
+++ b/vendor/github.com/mattermost/platform/model/user.go
@@ -7,20 +7,36 @@ import (
"encoding/json"
"fmt"
"io"
+ "net/http"
"regexp"
"strings"
+ "unicode"
"unicode/utf8"
"golang.org/x/crypto/bcrypt"
)
const (
- USER_NOTIFY_ALL = "all"
- USER_NOTIFY_MENTION = "mention"
- USER_NOTIFY_NONE = "none"
+ USER_NOTIFY_ALL = "all"
+ USER_NOTIFY_MENTION = "mention"
+ USER_NOTIFY_NONE = "none"
+ DESKTOP_NOTIFY_PROP = "desktop"
+ MARK_UNREAD_NOTIFY_PROP = "mark_unread"
+ PUSH_NOTIFY_PROP = "push"
+ EMAIL_NOTIFY_PROP = "email"
+
DEFAULT_LOCALE = "en"
USER_AUTH_SERVICE_EMAIL = "email"
USER_AUTH_SERVICE_USERNAME = "username"
+
+ USER_EMAIL_MAX_LENGTH = 128
+ USER_NICKNAME_MAX_RUNES = 64
+ USER_POSITION_MAX_RUNES = 35
+ 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
)
type User struct {
@@ -51,56 +67,68 @@ type User struct {
LastActivityAt int64 `db:"-" json:"last_activity_at,omitempty"`
}
+type UserPatch struct {
+ Username *string `json:"username"`
+ 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"`
+}
+
// IsValid validates the user and returns an error if it isn't configured
// correctly.
func (u *User) IsValid() *AppError {
if len(u.Id) != 26 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.id.app_error", nil, "")
+ return NewAppError("User.IsValid", "model.user.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
if u.CreateAt == 0 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.create_at.app_error", nil, "user_id="+u.Id)
+ return NewAppError("User.IsValid", "model.user.is_valid.create_at.app_error", nil, "user_id="+u.Id, http.StatusBadRequest)
}
if u.UpdateAt == 0 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.update_at.app_error", nil, "user_id="+u.Id)
+ return NewAppError("User.IsValid", "model.user.is_valid.update_at.app_error", nil, "user_id="+u.Id, http.StatusBadRequest)
}
if !IsValidUsername(u.Username) {
- return NewLocAppError("User.IsValid", "model.user.is_valid.username.app_error", nil, "user_id="+u.Id)
+ return NewAppError("User.IsValid", "model.user.is_valid.username.app_error", nil, "user_id="+u.Id, http.StatusBadRequest)
}
- if len(u.Email) > 128 || len(u.Email) == 0 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.email.app_error", nil, "user_id="+u.Id)
+ if len(u.Email) > USER_EMAIL_MAX_LENGTH || len(u.Email) == 0 {
+ return NewAppError("User.IsValid", "model.user.is_valid.email.app_error", nil, "user_id="+u.Id, http.StatusBadRequest)
}
- if utf8.RuneCountInString(u.Nickname) > 64 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.nickname.app_error", nil, "user_id="+u.Id)
+ if utf8.RuneCountInString(u.Nickname) > USER_NICKNAME_MAX_RUNES {
+ return NewAppError("User.IsValid", "model.user.is_valid.nickname.app_error", nil, "user_id="+u.Id, http.StatusBadRequest)
}
- if utf8.RuneCountInString(u.Position) > 35 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.position.app_error", nil, "user_id="+u.Id)
+ if utf8.RuneCountInString(u.Position) > USER_POSITION_MAX_RUNES {
+ return NewAppError("User.IsValid", "model.user.is_valid.position.app_error", nil, "user_id="+u.Id, http.StatusBadRequest)
}
- if utf8.RuneCountInString(u.FirstName) > 64 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.first_name.app_error", nil, "user_id="+u.Id)
+ if utf8.RuneCountInString(u.FirstName) > USER_FIRST_NAME_MAX_RUNES {
+ return NewAppError("User.IsValid", "model.user.is_valid.first_name.app_error", nil, "user_id="+u.Id, http.StatusBadRequest)
}
- if utf8.RuneCountInString(u.LastName) > 64 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.last_name.app_error", nil, "user_id="+u.Id)
+ if utf8.RuneCountInString(u.LastName) > USER_LAST_NAME_MAX_RUNES {
+ return NewAppError("User.IsValid", "model.user.is_valid.last_name.app_error", nil, "user_id="+u.Id, http.StatusBadRequest)
}
- if u.AuthData != nil && len(*u.AuthData) > 128 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.auth_data.app_error", nil, "user_id="+u.Id)
+ if u.AuthData != nil && len(*u.AuthData) > USER_AUTH_DATA_MAX_LENGTH {
+ return NewAppError("User.IsValid", "model.user.is_valid.auth_data.app_error", nil, "user_id="+u.Id, http.StatusBadRequest)
}
if u.AuthData != nil && len(*u.AuthData) > 0 && len(u.AuthService) == 0 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.auth_data_type.app_error", nil, "user_id="+u.Id)
+ return NewAppError("User.IsValid", "model.user.is_valid.auth_data_type.app_error", nil, "user_id="+u.Id, http.StatusBadRequest)
}
if len(u.Password) > 0 && u.AuthData != nil && len(*u.AuthData) > 0 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.auth_data_pwd.app_error", nil, "user_id="+u.Id)
+ return NewAppError("User.IsValid", "model.user.is_valid.auth_data_pwd.app_error", nil, "user_id="+u.Id, http.StatusBadRequest)
}
return nil
@@ -115,7 +143,7 @@ func (u *User) PreSave() {
}
if u.Username == "" {
- u.Username = NewId()
+ u.Username = "n" + NewId()
}
if u.AuthData != nil && *u.AuthData == "" {
@@ -205,6 +233,44 @@ func (user *User) UpdateMentionKeysFromUsername(oldUsername string) {
}
}
+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
+ }
+}
+
// ToJson convert a User to a json string
func (u *User) ToJson() string {
b, err := json.Marshal(u)
@@ -215,6 +281,15 @@ func (u *User) ToJson() string {
}
}
+func (u *UserPatch) ToJson() string {
+ b, err := json.Marshal(u)
+ if err != nil {
+ return ""
+ } else {
+ 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, showFullName, showEmail)
@@ -376,6 +451,13 @@ func IsInRole(userRoles string, inRole string) bool {
return false
}
+func (u *User) IsSSOUser() bool {
+ if u.AuthService != "" && u.AuthService != USER_AUTH_SERVICE_EMAIL {
+ return true
+ }
+ return false
+}
+
func (u *User) IsOAuthUser() bool {
if u.AuthService == USER_AUTH_SERVICE_GITLAB {
return true
@@ -402,6 +484,17 @@ func UserFromJson(data io.Reader) *User {
}
}
+func UserPatchFromJson(data io.Reader) *UserPatch {
+ decoder := json.NewDecoder(data)
+ var user UserPatch
+ err := decoder.Decode(&user)
+ if err == nil {
+ return &user
+ } else {
+ return nil
+ }
+}
+
func UserMapToJson(u map[string]*User) string {
b, err := json.Marshal(u)
if err != nil {
@@ -472,7 +565,7 @@ var restrictedUsernames = []string{
}
func IsValidUsername(s string) bool {
- if len(s) == 0 || len(s) > 64 {
+ if len(s) < USER_NAME_MIN_LENGTH || len(s) > USER_NAME_MAX_LENGTH {
return false
}
@@ -480,6 +573,10 @@ func IsValidUsername(s string) bool {
return false
}
+ if !unicode.IsLetter(rune(s[0])) {
+ return false
+ }
+
for _, restrictedUsername := range restrictedUsernames {
if s == restrictedUsername {
return false
diff --git a/vendor/github.com/mattermost/platform/model/utils.go b/vendor/github.com/mattermost/platform/model/utils.go
index 0ce243fe..08809a47 100644
--- a/vendor/github.com/mattermost/platform/model/utils.go
+++ b/vendor/github.com/mattermost/platform/model/utils.go
@@ -34,14 +34,14 @@ type StringArray []string
type EncryptStringMap map[string]string
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{} `json:"-"`
+ 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 {
@@ -93,6 +93,18 @@ func AppErrorFromJson(data io.Reader) *AppError {
}
}
+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
+ return ap
+}
+
func NewLocAppError(where string, id string, params map[string]interface{}, details string) *AppError {
ap := &AppError{}
ap.Id = id
@@ -268,7 +280,7 @@ func IsValidChannelIdentifier(s string) bool {
return false
}
- if len(s) < 2 {
+ if len(s) < CHANNEL_NAME_MIN_LENGTH {
return false
}
@@ -370,7 +382,7 @@ func ClearMentionTags(post string) string {
var UrlRegex = regexp.MustCompile(`^((?:[a-z]+:\/\/)?(?:(?:[a-z0-9\-]+\.)+(?:[a-z]{2}|aero|arpa|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|local|internal))(:[0-9]{1,5})?(?:\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(?:\?[a-z0-9+_~\-\.%=&amp;]*)?)?(?:#[a-zA-Z0-9!$&'()*+.=-_~:@/?]*)?)(?:\s+|$)$`)
var PartialUrlRegex = regexp.MustCompile(`/([A-Za-z0-9]{26})/([A-Za-z0-9]{26})/((?:[A-Za-z0-9]{26})?.+(?:\.[A-Za-z0-9]{3,})?)`)
-var SplitRunes = map[rune]bool{',': true, ' ': true, '.': true, '!': true, '?': true, ':': true, ';': true, '\n': true, '<': true, '>': true, '(': true, ')': true, '{': true, '}': true, '[': true, ']': true, '+': true, '/': true, '\\': true}
+var SplitRunes = map[rune]bool{',': true, ' ': true, '.': true, '!': true, '?': true, ':': true, ';': true, '\n': true, '<': true, '>': true, '(': true, ')': true, '{': true, '}': true, '[': true, ']': true, '+': true, '/': true, '\\': true, '^': true, '#': true, '$': true, '&': true}
func IsValidHttpUrl(rawUrl string) bool {
if strings.Index(rawUrl, "http://") != 0 && strings.Index(rawUrl, "https://") != 0 {
diff --git a/vendor/github.com/mattermost/platform/model/version.go b/vendor/github.com/mattermost/platform/model/version.go
index 2a034dec..32b1c3f5 100644
--- a/vendor/github.com/mattermost/platform/model/version.go
+++ b/vendor/github.com/mattermost/platform/model/version.go
@@ -13,6 +13,7 @@ import (
// It should be maitained in chronological order with most current
// release at the front of the list.
var versions = []string{
+ "3.7.0",
"3.6.0",
"3.5.0",
"3.4.0",
diff --git a/vendor/github.com/mattermost/platform/model/websocket_client.go b/vendor/github.com/mattermost/platform/model/websocket_client.go
index 453ae49b..083fe110 100644
--- a/vendor/github.com/mattermost/platform/model/websocket_client.go
+++ b/vendor/github.com/mattermost/platform/model/websocket_client.go
@@ -8,6 +8,10 @@ import (
"github.com/gorilla/websocket"
)
+const (
+ SOCKET_MAX_MESSAGE_SIZE_KB = 8 * 1024 // 8KB
+)
+
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"
@@ -22,14 +26,14 @@ type WebSocketClient struct {
// NewWebSocketClient constructs a new WebSocket client with convienence
// methods for talking to the server.
func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
- conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX+"/users/websocket", nil)
+ conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX_V3+"/users/websocket", nil)
if err != nil {
return nil, NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
}
client := &WebSocketClient{
url,
- url + API_URL_SUFFIX,
+ url + API_URL_SUFFIX_V3,
conn,
authToken,
1,
diff --git a/vendor/github.com/mattermost/platform/model/websocket_message.go b/vendor/github.com/mattermost/platform/model/websocket_message.go
index 5c956d57..23820470 100644
--- a/vendor/github.com/mattermost/platform/model/websocket_message.go
+++ b/vendor/github.com/mattermost/platform/model/websocket_message.go
@@ -14,8 +14,9 @@ const (
WEBSOCKET_EVENT_POST_EDITED = "post_edited"
WEBSOCKET_EVENT_POST_DELETED = "post_deleted"
WEBSOCKET_EVENT_CHANNEL_DELETED = "channel_deleted"
- WEBSOCKET_EVENT_CHANNEL_VIEWED = "channel_viewed"
+ WEBSOCKET_EVENT_CHANNEL_CREATED = "channel_created"
WEBSOCKET_EVENT_DIRECT_ADDED = "direct_added"
+ WEBSOCKET_EVENT_GROUP_ADDED = "group_added"
WEBSOCKET_EVENT_NEW_USER = "new_user"
WEBSOCKET_EVENT_LEAVE_TEAM = "leave_team"
WEBSOCKET_EVENT_UPDATE_TEAM = "update_team"