summaryrefslogtreecommitdiffstats
path: root/vendor/github.com
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/mattermost/platform/einterfaces/cluster.go1
-rw-r--r--vendor/github.com/mattermost/platform/einterfaces/mfa.go2
-rw-r--r--vendor/github.com/mattermost/platform/model/authorization.go372
-rw-r--r--vendor/github.com/mattermost/platform/model/autocomplete.go58
-rw-r--r--vendor/github.com/mattermost/platform/model/channel.go24
-rw-r--r--vendor/github.com/mattermost/platform/model/channel_extra.go49
-rw-r--r--vendor/github.com/mattermost/platform/model/channel_list.go35
-rw-r--r--vendor/github.com/mattermost/platform/model/channel_member.go32
-rw-r--r--vendor/github.com/mattermost/platform/model/channel_stats.go34
-rw-r--r--vendor/github.com/mattermost/platform/model/client.go334
-rw-r--r--vendor/github.com/mattermost/platform/model/compliance_post.go6
-rw-r--r--vendor/github.com/mattermost/platform/model/config.go248
-rw-r--r--vendor/github.com/mattermost/platform/model/file.go4
-rw-r--r--vendor/github.com/mattermost/platform/model/file_info.go173
-rw-r--r--vendor/github.com/mattermost/platform/model/initial_load.go15
-rw-r--r--vendor/github.com/mattermost/platform/model/license.go3
-rw-r--r--vendor/github.com/mattermost/platform/model/post.go14
-rw-r--r--vendor/github.com/mattermost/platform/model/session.go6
-rw-r--r--vendor/github.com/mattermost/platform/model/status.go5
-rw-r--r--vendor/github.com/mattermost/platform/model/team.go6
-rw-r--r--vendor/github.com/mattermost/platform/model/team_member.go59
-rw-r--r--vendor/github.com/mattermost/platform/model/team_stats.go35
-rw-r--r--vendor/github.com/mattermost/platform/model/user.go54
-rw-r--r--vendor/github.com/mattermost/platform/model/user_search.go39
-rw-r--r--vendor/github.com/mattermost/platform/model/utils.go101
-rw-r--r--vendor/github.com/mattermost/platform/model/version.go1
-rw-r--r--vendor/github.com/mattermost/platform/model/webrtc.go21
-rw-r--r--vendor/github.com/mattermost/platform/model/websocket_client.go45
-rw-r--r--vendor/github.com/mattermost/platform/model/websocket_message.go60
29 files changed, 1439 insertions, 397 deletions
diff --git a/vendor/github.com/mattermost/platform/einterfaces/cluster.go b/vendor/github.com/mattermost/platform/einterfaces/cluster.go
index 921576ad..6b439539 100644
--- a/vendor/github.com/mattermost/platform/einterfaces/cluster.go
+++ b/vendor/github.com/mattermost/platform/einterfaces/cluster.go
@@ -13,7 +13,6 @@ type ClusterInterface interface {
GetClusterInfos() []*model.ClusterInfo
RemoveAllSessionsForUserId(userId string)
InvalidateCacheForUser(userId string)
- InvalidateCacheForChannel(channelId string)
Publish(event *model.WebSocketEvent)
UpdateStatus(status *model.Status)
GetLogs() ([]string, *model.AppError)
diff --git a/vendor/github.com/mattermost/platform/einterfaces/mfa.go b/vendor/github.com/mattermost/platform/einterfaces/mfa.go
index 25f3ed91..4830d261 100644
--- a/vendor/github.com/mattermost/platform/einterfaces/mfa.go
+++ b/vendor/github.com/mattermost/platform/einterfaces/mfa.go
@@ -8,7 +8,7 @@ import (
)
type MfaInterface interface {
- GenerateQrCode(user *model.User) ([]byte, *model.AppError)
+ GenerateSecret(user *model.User) (string, []byte, *model.AppError)
Activate(user *model.User, token string) *model.AppError
Deactivate(userId string) *model.AppError
ValidateToken(secret, token string) (bool, *model.AppError)
diff --git a/vendor/github.com/mattermost/platform/model/authorization.go b/vendor/github.com/mattermost/platform/model/authorization.go
new file mode 100644
index 00000000..75aebf55
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/authorization.go
@@ -0,0 +1,372 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+type Permission struct {
+ Id string `json:"id"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+}
+
+type Role struct {
+ Id string `json:"id"`
+ Name string `json:"name"`
+ Description string `json:"description"`
+ Permissions []string `json:"permissions"`
+}
+
+var PERMISSION_INVITE_USER *Permission
+var PERMISSION_ADD_USER_TO_TEAM *Permission
+var PERMISSION_USE_SLASH_COMMANDS *Permission
+var PERMISSION_MANAGE_SLASH_COMMANDS *Permission
+var PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS *Permission
+var PERMISSION_CREATE_PUBLIC_CHANNEL *Permission
+var PERMISSION_CREATE_PRIVATE_CHANNEL *Permission
+var PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS *Permission
+var PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS *Permission
+var PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE *Permission
+var PERMISSION_MANAGE_ROLES *Permission
+var PERMISSION_CREATE_DIRECT_CHANNEL *Permission
+var PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES *Permission
+var PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES *Permission
+var PERMISSION_LIST_TEAM_CHANNELS *Permission
+var PERMISSION_JOIN_PUBLIC_CHANNELS *Permission
+var PERMISSION_DELETE_PUBLIC_CHANNEL *Permission
+var PERMISSION_DELETE_PRIVATE_CHANNEL *Permission
+var PERMISSION_EDIT_OTHER_USERS *Permission
+var PERMISSION_READ_CHANNEL *Permission
+var PERMISSION_PERMANENT_DELETE_USER *Permission
+var PERMISSION_UPLOAD_FILE *Permission
+var PERMISSION_GET_PUBLIC_LINK *Permission
+var PERMISSION_MANAGE_WEBHOOKS *Permission
+var PERMISSION_MANAGE_OTHERS_WEBHOOKS *Permission
+var PERMISSION_MANAGE_OAUTH *Permission
+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_REMOVE_USER_FROM_TEAM *Permission
+var PERMISSION_MANAGE_TEAM *Permission
+var PERMISSION_IMPORT_TEAM *Permission
+
+// General permission that encompases all system admin functions
+// in the future this could be broken up to allow access to some
+// admin functions but not others
+var PERMISSION_MANAGE_SYSTEM *Permission
+
+var ROLE_SYSTEM_USER *Role
+var ROLE_SYSTEM_ADMIN *Role
+
+var ROLE_TEAM_USER *Role
+var ROLE_TEAM_ADMIN *Role
+
+var ROLE_CHANNEL_USER *Role
+var ROLE_CHANNEL_ADMIN *Role
+var ROLE_CHANNEL_GUEST *Role
+
+var BuiltInRoles map[string]*Role
+
+func InitalizePermissions() {
+ PERMISSION_INVITE_USER = &Permission{
+ "invite_user",
+ "authentication.permissions.team_invite_user.name",
+ "authentication.permissions.team_invite_user.description",
+ }
+ PERMISSION_ADD_USER_TO_TEAM = &Permission{
+ "add_user_to_team",
+ "authentication.permissions.add_user_to_team.name",
+ "authentication.permissions.add_user_to_team.description",
+ }
+ PERMISSION_USE_SLASH_COMMANDS = &Permission{
+ "use_slash_commands",
+ "authentication.permissions.team_use_slash_commands.name",
+ "authentication.permissions.team_use_slash_commands.description",
+ }
+ PERMISSION_MANAGE_SLASH_COMMANDS = &Permission{
+ "manage_slash_commands",
+ "authentication.permissions.manage_slash_commands.name",
+ "authentication.permissions.manage_slash_commands.description",
+ }
+ PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS = &Permission{
+ "manage_others_slash_commands",
+ "authentication.permissions.manage_others_slash_commands.name",
+ "authentication.permissions.manage_others_slash_commands.description",
+ }
+ PERMISSION_CREATE_PUBLIC_CHANNEL = &Permission{
+ "create_public_channel",
+ "authentication.permissions.create_public_channel.name",
+ "authentication.permissions.create_public_channel.description",
+ }
+ PERMISSION_CREATE_PRIVATE_CHANNEL = &Permission{
+ "create_private_channel",
+ "authentication.permissions.create_private_channel.name",
+ "authentication.permissions.create_private_channel.description",
+ }
+ PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS = &Permission{
+ "manage_public_channel_members",
+ "authentication.permissions.manage_public_channel_members.name",
+ "authentication.permissions.manage_public_channel_members.description",
+ }
+ PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS = &Permission{
+ "manage_private_channel_members",
+ "authentication.permissions.manage_private_channel_members.name",
+ "authentication.permissions.manage_private_channel_members.description",
+ }
+ PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE = &Permission{
+ "assign_system_admin_role",
+ "authentication.permissions.assign_system_admin_role.name",
+ "authentication.permissions.assign_system_admin_role.description",
+ }
+ PERMISSION_MANAGE_ROLES = &Permission{
+ "manage_roles",
+ "authentication.permissions.manage_roles.name",
+ "authentication.permissions.manage_roles.description",
+ }
+ PERMISSION_MANAGE_SYSTEM = &Permission{
+ "manage_system",
+ "authentication.permissions.manage_system.name",
+ "authentication.permissions.manage_system.description",
+ }
+ PERMISSION_CREATE_DIRECT_CHANNEL = &Permission{
+ "create_direct_channel",
+ "authentication.permissions.create_direct_channel.name",
+ "authentication.permissions.create_direct_channel.description",
+ }
+ PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES = &Permission{
+ "manage__publicchannel_properties",
+ "authentication.permissions.manage_public_channel_properties.name",
+ "authentication.permissions.manage_public_channel_properties.description",
+ }
+ PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES = &Permission{
+ "manage_private_channel_properties",
+ "authentication.permissions.manage_private_channel_properties.name",
+ "authentication.permissions.manage_private_channel_properties.description",
+ }
+ PERMISSION_LIST_TEAM_CHANNELS = &Permission{
+ "list_team_channels",
+ "authentication.permissions.list_team_channels.name",
+ "authentication.permissions.list_team_channels.description",
+ }
+ PERMISSION_JOIN_PUBLIC_CHANNELS = &Permission{
+ "join_public_channels",
+ "authentication.permissions.join_public_channels.name",
+ "authentication.permissions.join_public_channels.description",
+ }
+ PERMISSION_DELETE_PUBLIC_CHANNEL = &Permission{
+ "delete_public_channel",
+ "authentication.permissions.delete_public_channel.name",
+ "authentication.permissions.delete_public_channel.description",
+ }
+ PERMISSION_DELETE_PRIVATE_CHANNEL = &Permission{
+ "delete_private_channel",
+ "authentication.permissions.delete_private_channel.name",
+ "authentication.permissions.delete_private_channel.description",
+ }
+ PERMISSION_EDIT_OTHER_USERS = &Permission{
+ "edit_other_users",
+ "authentication.permissions.edit_other_users.name",
+ "authentication.permissions.edit_other_users.description",
+ }
+ PERMISSION_READ_CHANNEL = &Permission{
+ "read_channel",
+ "authentication.permissions.read_channel.name",
+ "authentication.permissions.read_channel.description",
+ }
+ PERMISSION_PERMANENT_DELETE_USER = &Permission{
+ "permanent_delete_user",
+ "authentication.permissions.permanent_delete_user.name",
+ "authentication.permissions.permanent_delete_user.description",
+ }
+ PERMISSION_UPLOAD_FILE = &Permission{
+ "upload_file",
+ "authentication.permissions.upload_file.name",
+ "authentication.permissions.upload_file.description",
+ }
+ PERMISSION_GET_PUBLIC_LINK = &Permission{
+ "get_public_link",
+ "authentication.permissions.get_public_link.name",
+ "authentication.permissions.get_public_link.description",
+ }
+ PERMISSION_MANAGE_WEBHOOKS = &Permission{
+ "manage_webhooks",
+ "authentication.permissions.manage_webhooks.name",
+ "authentication.permissions.manage_webhooks.description",
+ }
+ PERMISSION_MANAGE_OTHERS_WEBHOOKS = &Permission{
+ "manage_others_webhooks",
+ "authentication.permissions.manage_others_webhooks.name",
+ "authentication.permissions.manage_others_webhooks.description",
+ }
+ PERMISSION_MANAGE_OAUTH = &Permission{
+ "manage_oauth",
+ "authentication.permissions.manage_oauth.name",
+ "authentication.permissions.manage_oauth.description",
+ }
+ PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH = &Permission{
+ "manage_sytem_wide_oauth",
+ "authentication.permissions.manage_sytem_wide_oauth.name",
+ "authentication.permissions.manage_sytem_wide_oauth.description",
+ }
+ PERMISSION_CREATE_POST = &Permission{
+ "create_post",
+ "authentication.permissions.create_post.name",
+ "authentication.permissions.create_post.description",
+ }
+ PERMISSION_EDIT_POST = &Permission{
+ "edit_post",
+ "authentication.permissions.edit_post.name",
+ "authentication.permissions.edit_post.description",
+ }
+ PERMISSION_EDIT_OTHERS_POSTS = &Permission{
+ "edit_others_posts",
+ "authentication.permissions.edit_others_posts.name",
+ "authentication.permissions.edit_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_MANAGE_TEAM = &Permission{
+ "manage_team",
+ "authentication.permissions.manage_team.name",
+ "authentication.permissions.manage_team.description",
+ }
+ PERMISSION_IMPORT_TEAM = &Permission{
+ "import_team",
+ "authentication.permissions.import_team.name",
+ "authentication.permissions.import_team.description",
+ }
+}
+
+func InitalizeRoles() {
+ InitalizePermissions()
+ BuiltInRoles = make(map[string]*Role)
+
+ ROLE_CHANNEL_USER = &Role{
+ "channel_user",
+ "authentication.roles.channel_user.name",
+ "authentication.roles.channel_user.description",
+ []string{
+ PERMISSION_READ_CHANNEL.Id,
+ PERMISSION_MANAGE_PUBLIC_CHANNEL_MEMBERS.Id,
+ PERMISSION_MANAGE_PRIVATE_CHANNEL_MEMBERS.Id,
+ PERMISSION_UPLOAD_FILE.Id,
+ PERMISSION_GET_PUBLIC_LINK.Id,
+ PERMISSION_CREATE_POST.Id,
+ PERMISSION_EDIT_POST.Id,
+ PERMISSION_USE_SLASH_COMMANDS.Id,
+ },
+ }
+ BuiltInRoles[ROLE_CHANNEL_USER.Id] = ROLE_CHANNEL_USER
+ ROLE_CHANNEL_ADMIN = &Role{
+ "channel_admin",
+ "authentication.roles.channel_admin.name",
+ "authentication.roles.channel_admin.description",
+ []string{},
+ }
+ BuiltInRoles[ROLE_CHANNEL_ADMIN.Id] = ROLE_CHANNEL_ADMIN
+ ROLE_CHANNEL_GUEST = &Role{
+ "guest",
+ "authentication.roles.global_guest.name",
+ "authentication.roles.global_guest.description",
+ []string{},
+ }
+ BuiltInRoles[ROLE_CHANNEL_GUEST.Id] = ROLE_CHANNEL_GUEST
+
+ ROLE_TEAM_USER = &Role{
+ "team_user",
+ "authentication.roles.team_user.name",
+ "authentication.roles.team_user.description",
+ []string{
+ PERMISSION_LIST_TEAM_CHANNELS.Id,
+ PERMISSION_JOIN_PUBLIC_CHANNELS.Id,
+ },
+ }
+ BuiltInRoles[ROLE_TEAM_USER.Id] = ROLE_TEAM_USER
+ ROLE_TEAM_ADMIN = &Role{
+ "team_admin",
+ "authentication.roles.team_admin.name",
+ "authentication.roles.team_admin.description",
+ []string{
+ PERMISSION_EDIT_OTHERS_POSTS.Id,
+ PERMISSION_ADD_USER_TO_TEAM.Id,
+ PERMISSION_REMOVE_USER_FROM_TEAM.Id,
+ PERMISSION_MANAGE_TEAM.Id,
+ PERMISSION_IMPORT_TEAM.Id,
+ PERMISSION_MANAGE_ROLES.Id,
+ PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id,
+ PERMISSION_MANAGE_SLASH_COMMANDS.Id,
+ PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS.Id,
+ PERMISSION_MANAGE_WEBHOOKS.Id,
+ },
+ }
+ BuiltInRoles[ROLE_TEAM_ADMIN.Id] = ROLE_TEAM_ADMIN
+
+ ROLE_SYSTEM_USER = &Role{
+ "system_user",
+ "authentication.roles.global_user.name",
+ "authentication.roles.global_user.description",
+ []string{
+ PERMISSION_CREATE_DIRECT_CHANNEL.Id,
+ PERMISSION_PERMANENT_DELETE_USER.Id,
+ PERMISSION_MANAGE_OAUTH.Id,
+ },
+ }
+ BuiltInRoles[ROLE_SYSTEM_USER.Id] = ROLE_SYSTEM_USER
+ ROLE_SYSTEM_ADMIN = &Role{
+ "system_admin",
+ "authentication.roles.global_admin.name",
+ "authentication.roles.global_admin.description",
+ // System admins can do anything channel and team admins can do
+ // plus everything members of teams and channels can do to all teams
+ // and channels on the system
+ append(
+ append(
+ append(
+ append(
+ []string{
+ PERMISSION_ASSIGN_SYSTEM_ADMIN_ROLE.Id,
+ PERMISSION_MANAGE_SYSTEM.Id,
+ PERMISSION_MANAGE_PUBLIC_CHANNEL_PROPERTIES.Id,
+ PERMISSION_DELETE_PUBLIC_CHANNEL.Id,
+ PERMISSION_CREATE_PUBLIC_CHANNEL.Id,
+ PERMISSION_MANAGE_PRIVATE_CHANNEL_PROPERTIES.Id,
+ PERMISSION_DELETE_PRIVATE_CHANNEL.Id,
+ PERMISSION_CREATE_PRIVATE_CHANNEL.Id,
+ PERMISSION_MANAGE_SYSTEM_WIDE_OAUTH.Id,
+ PERMISSION_MANAGE_OTHERS_WEBHOOKS.Id,
+ PERMISSION_EDIT_OTHER_USERS.Id,
+ PERMISSION_MANAGE_OAUTH.Id,
+ PERMISSION_INVITE_USER.Id,
+ },
+ ROLE_TEAM_USER.Permissions...,
+ ),
+ ROLE_CHANNEL_USER.Permissions...,
+ ),
+ ROLE_TEAM_ADMIN.Permissions...,
+ ),
+ ROLE_CHANNEL_ADMIN.Permissions...,
+ ),
+ }
+ BuiltInRoles[ROLE_SYSTEM_ADMIN.Id] = ROLE_SYSTEM_ADMIN
+
+}
+
+func RoleIdsToString(roles []string) string {
+ output := ""
+ for _, role := range roles {
+ output += role + ", "
+ }
+
+ if output == "" {
+ return "[<NO ROLES>]"
+ }
+
+ return output[:len(output)-1]
+}
+
+func init() {
+ InitalizeRoles()
+}
diff --git a/vendor/github.com/mattermost/platform/model/autocomplete.go b/vendor/github.com/mattermost/platform/model/autocomplete.go
new file mode 100644
index 00000000..b7449a79
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/autocomplete.go
@@ -0,0 +1,58 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+)
+
+type UserAutocompleteInChannel struct {
+ InChannel []*User `json:"in_channel"`
+ OutOfChannel []*User `json:"out_of_channel"`
+}
+
+type UserAutocompleteInTeam struct {
+ InTeam []*User `json:"in_team"`
+}
+
+func (o *UserAutocompleteInChannel) ToJson() string {
+ b, err := json.Marshal(o)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func UserAutocompleteInChannelFromJson(data io.Reader) *UserAutocompleteInChannel {
+ decoder := json.NewDecoder(data)
+ var o UserAutocompleteInChannel
+ err := decoder.Decode(&o)
+ if err == nil {
+ return &o
+ } else {
+ return nil
+ }
+}
+
+func (o *UserAutocompleteInTeam) ToJson() string {
+ b, err := json.Marshal(o)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func UserAutocompleteInTeamFromJson(data io.Reader) *UserAutocompleteInTeam {
+ decoder := json.NewDecoder(data)
+ var o UserAutocompleteInTeam
+ err := decoder.Decode(&o)
+ if err == nil {
+ return &o
+ } else {
+ return nil
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/channel.go b/vendor/github.com/mattermost/platform/model/channel.go
index 3da9f4fe..2ad257cc 100644
--- a/vendor/github.com/mattermost/platform/model/channel.go
+++ b/vendor/github.com/mattermost/platform/model/channel.go
@@ -10,10 +10,14 @@ import (
)
const (
- CHANNEL_OPEN = "O"
- CHANNEL_PRIVATE = "P"
- CHANNEL_DIRECT = "D"
- DEFAULT_CHANNEL = "town-square"
+ CHANNEL_OPEN = "O"
+ CHANNEL_PRIVATE = "P"
+ CHANNEL_DIRECT = "D"
+ DEFAULT_CHANNEL = "town-square"
+ CHANNEL_DISPLAY_NAME_MAX_RUNES = 64
+ CHANNEL_NAME_MAX_LENGTH = 64
+ CHANNEL_HEADER_MAX_RUNES = 1024
+ CHANNEL_PURPOSE_MAX_RUNES = 250
)
type Channel struct {
@@ -57,8 +61,8 @@ func (o *Channel) Etag() string {
return Etag(o.Id, o.UpdateAt)
}
-func (o *Channel) ExtraEtag(memberLimit int) string {
- return Etag(o.Id, o.ExtraUpdateAt, memberLimit)
+func (o *Channel) StatsEtag() string {
+ return Etag(o.Id, o.ExtraUpdateAt)
}
func (o *Channel) IsValid() *AppError {
@@ -75,11 +79,11 @@ func (o *Channel) IsValid() *AppError {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.update_at.app_error", nil, "id="+o.Id)
}
- if utf8.RuneCountInString(o.DisplayName) > 64 {
+ if utf8.RuneCountInString(o.DisplayName) > CHANNEL_DISPLAY_NAME_MAX_RUNES {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.display_name.app_error", nil, "id="+o.Id)
}
- if len(o.Name) > 64 {
+ if len(o.Name) > CHANNEL_NAME_MAX_LENGTH {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.name.app_error", nil, "id="+o.Id)
}
@@ -91,11 +95,11 @@ func (o *Channel) IsValid() *AppError {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.type.app_error", nil, "id="+o.Id)
}
- if utf8.RuneCountInString(o.Header) > 1024 {
+ if utf8.RuneCountInString(o.Header) > CHANNEL_HEADER_MAX_RUNES {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.header.app_error", nil, "id="+o.Id)
}
- if utf8.RuneCountInString(o.Purpose) > 128 {
+ if utf8.RuneCountInString(o.Purpose) > CHANNEL_PURPOSE_MAX_RUNES {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.purpose.app_error", nil, "id="+o.Id)
}
diff --git a/vendor/github.com/mattermost/platform/model/channel_extra.go b/vendor/github.com/mattermost/platform/model/channel_extra.go
deleted file mode 100644
index 55da588a..00000000
--- a/vendor/github.com/mattermost/platform/model/channel_extra.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
-)
-
-type ExtraMember struct {
- Id string `json:"id"`
- Nickname string `json:"nickname"`
- Email string `json:"email"`
- Roles string `json:"roles"`
- Username string `json:"username"`
-}
-
-func (o *ExtraMember) Sanitize(options map[string]bool) {
- if len(options) == 0 || !options["email"] {
- o.Email = ""
- }
-}
-
-type ChannelExtra struct {
- Id string `json:"id"`
- Members []ExtraMember `json:"members"`
- MemberCount int64 `json:"member_count"`
-}
-
-func (o *ChannelExtra) ToJson() string {
- b, err := json.Marshal(o)
- if err != nil {
- return ""
- } else {
- return string(b)
- }
-}
-
-func ChannelExtraFromJson(data io.Reader) *ChannelExtra {
- decoder := json.NewDecoder(data)
- var o ChannelExtra
- err := decoder.Decode(&o)
- if err == nil {
- return &o
- } else {
- return nil
- }
-}
diff --git a/vendor/github.com/mattermost/platform/model/channel_list.go b/vendor/github.com/mattermost/platform/model/channel_list.go
index 49ba384a..7a46de45 100644
--- a/vendor/github.com/mattermost/platform/model/channel_list.go
+++ b/vendor/github.com/mattermost/platform/model/channel_list.go
@@ -8,15 +8,11 @@ import (
"io"
)
-type ChannelList struct {
- Channels []*Channel `json:"channels"`
- Members map[string]*ChannelMember `json:"members"`
-}
+type ChannelList []*Channel
func (o *ChannelList) ToJson() string {
- b, err := json.Marshal(o)
- if err != nil {
- return ""
+ if b, err := json.Marshal(o); err != nil {
+ return "[]"
} else {
return string(b)
}
@@ -28,7 +24,7 @@ func (o *ChannelList) Etag() string {
var t int64 = 0
var delta int64 = 0
- for _, v := range o.Channels {
+ for _, v := range *o {
if v.LastPostAt > t {
t = v.LastPostAt
id = v.Id
@@ -39,30 +35,9 @@ func (o *ChannelList) Etag() string {
id = v.Id
}
- member := o.Members[v.Id]
-
- if member != nil {
- max := v.LastPostAt
- if v.UpdateAt > max {
- max = v.UpdateAt
- }
-
- delta += max - member.LastViewedAt
-
- if member.LastViewedAt > t {
- t = member.LastViewedAt
- id = v.Id
- }
-
- if member.LastUpdateAt > t {
- t = member.LastUpdateAt
- id = v.Id
- }
-
- }
}
- return Etag(id, t, delta, len(o.Channels))
+ return Etag(id, t, delta, len(*o))
}
func ChannelListFromJson(data io.Reader) *ChannelList {
diff --git a/vendor/github.com/mattermost/platform/model/channel_member.go b/vendor/github.com/mattermost/platform/model/channel_member.go
index 66e20da6..4180bb8e 100644
--- a/vendor/github.com/mattermost/platform/model/channel_member.go
+++ b/vendor/github.com/mattermost/platform/model/channel_member.go
@@ -10,7 +10,6 @@ import (
)
const (
- CHANNEL_ROLE_ADMIN = "admin"
CHANNEL_NOTIFY_DEFAULT = "default"
CHANNEL_NOTIFY_ALL = "all"
CHANNEL_NOTIFY_MENTION = "mention"
@@ -30,6 +29,27 @@ type ChannelMember struct {
LastUpdateAt int64 `json:"last_update_at"`
}
+type ChannelMembers []ChannelMember
+
+func (o *ChannelMembers) ToJson() string {
+ if b, err := json.Marshal(o); err != nil {
+ return "[]"
+ } else {
+ return string(b)
+ }
+}
+
+func ChannelMembersFromJson(data io.Reader) *ChannelMembers {
+ decoder := json.NewDecoder(data)
+ var o ChannelMembers
+ err := decoder.Decode(&o)
+ if err == nil {
+ return &o
+ } else {
+ return nil
+ }
+}
+
func (o *ChannelMember) ToJson() string {
b, err := json.Marshal(o)
if err != nil {
@@ -60,12 +80,6 @@ func (o *ChannelMember) IsValid() *AppError {
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.user_id.app_error", nil, "")
}
- for _, role := range strings.Split(o.Roles, " ") {
- if !(role == "" || role == CHANNEL_ROLE_ADMIN) {
- return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.role.app_error", nil, "role="+role)
- }
- }
-
notifyLevel := o.NotifyProps["desktop"]
if len(notifyLevel) > 20 || !IsChannelNotifyLevelValid(notifyLevel) {
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.notify_level.app_error",
@@ -89,6 +103,10 @@ func (o *ChannelMember) PreUpdate() {
o.LastUpdateAt = GetMillis()
}
+func (o *ChannelMember) GetRoles() []string {
+ return strings.Fields(o.Roles)
+}
+
func IsChannelNotifyLevelValid(notifyLevel string) bool {
return notifyLevel == CHANNEL_NOTIFY_DEFAULT ||
notifyLevel == CHANNEL_NOTIFY_ALL ||
diff --git a/vendor/github.com/mattermost/platform/model/channel_stats.go b/vendor/github.com/mattermost/platform/model/channel_stats.go
new file mode 100644
index 00000000..079769eb
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/channel_stats.go
@@ -0,0 +1,34 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+)
+
+type ChannelStats struct {
+ ChannelId string `json:"channel_id"`
+ MemberCount int64 `json:"member_count"`
+}
+
+func (o *ChannelStats) ToJson() string {
+ b, err := json.Marshal(o)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func ChannelStatsFromJson(data io.Reader) *ChannelStats {
+ decoder := json.NewDecoder(data)
+ var o ChannelStats
+ err := decoder.Decode(&o)
+ if err == nil {
+ return &o
+ } else {
+ return nil
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/client.go b/vendor/github.com/mattermost/platform/model/client.go
index e54f6134..8a361c17 100644
--- a/vendor/github.com/mattermost/platform/model/client.go
+++ b/vendor/github.com/mattermost/platform/model/client.go
@@ -108,6 +108,10 @@ func (c *Client) GetChannelRoute(channelId string) string {
return fmt.Sprintf("/teams/%v/channels/%v", c.GetTeamId(), channelId)
}
+func (c *Client) GetUserRequiredRoute(userId string) string {
+ return fmt.Sprintf("/users/%v", userId)
+}
+
func (c *Client) GetChannelNameRoute(channelName string) string {
return fmt.Sprintf("/teams/%v/channels/name/%v", c.GetTeamId(), channelName)
}
@@ -120,9 +124,14 @@ func (c *Client) GetGeneralRoute() string {
return "/general"
}
+func (c *Client) GetFileRoute(fileId string) string {
+ return fmt.Sprintf("/files/%v", fileId)
+}
+
func (c *Client) DoPost(url, data, contentType string) (*http.Response, *AppError) {
rq, _ := http.NewRequest("POST", c.Url+url, strings.NewReader(data))
rq.Header.Set("Content-Type", contentType)
+ rq.Close = true
if rp, err := c.HttpClient.Do(rq); err != nil {
return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
@@ -136,6 +145,7 @@ func (c *Client) DoPost(url, data, contentType string) (*http.Response, *AppErro
func (c *Client) DoApiPost(url string, data string) (*http.Response, *AppError) {
rq, _ := http.NewRequest("POST", c.ApiUrl+url, strings.NewReader(data))
+ rq.Close = true
if len(c.AuthToken) > 0 {
rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
@@ -153,6 +163,7 @@ func (c *Client) DoApiPost(url string, data string) (*http.Response, *AppError)
func (c *Client) DoApiGet(url string, data string, etag string) (*http.Response, *AppError) {
rq, _ := http.NewRequest("GET", c.ApiUrl+url, strings.NewReader(data))
+ rq.Close = true
if len(etag) > 0 {
rq.Header.Set(HEADER_ETAG_CLIENT, etag)
@@ -500,10 +511,33 @@ func (c *Client) GetMe(etag string) (*Result, *AppError) {
}
}
-// GetProfilesForDirectMessageList returns a map of users for a team that can be direct
-// messaged, using user id as the key. Must be authenticated.
-func (c *Client) GetProfilesForDirectMessageList(teamId string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/users/profiles_for_dm_list/"+teamId, "", ""); err != nil {
+// GetProfiles returns a map of users using user id as the key. Must be authenticated.
+func (c *Client) GetProfiles(offset int, limit int, etag string) (*Result, *AppError) {
+ if r, err := c.DoApiGet(fmt.Sprintf("/users/%v/%v", offset, limit), "", etag); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
+ }
+}
+
+// GetProfilesInTeam returns a map of users for a team using user id as the key. Must
+// be authenticated.
+func (c *Client) GetProfilesInTeam(teamId string, offset int, limit int, etag string) (*Result, *AppError) {
+ if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/users/%v/%v", teamId, offset, limit), "", etag); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
+ }
+}
+
+// GetProfilesInChannel returns a map of users for a channel using user id as the key. Must
+// be authenticated.
+func (c *Client) GetProfilesInChannel(channelId string, offset int, limit int, etag string) (*Result, *AppError) {
+ if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/users/%v/%v", offset, limit), "", etag); err != nil {
return nil, err
} else {
defer closeBody(r)
@@ -512,10 +546,10 @@ func (c *Client) GetProfilesForDirectMessageList(teamId string) (*Result, *AppEr
}
}
-// GetProfiles returns a map of users for a team using user id as the key. Must
+// GetProfilesNotInChannel returns a map of users not in a channel but on the team using user id as the key. Must
// be authenticated.
-func (c *Client) GetProfiles(teamId string, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/users/profiles/"+teamId, "", etag); err != nil {
+func (c *Client) GetProfilesNotInChannel(channelId string, offset int, limit int, etag string) (*Result, *AppError) {
+ if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/users/not_in_channel/%v/%v", offset, limit), "", etag); err != nil {
return nil, err
} else {
defer closeBody(r)
@@ -524,10 +558,10 @@ func (c *Client) GetProfiles(teamId string, etag string) (*Result, *AppError) {
}
}
-// GetDirectProfiles gets a map of users that are currently shown in the sidebar,
-// using user id as the key. Must be authenticated.
-func (c *Client) GetDirectProfiles(etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/users/direct_profiles", "", etag); err != nil {
+// GetProfilesByIds returns a map of users based on the user ids provided. Must
+// be authenticated.
+func (c *Client) GetProfilesByIds(userIds []string) (*Result, *AppError) {
+ if r, err := c.DoApiPost("/users/ids", ArrayToJson(userIds)); err != nil {
return nil, err
} else {
defer closeBody(r)
@@ -536,6 +570,46 @@ func (c *Client) GetDirectProfiles(etag string) (*Result, *AppError) {
}
}
+// SearchUsers returns a list of users that have a username matching or similar to the search term. Must
+// be authenticated.
+func (c *Client) SearchUsers(params UserSearch) (*Result, *AppError) {
+ if r, err := c.DoApiPost("/users/search", params.ToJson()); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), UserListFromJson(r.Body)}, nil
+ }
+}
+
+// AutocompleteUsersInChannel returns two lists for autocompletion of users in a channel. The first list "in_channel",
+// specifies users in the channel. The second list "out_of_channel" specifies users outside of the
+// channel. Term, the string to search against, is required, channel id is also required. Must be authenticated.
+func (c *Client) AutocompleteUsersInChannel(term string, channelId string) (*Result, *AppError) {
+ url := fmt.Sprintf("%s/users/autocomplete?term=%s", c.GetChannelRoute(channelId), url.QueryEscape(term))
+ if r, err := c.DoApiGet(url, "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), UserAutocompleteInChannelFromJson(r.Body)}, nil
+ }
+}
+
+// AutocompleteUsersInTeam returns a list for autocompletion of users in a team. The list "in_team" specifies
+// the users in the team that match the provided term, matching against username, full name and
+// nickname. Must be authenticated.
+func (c *Client) AutocompleteUsersInTeam(term string) (*Result, *AppError) {
+ url := fmt.Sprintf("%s/users/autocomplete?term=%s", c.GetTeamRoute(), url.QueryEscape(term))
+ if r, err := c.DoApiGet(url, "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), UserAutocompleteInTeamFromJson(r.Body)}, nil
+ }
+}
+
// LoginById authenticates a user by user id and password.
func (c *Client) LoginById(id string, password string) (*Result, *AppError) {
m := make(map[string]string)
@@ -622,15 +696,16 @@ func (c *Client) CheckMfa(loginId string) (*Result, *AppError) {
}
}
-// GenerateMfaQrCode returns a QR code imagem containing the secret, to be scanned
-// by a multi-factor authentication mobile application. Must be authenticated.
-func (c *Client) GenerateMfaQrCode() (*Result, *AppError) {
- if r, err := c.DoApiGet("/users/generate_mfa_qr", "", ""); err != nil {
+// GenerateMfaSecret returns a QR code image containing the secret, to be scanned
+// by a multi-factor authentication mobile application. It also returns the secret
+// for manual entry. Must be authenticated.
+func (c *Client) GenerateMfaSecret() (*Result, *AppError) {
+ if r, err := c.DoApiGet("/users/generate_mfa_secret", "", ""); err != nil {
return nil, err
} else {
defer closeBody(r)
return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), r.Body}, nil
+ r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
}
}
@@ -934,6 +1009,7 @@ func (c *Client) SaveComplianceReport(job *Compliance) (*Result, *AppError) {
func (c *Client) DownloadComplianceReport(id string) (*Result, *AppError) {
var rq *http.Request
rq, _ = http.NewRequest("GET", c.ApiUrl+"/admin/download_compliance_report/"+id, nil)
+ rq.Close = true
if len(c.AuthToken) > 0 {
rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
@@ -1047,13 +1123,13 @@ func (c *Client) UpdateNotifyProps(data map[string]string) (*Result, *AppError)
}
}
-func (c *Client) GetChannels(etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/", "", etag); err != nil {
+func (c *Client) GetMyChannelMembers() (*Result, *AppError) {
+ if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/members", "", ""); err != nil {
return nil, err
} else {
defer closeBody(r)
return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
+ r.Header.Get(HEADER_ETAG_SERVER), ChannelMembersFromJson(r.Body)}, nil
}
}
@@ -1087,6 +1163,16 @@ func (c *Client) GetChannelCounts(etag string) (*Result, *AppError) {
}
}
+func (c *Client) GetChannels(etag string) (*Result, *AppError) {
+ if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/", "", etag); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
+ }
+}
+
func (c *Client) JoinChannel(id string) (*Result, *AppError) {
if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/join", ""); err != nil {
return nil, err
@@ -1166,13 +1252,23 @@ func (c *Client) UpdateLastViewedAt(channelId string, active bool) (*Result, *Ap
}
}
-func (c *Client) GetChannelExtraInfo(id string, memberLimit int, etag string) (*Result, *AppError) {
- if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/extra_info/"+strconv.FormatInt(int64(memberLimit), 10), "", etag); err != nil {
+func (c *Client) GetChannelStats(id string, etag string) (*Result, *AppError) {
+ if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/stats", "", etag); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), ChannelStatsFromJson(r.Body)}, nil
+ }
+}
+
+func (c *Client) GetChannelMember(channelId string, userId string) (*Result, *AppError) {
+ if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/members/"+userId, "", ""); err != nil {
return nil, err
} else {
defer closeBody(r)
return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), ChannelExtraFromJson(r.Body)}, nil
+ r.Header.Get(HEADER_ETAG_SERVER), ChannelMemberFromJson(r.Body)}, nil
}
}
@@ -1285,13 +1381,39 @@ func (c *Client) UploadProfileFile(data []byte, contentType string) (*Result, *A
return c.uploadFile(c.ApiUrl+"/users/newimage", data, contentType)
}
-func (c *Client) UploadPostAttachment(data []byte, contentType string) (*Result, *AppError) {
- return c.uploadFile(c.ApiUrl+c.GetTeamRoute()+"/files/upload", data, contentType)
+func (c *Client) UploadPostAttachment(data []byte, channelId string, filename string) (*FileUploadResponse, *AppError) {
+ c.clearExtraProperties()
+
+ body := &bytes.Buffer{}
+ writer := multipart.NewWriter(body)
+
+ if part, err := writer.CreateFormFile("files", filename); err != nil {
+ return nil, NewLocAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error())
+ } else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
+ return nil, NewLocAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error())
+ }
+
+ if part, err := writer.CreateFormField("channel_id"); err != nil {
+ return nil, NewLocAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error())
+ } else if _, err = io.Copy(part, strings.NewReader(channelId)); err != nil {
+ return nil, NewLocAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error())
+ }
+
+ if err := writer.Close(); err != nil {
+ return nil, NewLocAppError("UploadPostAttachment", "model.client.upload_post_attachment.writer.app_error", nil, err.Error())
+ }
+
+ if result, err := c.uploadFile(c.ApiUrl+c.GetTeamRoute()+"/files/upload", body.Bytes(), writer.FormDataContentType()); err != nil {
+ return nil, err
+ } else {
+ return result.Data.(*FileUploadResponse), nil
+ }
}
func (c *Client) uploadFile(url string, data []byte, contentType string) (*Result, *AppError) {
rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
rq.Header.Set("Content-Type", contentType)
+ rq.Close = true
if len(c.AuthToken) > 0 {
rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
@@ -1308,70 +1430,83 @@ func (c *Client) uploadFile(url string, data []byte, contentType string) (*Resul
}
}
-func (c *Client) GetFile(url string, isFullUrl bool) (*Result, *AppError) {
- var rq *http.Request
- if isFullUrl {
- rq, _ = http.NewRequest("GET", url, nil)
+func (c *Client) GetFile(fileId string) (io.ReadCloser, *AppError) {
+ if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get", "", ""); err != nil {
+ return nil, err
} else {
- rq, _ = http.NewRequest("GET", c.ApiUrl+c.GetTeamRoute()+"/files/get"+url, nil)
+ c.fillInExtraProperties(r)
+ return r.Body, nil
}
+}
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
+func (c *Client) GetFileThumbnail(fileId string) (io.ReadCloser, *AppError) {
+ if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_thumbnail", "", ""); err != nil {
+ return nil, err
+ } else {
+ c.fillInExtraProperties(r)
+ return r.Body, nil
}
+}
- 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 >= 300 {
- return nil, AppErrorFromJson(rp.Body)
+func (c *Client) GetFilePreview(fileId string) (io.ReadCloser, *AppError) {
+ if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_preview", "", ""); err != nil {
+ return nil, err
} else {
- defer closeBody(rp)
- return &Result{rp.Header.Get(HEADER_REQUEST_ID),
- rp.Header.Get(HEADER_ETAG_SERVER), rp.Body}, nil
+ defer closeBody(r)
+ c.fillInExtraProperties(r)
+ return r.Body, nil
}
}
-func (c *Client) GetFileInfo(url string) (*Result, *AppError) {
- var rq *http.Request
- rq, _ = http.NewRequest("GET", c.ApiUrl+c.GetTeamRoute()+"/files/get_info"+url, nil)
-
- if len(c.AuthToken) > 0 {
- rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
+func (c *Client) GetFileInfo(fileId string) (*FileInfo, *AppError) {
+ if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_info", "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ c.fillInExtraProperties(r)
+ return FileInfoFromJson(r.Body), nil
}
+}
- 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 >= 300 {
- return nil, AppErrorFromJson(rp.Body)
+func (c *Client) GetPublicLink(fileId string) (string, *AppError) {
+ if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_public_link", "", ""); err != nil {
+ return "", err
} else {
- defer closeBody(rp)
- return &Result{rp.Header.Get(HEADER_REQUEST_ID),
- rp.Header.Get(HEADER_ETAG_SERVER), FileInfoFromJson(rp.Body)}, nil
+ defer closeBody(r)
+ c.fillInExtraProperties(r)
+ return StringFromJson(r.Body), nil
}
}
-func (c *Client) GetPublicLink(filename string) (*Result, *AppError) {
- if r, err := c.DoApiPost(c.GetTeamRoute()+"/files/get_public_link", MapToJson(map[string]string{"filename": filename})); err != nil {
+func (c *Client) UpdateUser(user *User) (*Result, *AppError) {
+ if r, err := c.DoApiPost("/users/update", user.ToJson()); err != nil {
return nil, err
} else {
defer closeBody(r)
return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), StringFromJson(r.Body)}, nil
+ r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
}
}
-func (c *Client) UpdateUser(user *User) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/update", user.ToJson()); err != nil {
+func (c *Client) UpdateUserRoles(userId string, roles string) (*Result, *AppError) {
+ data := make(map[string]string)
+ data["new_roles"] = roles
+
+ if r, err := c.DoApiPost(c.GetUserRequiredRoute(userId)+"/update_roles", MapToJson(data)); err != nil {
return nil, err
} else {
defer closeBody(r)
return &Result{r.Header.Get(HEADER_REQUEST_ID),
- r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
+ r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
}
}
-func (c *Client) UpdateUserRoles(data map[string]string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/update_roles", MapToJson(data)); err != nil {
+func (c *Client) UpdateTeamRoles(userId string, roles string) (*Result, *AppError) {
+ data := make(map[string]string)
+ data["new_roles"] = roles
+ data["user_id"] = userId
+
+ if r, err := c.DoApiPost(c.GetTeamRoute()+"/update_member_roles", MapToJson(data)); err != nil {
return nil, err
} else {
defer closeBody(r)
@@ -1479,6 +1614,18 @@ func (c *Client) GetStatuses() (*Result, *AppError) {
}
}
+// GetStatusesByIds returns a map of string statuses using user id as the key,
+// based on the provided user ids
+func (c *Client) GetStatusesByIds(userIds []string) (*Result, *AppError) {
+ if r, err := c.DoApiPost("/users/status/ids", 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), MapFromJson(r.Body)}, nil
+ }
+}
+
// SetActiveChannel sets the the channel id the user is currently viewing.
// The channelId key is required but the value can be blank. Returns standard
// response.
@@ -1504,8 +1651,46 @@ func (c *Client) GetMyTeam(etag string) (*Result, *AppError) {
}
}
-func (c *Client) GetTeamMembers(teamId string) (*Result, *AppError) {
- if r, err := c.DoApiGet("/teams/members/"+teamId, "", ""); err != nil {
+// GetTeamMembers will return a page of team member objects as an array paged based on the
+// team id, offset and limit provided. Must be authenticated.
+func (c *Client) GetTeamMembers(teamId string, offset int, limit int) (*Result, *AppError) {
+ if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/members/%v/%v", teamId, offset, limit), "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), TeamMembersFromJson(r.Body)}, nil
+ }
+}
+
+// GetTeamMember will return a team member object based on the team id and user id provided.
+// Must be authenticated.
+func (c *Client) GetTeamMember(teamId string, userId string) (*Result, *AppError) {
+ if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/members/%v", teamId, userId), "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), TeamMemberFromJson(r.Body)}, nil
+ }
+}
+
+// GetTeamStats will return a team stats object containing the number of users on the team
+// based on the team id provided. Must be authenticated.
+func (c *Client) GetTeamStats(teamId string) (*Result, *AppError) {
+ if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/stats", teamId), "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), TeamStatsFromJson(r.Body)}, nil
+ }
+}
+
+// GetTeamMembersByIds will return team member objects as an array based on the
+// team id and a list of user ids provided. Must be authenticated.
+func (c *Client) GetTeamMembersByIds(teamId string, userIds []string) (*Result, *AppError) {
+ if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds)); err != nil {
return nil, err
} else {
defer closeBody(r)
@@ -1820,6 +2005,7 @@ func (c *Client) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoj
rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetEmojiRoute()+"/create", body)
rq.Header.Set("Content-Type", writer.FormDataContentType())
+ rq.Close = true
if len(c.AuthToken) > 0 {
rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
@@ -1862,6 +2048,7 @@ func (c *Client) UploadCertificateFile(data []byte, contentType string) *AppErro
url := c.ApiUrl + "/admin/add_certificate"
rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
rq.Header.Set("Content-Type", contentType)
+ rq.Close = true
if len(c.AuthToken) > 0 {
rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
@@ -1898,3 +2085,28 @@ func (c *Client) SamlCertificateStatus(filename string) (map[string]interface{},
return StringInterfaceFromJson(r.Body), nil
}
}
+
+// GetWebrtcToken if Successful returns a map with a valid token, stun server and turn server with credentials to use with
+// the Mattermost WebRTC service, otherwise returns an AppError. Must be authenticated user.
+func (c *Client) GetWebrtcToken() (map[string]string, *AppError) {
+ if r, err := c.DoApiPost("/webrtc/token", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return MapFromJson(r.Body), nil
+ }
+}
+
+// GetFileInfosForPost returns a list of FileInfo objects for a given post id, if successful.
+// Otherwise, it returns an error.
+func (c *Client) GetFileInfosForPost(channelId string, postId string, etag string) ([]*FileInfo, *AppError) {
+ c.clearExtraProperties()
+
+ if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/get_file_infos", postId), "", etag); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ c.fillInExtraProperties(r)
+ return FileInfosFromJson(r.Body), nil
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/compliance_post.go b/vendor/github.com/mattermost/platform/model/compliance_post.go
index ce26a366..027e534b 100644
--- a/vendor/github.com/mattermost/platform/model/compliance_post.go
+++ b/vendor/github.com/mattermost/platform/model/compliance_post.go
@@ -34,7 +34,7 @@ type CompliancePost struct {
PostType string
PostProps string
PostHashtags string
- PostFilenames string
+ PostFileIds string
}
func CompliancePostHeader() []string {
@@ -60,7 +60,7 @@ func CompliancePostHeader() []string {
"PostType",
"PostProps",
"PostHashtags",
- "PostFilenames",
+ "PostFileIds",
}
}
@@ -99,6 +99,6 @@ func (me *CompliancePost) Row() []string {
me.PostType,
me.PostProps,
me.PostHashtags,
- me.PostFilenames,
+ me.PostFileIds,
}
}
diff --git a/vendor/github.com/mattermost/platform/model/config.go b/vendor/github.com/mattermost/platform/model/config.go
index 3ad1c4c6..f2ff788d 100644
--- a/vendor/github.com/mattermost/platform/model/config.go
+++ b/vendor/github.com/mattermost/platform/model/config.go
@@ -57,6 +57,14 @@ const (
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
@@ -130,26 +138,24 @@ type PasswordSettings struct {
}
type FileSettings struct {
- MaxFileSize *int64
- DriverName string
- Directory string
- EnablePublicLink bool
- PublicLinkSalt *string
- ThumbnailWidth int
- ThumbnailHeight int
- PreviewWidth int
- PreviewHeight int
- ProfileWidth int
- ProfileHeight int
- InitialFont string
- AmazonS3AccessKeyId string
- AmazonS3SecretAccessKey string
- AmazonS3Bucket string
- AmazonS3Region string
- AmazonS3Endpoint string
- AmazonS3BucketEndpoint string
- AmazonS3LocationConstraint *bool
- AmazonS3LowercaseBucket *bool
+ MaxFileSize *int64
+ DriverName string
+ Directory string
+ EnablePublicLink bool
+ PublicLinkSalt *string
+ ThumbnailWidth int
+ ThumbnailHeight int
+ PreviewWidth int
+ PreviewHeight int
+ ProfileWidth int
+ ProfileHeight int
+ InitialFont string
+ AmazonS3AccessKeyId string
+ AmazonS3SecretAccessKey string
+ AmazonS3Bucket string
+ AmazonS3Region string
+ AmazonS3Endpoint string
+ AmazonS3SSL *bool
}
type EmailSettings struct {
@@ -177,11 +183,12 @@ type EmailSettings struct {
}
type RateLimitSettings struct {
- EnableRateLimiter bool
- PerSec int
- MemoryStoreSize int
- VaryByRemoteAddr bool
- VaryByHeader string
+ Enable *bool
+ PerSec int
+ MaxBurst *int
+ MemoryStoreSize int
+ VaryByRemoteAddr bool
+ VaryByHeader string
}
type PrivacySettings struct {
@@ -205,7 +212,6 @@ type TeamSettings struct {
EnableUserCreation bool
EnableOpenServer *bool
RestrictCreationToDomains string
- RestrictTeamNames *bool
EnableCustomBrand *bool
CustomBrandText *string
CustomDescriptionText *string
@@ -214,6 +220,7 @@ type TeamSettings struct {
RestrictPublicChannelManagement *string
RestrictPrivateChannelManagement *string
UserStatusAwayTimeout *int64
+ MaxChannelsPerTeam *int64
}
type LdapSettings struct {
@@ -292,6 +299,17 @@ type NativeAppSettings struct {
IosAppDownloadLink *string
}
+type WebrtcSettings struct {
+ Enable *bool
+ GatewayWebsocketUrl *string
+ GatewayAdminUrl *string
+ GatewayAdminSecret *string
+ StunURI *string
+ TurnURI *string
+ TurnUsername *string
+ TurnSharedKey *string
+}
+
type Config struct {
ServiceSettings ServiceSettings
TeamSettings TeamSettings
@@ -312,6 +330,7 @@ type Config struct {
SamlSettings SamlSettings
NativeAppSettings NativeAppSettings
ClusterSettings ClusterSettings
+ WebrtcSettings WebrtcSettings
}
func (o *Config) ToJson() string {
@@ -353,26 +372,27 @@ func (o *Config) SetDefaults() {
o.SqlSettings.AtRestEncryptKey = NewRandomString(32)
}
+ if o.FileSettings.AmazonS3Endpoint == "" {
+ // Defaults to "s3.amazonaws.com"
+ o.FileSettings.AmazonS3Endpoint = "s3.amazonaws.com"
+ }
+ if o.FileSettings.AmazonS3Region == "" {
+ // Defaults to "us-east-1" region.
+ o.FileSettings.AmazonS3Region = "us-east-1"
+ }
+ if o.FileSettings.AmazonS3SSL == nil {
+ o.FileSettings.AmazonS3SSL = new(bool)
+ *o.FileSettings.AmazonS3SSL = true // Secure by default.
+ }
if o.FileSettings.MaxFileSize == nil {
o.FileSettings.MaxFileSize = new(int64)
*o.FileSettings.MaxFileSize = 52428800 // 50 MB
}
-
if len(*o.FileSettings.PublicLinkSalt) == 0 {
o.FileSettings.PublicLinkSalt = new(string)
*o.FileSettings.PublicLinkSalt = NewRandomString(32)
}
- if o.FileSettings.AmazonS3LocationConstraint == nil {
- o.FileSettings.AmazonS3LocationConstraint = new(bool)
- *o.FileSettings.AmazonS3LocationConstraint = false
- }
-
- if o.FileSettings.AmazonS3LowercaseBucket == nil {
- o.FileSettings.AmazonS3LowercaseBucket = new(bool)
- *o.FileSettings.AmazonS3LowercaseBucket = false
- }
-
if len(o.EmailSettings.InviteSalt) == 0 {
o.EmailSettings.InviteSalt = NewRandomString(32)
}
@@ -431,11 +451,6 @@ func (o *Config) SetDefaults() {
*o.PasswordSettings.Symbol = false
}
- if o.TeamSettings.RestrictTeamNames == nil {
- o.TeamSettings.RestrictTeamNames = new(bool)
- *o.TeamSettings.RestrictTeamNames = true
- }
-
if o.TeamSettings.EnableCustomBrand == nil {
o.TeamSettings.EnableCustomBrand = new(bool)
*o.TeamSettings.EnableCustomBrand = false
@@ -481,6 +496,11 @@ func (o *Config) SetDefaults() {
*o.TeamSettings.UserStatusAwayTimeout = 300
}
+ if o.TeamSettings.MaxChannelsPerTeam == nil {
+ o.TeamSettings.MaxChannelsPerTeam = new(int64)
+ *o.TeamSettings.MaxChannelsPerTeam = 2000
+ }
+
if o.EmailSettings.EnableSignInWithEmail == nil {
o.EmailSettings.EnableSignInWithEmail = new(bool)
@@ -881,6 +901,58 @@ func (o *Config) SetDefaults() {
o.NativeAppSettings.IosAppDownloadLink = new(string)
*o.NativeAppSettings.IosAppDownloadLink = "https://about.mattermost.com/mattermost-ios-app/"
}
+
+ if o.RateLimitSettings.Enable == nil {
+ o.RateLimitSettings.Enable = new(bool)
+ *o.RateLimitSettings.Enable = false
+ }
+
+ if o.RateLimitSettings.MaxBurst == nil {
+ o.RateLimitSettings.MaxBurst = new(int)
+ *o.RateLimitSettings.MaxBurst = 100
+ }
+
+ if o.ServiceSettings.ConnectionSecurity == nil {
+ o.ServiceSettings.ConnectionSecurity = new(string)
+ *o.ServiceSettings.ConnectionSecurity = ""
+ }
+
+ if o.ServiceSettings.TLSKeyFile == nil {
+ o.ServiceSettings.TLSKeyFile = new(string)
+ *o.ServiceSettings.TLSKeyFile = ""
+ }
+
+ if o.ServiceSettings.TLSCertFile == nil {
+ o.ServiceSettings.TLSCertFile = new(string)
+ *o.ServiceSettings.TLSCertFile = ""
+ }
+
+ if o.ServiceSettings.UseLetsEncrypt == nil {
+ o.ServiceSettings.UseLetsEncrypt = new(bool)
+ *o.ServiceSettings.UseLetsEncrypt = false
+ }
+
+ if o.ServiceSettings.LetsEncryptCertificateCacheFile == nil {
+ o.ServiceSettings.LetsEncryptCertificateCacheFile = new(string)
+ *o.ServiceSettings.LetsEncryptCertificateCacheFile = "./config/letsencrypt.cache"
+ }
+
+ if o.ServiceSettings.ReadTimeout == nil {
+ o.ServiceSettings.ReadTimeout = new(int)
+ *o.ServiceSettings.ReadTimeout = 300
+ }
+
+ if o.ServiceSettings.WriteTimeout == nil {
+ o.ServiceSettings.WriteTimeout = new(int)
+ *o.ServiceSettings.WriteTimeout = 300
+ }
+
+ if o.ServiceSettings.Forward80To443 == nil {
+ o.ServiceSettings.Forward80To443 = new(bool)
+ *o.ServiceSettings.Forward80To443 = false
+ }
+
+ o.defaultWebrtcSettings()
}
func (o *Config) IsValid() *AppError {
@@ -911,6 +983,10 @@ func (o *Config) IsValid() *AppError {
return NewLocAppError("Config.IsValid", "model.config.is_valid.max_users.app_error", nil, "")
}
+ if *o.TeamSettings.MaxChannelsPerTeam <= 0 {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.max_channels.app_error", nil, "")
+ }
+
if !(*o.TeamSettings.RestrictDirectMessage == DIRECT_MESSAGE_ANY || *o.TeamSettings.RestrictDirectMessage == DIRECT_MESSAGE_TEAM) {
return NewLocAppError("Config.IsValid", "model.config.is_valid.restrict_direct_message.app_error", nil, "")
}
@@ -1083,6 +1159,26 @@ func (o *Config) IsValid() *AppError {
return NewLocAppError("Config.IsValid", "model.config.is_valid.sitename_length.app_error", map[string]interface{}{"MaxLength": SITENAME_MAX_LENGTH}, "")
}
+ if *o.RateLimitSettings.MaxBurst <= 0 {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.max_burst.app_error", nil, "")
+ }
+
+ if err := o.isValidWebrtcSettings(); err != nil {
+ return err
+ }
+
+ if !(*o.ServiceSettings.ConnectionSecurity == CONN_SECURITY_NONE || *o.ServiceSettings.ConnectionSecurity == CONN_SECURITY_TLS) {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.webserver_security.app_error", nil, "")
+ }
+
+ if *o.ServiceSettings.ReadTimeout <= 0 {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.read_timeout.app_error", nil, "")
+ }
+
+ if *o.ServiceSettings.WriteTimeout <= 0 {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.write_timeout.app_error", nil, "")
+ }
+
return nil
}
@@ -1121,3 +1217,71 @@ func (o *Config) Sanitize() {
o.SqlSettings.DataSourceReplicas[i] = FAKE_SETTING
}
}
+
+func (o *Config) defaultWebrtcSettings() {
+ if o.WebrtcSettings.Enable == nil {
+ o.WebrtcSettings.Enable = new(bool)
+ *o.WebrtcSettings.Enable = false
+ }
+
+ if o.WebrtcSettings.GatewayWebsocketUrl == nil {
+ o.WebrtcSettings.GatewayWebsocketUrl = new(string)
+ *o.WebrtcSettings.GatewayWebsocketUrl = ""
+ }
+
+ if o.WebrtcSettings.GatewayAdminUrl == nil {
+ o.WebrtcSettings.GatewayAdminUrl = new(string)
+ *o.WebrtcSettings.GatewayAdminUrl = ""
+ }
+
+ if o.WebrtcSettings.GatewayAdminSecret == nil {
+ o.WebrtcSettings.GatewayAdminSecret = new(string)
+ *o.WebrtcSettings.GatewayAdminSecret = ""
+ }
+
+ if o.WebrtcSettings.StunURI == nil {
+ o.WebrtcSettings.StunURI = new(string)
+ *o.WebrtcSettings.StunURI = ""
+ }
+
+ if o.WebrtcSettings.TurnURI == nil {
+ o.WebrtcSettings.TurnURI = new(string)
+ *o.WebrtcSettings.TurnURI = ""
+ }
+
+ if o.WebrtcSettings.TurnUsername == nil {
+ o.WebrtcSettings.TurnUsername = new(string)
+ *o.WebrtcSettings.TurnUsername = ""
+ }
+
+ if o.WebrtcSettings.TurnSharedKey == nil {
+ o.WebrtcSettings.TurnSharedKey = new(string)
+ *o.WebrtcSettings.TurnSharedKey = ""
+ }
+}
+
+func (o *Config) isValidWebrtcSettings() *AppError {
+ if *o.WebrtcSettings.Enable {
+ if len(*o.WebrtcSettings.GatewayWebsocketUrl) == 0 || !IsValidWebsocketUrl(*o.WebrtcSettings.GatewayWebsocketUrl) {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.webrtc_gateway_ws_url.app_error", nil, "")
+ } else if len(*o.WebrtcSettings.GatewayAdminUrl) == 0 || !IsValidHttpUrl(*o.WebrtcSettings.GatewayAdminUrl) {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.webrtc_gateway_admin_url.app_error", nil, "")
+ } else if len(*o.WebrtcSettings.GatewayAdminSecret) == 0 {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.webrtc_gateway_admin_secret.app_error", nil, "")
+ } else if len(*o.WebrtcSettings.StunURI) != 0 && !IsValidTurnOrStunServer(*o.WebrtcSettings.StunURI) {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.webrtc_stun_uri.app_error", nil, "")
+ } else if len(*o.WebrtcSettings.TurnURI) != 0 {
+ if !IsValidTurnOrStunServer(*o.WebrtcSettings.TurnURI) {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.webrtc_turn_uri.app_error", nil, "")
+ }
+ if len(*o.WebrtcSettings.TurnUsername) == 0 {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.webrtc_turn_username.app_error", nil, "")
+ } else if len(*o.WebrtcSettings.TurnSharedKey) == 0 {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.webrtc_turn_shared_key.app_error", nil, "")
+ }
+
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/mattermost/platform/model/file.go b/vendor/github.com/mattermost/platform/model/file.go
index fa98a3b3..c218c424 100644
--- a/vendor/github.com/mattermost/platform/model/file.go
+++ b/vendor/github.com/mattermost/platform/model/file.go
@@ -14,8 +14,8 @@ var (
)
type FileUploadResponse struct {
- Filenames []string `json:"filenames"`
- ClientIds []string `json:"client_ids"`
+ FileInfos []*FileInfo `json:"file_infos"`
+ ClientIds []string `json:"client_ids"`
}
func FileUploadResponseFromJson(data io.Reader) *FileUploadResponse {
diff --git a/vendor/github.com/mattermost/platform/model/file_info.go b/vendor/github.com/mattermost/platform/model/file_info.go
index f785042b..687473d4 100644
--- a/vendor/github.com/mattermost/platform/model/file_info.go
+++ b/vendor/github.com/mattermost/platform/model/file_info.go
@@ -6,58 +6,55 @@ package model
import (
"bytes"
"encoding/json"
+ "image"
"image/gif"
"io"
"mime"
"path/filepath"
+ "strings"
)
type FileInfo struct {
- Filename string `json:"filename"`
- Size int `json:"size"`
+ Id string `json:"id"`
+ CreatorId string `json:"user_id"`
+ PostId string `json:"post_id,omitempty"`
+ CreateAt int64 `json:"create_at"`
+ UpdateAt int64 `json:"update_at"`
+ DeleteAt int64 `json:"delete_at"`
+ Path string `json:"-"` // not sent back to the client
+ ThumbnailPath string `json:"-"` // not sent back to the client
+ PreviewPath string `json:"-"` // not sent back to the client
+ Name string `json:"name"`
Extension string `json:"extension"`
+ Size int64 `json:"size"`
MimeType string `json:"mime_type"`
- HasPreviewImage bool `json:"has_preview_image"`
+ Width int `json:"width,omitempty"`
+ Height int `json:"height,omitempty"`
+ HasPreviewImage bool `json:"has_preview_image,omitempty"`
}
-func GetInfoForBytes(filename string, data []byte) (*FileInfo, *AppError) {
- size := len(data)
-
- var mimeType string
- extension := filepath.Ext(filename)
- isImage := IsFileExtImage(extension)
- if isImage {
- mimeType = GetImageMimeType(extension)
+func (info *FileInfo) ToJson() string {
+ b, err := json.Marshal(info)
+ if err != nil {
+ return ""
} else {
- mimeType = mime.TypeByExtension(extension)
+ return string(b)
}
+}
- if extension != "" && extension[0] == '.' {
- // the client expects a file extension without the leading period
- extension = extension[1:]
- }
+func FileInfoFromJson(data io.Reader) *FileInfo {
+ decoder := json.NewDecoder(data)
- hasPreviewImage := isImage
- if mimeType == "image/gif" {
- // just show the gif itself instead of a preview image for animated gifs
- if gifImage, err := gif.DecodeAll(bytes.NewReader(data)); err != nil {
- return nil, NewLocAppError("GetInfoForBytes", "model.file_info.get.gif.app_error", nil, "filename="+filename)
- } else {
- hasPreviewImage = len(gifImage.Image) == 1
- }
+ var info FileInfo
+ if err := decoder.Decode(&info); err != nil {
+ return nil
+ } else {
+ return &info
}
-
- return &FileInfo{
- Filename: filename,
- Size: size,
- Extension: extension,
- MimeType: mimeType,
- HasPreviewImage: hasPreviewImage,
- }, nil
}
-func (info *FileInfo) ToJson() string {
- b, err := json.Marshal(info)
+func FileInfosToJson(infos []*FileInfo) string {
+ b, err := json.Marshal(infos)
if err != nil {
return ""
} else {
@@ -65,13 +62,113 @@ func (info *FileInfo) ToJson() string {
}
}
-func FileInfoFromJson(data io.Reader) *FileInfo {
+func FileInfosFromJson(data io.Reader) []*FileInfo {
decoder := json.NewDecoder(data)
- var info FileInfo
- if err := decoder.Decode(&info); err != nil {
+ var infos []*FileInfo
+ if err := decoder.Decode(&infos); err != nil {
return nil
} else {
- return &info
+ return infos
+ }
+}
+
+func (o *FileInfo) PreSave() {
+ if o.Id == "" {
+ o.Id = NewId()
+ }
+
+ if o.CreateAt == 0 {
+ o.CreateAt = GetMillis()
+ o.UpdateAt = o.CreateAt
+ }
+}
+
+func (o *FileInfo) IsValid() *AppError {
+ if len(o.Id) != 26 {
+ return NewLocAppError("FileInfo.IsValid", "model.file_info.is_valid.id.app_error", nil, "")
+ }
+
+ if len(o.CreatorId) != 26 {
+ return NewLocAppError("FileInfo.IsValid", "model.file_info.is_valid.user_id.app_error", nil, "id="+o.Id)
+ }
+
+ if len(o.PostId) != 0 && len(o.PostId) != 26 {
+ return NewLocAppError("FileInfo.IsValid", "model.file_info.is_valid.post_id.app_error", nil, "id="+o.Id)
+ }
+
+ if o.CreateAt == 0 {
+ return NewLocAppError("FileInfo.IsValid", "model.file_info.is_valid.create_at.app_error", nil, "id="+o.Id)
+ }
+
+ if o.UpdateAt == 0 {
+ return NewLocAppError("FileInfo.IsValid", "model.file_info.is_valid.update_at.app_error", nil, "id="+o.Id)
+ }
+
+ if o.Path == "" {
+ return NewLocAppError("FileInfo.IsValid", "model.file_info.is_valid.path.app_error", nil, "id="+o.Id)
}
+
+ return nil
+}
+
+func (o *FileInfo) IsImage() bool {
+ return strings.HasPrefix(o.MimeType, "image")
+}
+
+func GetInfoForBytes(name string, data []byte) (*FileInfo, *AppError) {
+ info := &FileInfo{
+ Name: name,
+ Size: int64(len(data)),
+ }
+ var err *AppError
+
+ extension := strings.ToLower(filepath.Ext(name))
+ info.MimeType = mime.TypeByExtension(extension)
+
+ if extension != "" && extension[0] == '.' {
+ // The client expects a file extension without the leading period
+ info.Extension = extension[1:]
+ } else {
+ info.Extension = extension
+ }
+
+ if info.IsImage() {
+ // Only set the width and height if it's actually an image that we can understand
+ if config, _, err := image.DecodeConfig(bytes.NewReader(data)); err == nil {
+ info.Width = config.Width
+ info.Height = config.Height
+
+ if info.MimeType == "image/gif" {
+ // Just show the gif itself instead of a preview image for animated gifs
+ if gifConfig, err := gif.DecodeAll(bytes.NewReader(data)); err != nil {
+ // Still return the rest of the info even though it doesn't appear to be an actual gif
+ info.HasPreviewImage = true
+ err = NewLocAppError("GetInfoForBytes", "model.file_info.get.gif.app_error", nil, "name="+name)
+ } else {
+ info.HasPreviewImage = len(gifConfig.Image) == 1
+ }
+ } else {
+ info.HasPreviewImage = true
+ }
+ }
+ }
+
+ return info, err
+}
+
+func GetEtagForFileInfos(infos []*FileInfo) string {
+ if len(infos) == 0 {
+ return Etag()
+ }
+
+ var maxUpdateAt int64
+
+ for _, info := range infos {
+ if info.UpdateAt > maxUpdateAt {
+ maxUpdateAt = info.UpdateAt
+ }
+ }
+
+ return Etag(infos[0].PostId, maxUpdateAt)
}
diff --git a/vendor/github.com/mattermost/platform/model/initial_load.go b/vendor/github.com/mattermost/platform/model/initial_load.go
index d7587e6d..afb0a276 100644
--- a/vendor/github.com/mattermost/platform/model/initial_load.go
+++ b/vendor/github.com/mattermost/platform/model/initial_load.go
@@ -9,14 +9,13 @@ import (
)
type InitialLoad struct {
- User *User `json:"user"`
- TeamMembers []*TeamMember `json:"team_members"`
- Teams []*Team `json:"teams"`
- DirectProfiles map[string]*User `json:"direct_profiles"`
- Preferences Preferences `json:"preferences"`
- ClientCfg map[string]string `json:"client_cfg"`
- LicenseCfg map[string]string `json:"license_cfg"`
- NoAccounts bool `json:"no_accounts"`
+ User *User `json:"user"`
+ TeamMembers []*TeamMember `json:"team_members"`
+ Teams []*Team `json:"teams"`
+ Preferences Preferences `json:"preferences"`
+ ClientCfg map[string]string `json:"client_cfg"`
+ LicenseCfg map[string]string `json:"license_cfg"`
+ NoAccounts bool `json:"no_accounts"`
}
func (me *InitialLoad) ToJson() string {
diff --git a/vendor/github.com/mattermost/platform/model/license.go b/vendor/github.com/mattermost/platform/model/license.go
index 1fce1eeb..8d8d0068 100644
--- a/vendor/github.com/mattermost/platform/model/license.go
+++ b/vendor/github.com/mattermost/platform/model/license.go
@@ -43,7 +43,8 @@ type Features struct {
MHPNS *bool `json:"mhpns"`
SAML *bool `json:"saml"`
PasswordRequirements *bool `json:"password_requirements"`
- FutureFeatures *bool `json:"future_features"`
+ // after we enabled more features for webrtc we'll need to control them with this
+ FutureFeatures *bool `json:"future_features"`
}
func (f *Features) ToMap() map[string]interface{} {
diff --git a/vendor/github.com/mattermost/platform/model/post.go b/vendor/github.com/mattermost/platform/model/post.go
index 33caeb9e..da14b650 100644
--- a/vendor/github.com/mattermost/platform/model/post.go
+++ b/vendor/github.com/mattermost/platform/model/post.go
@@ -35,7 +35,8 @@ type Post struct {
Type string `json:"type"`
Props StringInterface `json:"props"`
Hashtags string `json:"hashtags"`
- Filenames StringArray `json:"filenames"`
+ Filenames StringArray `json:"filenames,omitempty"` // Deprecated, do not use this field any more
+ FileIds StringArray `json:"file_ids,omitempty"`
PendingPostId string `json:"pending_post_id" db:"-"`
}
@@ -118,6 +119,10 @@ func (o *Post) IsValid() *AppError {
return NewLocAppError("Post.IsValid", "model.post.is_valid.filenames.app_error", nil, "id="+o.Id)
}
+ if utf8.RuneCountInString(ArrayToJson(o.FileIds)) > 150 {
+ return NewLocAppError("Post.IsValid", "model.post.is_valid.file_ids.app_error", nil, "id="+o.Id)
+ }
+
if utf8.RuneCountInString(StringInterfaceToJson(o.Props)) > 8000 {
return NewLocAppError("Post.IsValid", "model.post.is_valid.props.app_error", nil, "id="+o.Id)
}
@@ -145,15 +150,16 @@ func (o *Post) PreSave() {
if o.Filenames == nil {
o.Filenames = []string{}
}
+
+ if o.FileIds == nil {
+ o.FileIds = []string{}
+ }
}
func (o *Post) MakeNonNil() {
if o.Props == nil {
o.Props = make(map[string]interface{})
}
- if o.Filenames == nil {
- o.Filenames = []string{}
- }
}
func (o *Post) AddProp(key string, value interface{}) {
diff --git a/vendor/github.com/mattermost/platform/model/session.go b/vendor/github.com/mattermost/platform/model/session.go
index e8b04fbe..a6a753e7 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 = 10000
+ SESSION_CACHE_SIZE = 25000
SESSION_PROP_PLATFORM = "platform"
SESSION_PROP_OS = "os"
SESSION_PROP_BROWSER = "browser"
@@ -115,6 +115,10 @@ func (me *Session) IsMobileApp() bool {
(strings.HasPrefix(me.DeviceId, PUSH_NOTIFY_APPLE+":") || strings.HasPrefix(me.DeviceId, PUSH_NOTIFY_ANDROID+":"))
}
+func (me *Session) GetUserRoles() []string {
+ return strings.Fields(me.Roles)
+}
+
func SessionsToJson(o []*Session) string {
if b, err := json.Marshal(o); err != nil {
return "[]"
diff --git a/vendor/github.com/mattermost/platform/model/status.go b/vendor/github.com/mattermost/platform/model/status.go
index f4ad8e77..32486642 100644
--- a/vendor/github.com/mattermost/platform/model/status.go
+++ b/vendor/github.com/mattermost/platform/model/status.go
@@ -12,8 +12,9 @@ const (
STATUS_OFFLINE = "offline"
STATUS_AWAY = "away"
STATUS_ONLINE = "online"
- STATUS_CACHE_SIZE = 10000
- STATUS_CHANNEL_TIMEOUT = 20000 // 20 seconds
+ STATUS_CACHE_SIZE = 25000
+ STATUS_CHANNEL_TIMEOUT = 20000 // 20 seconds
+ STATUS_MIN_UPDATE_TIME = 120000 // 2 minutes
)
type Status struct {
diff --git a/vendor/github.com/mattermost/platform/model/team.go b/vendor/github.com/mattermost/platform/model/team.go
index dccc0219..d54a809f 100644
--- a/vendor/github.com/mattermost/platform/model/team.go
+++ b/vendor/github.com/mattermost/platform/model/team.go
@@ -100,7 +100,7 @@ func (o *Team) Etag() string {
return Etag(o.Id, o.UpdateAt)
}
-func (o *Team) IsValid(restrictTeamNames bool) *AppError {
+func (o *Team) IsValid() *AppError {
if len(o.Id) != 26 {
return NewLocAppError("Team.IsValid", "model.team.is_valid.id.app_error", nil, "")
@@ -130,7 +130,7 @@ func (o *Team) IsValid(restrictTeamNames bool) *AppError {
return NewLocAppError("Team.IsValid", "model.team.is_valid.url.app_error", nil, "id="+o.Id)
}
- if restrictTeamNames && IsReservedTeamName(o.Name) {
+ if IsReservedTeamName(o.Name) {
return NewLocAppError("Team.IsValid", "model.team.is_valid.reserved.app_error", nil, "id="+o.Id)
}
@@ -188,7 +188,7 @@ func IsValidTeamName(s string) bool {
return false
}
- if len(s) <= 3 {
+ if len(s) <= 1 {
return false
}
diff --git a/vendor/github.com/mattermost/platform/model/team_member.go b/vendor/github.com/mattermost/platform/model/team_member.go
index 7d932dec..a040e916 100644
--- a/vendor/github.com/mattermost/platform/model/team_member.go
+++ b/vendor/github.com/mattermost/platform/model/team_member.go
@@ -9,10 +9,6 @@ import (
"strings"
)
-const (
- ROLE_TEAM_ADMIN = "admin"
-)
-
type TeamMember struct {
TeamId string `json:"team_id"`
UserId string `json:"user_id"`
@@ -59,48 +55,6 @@ func TeamMembersFromJson(data io.Reader) []*TeamMember {
}
}
-func IsValidTeamRoles(teamRoles string) bool {
-
- roles := strings.Split(teamRoles, " ")
-
- for _, r := range roles {
- if !isValidTeamRole(r) {
- return false
- }
- }
-
- return true
-}
-
-func isValidTeamRole(role string) bool {
- if role == "" {
- return true
- }
-
- if role == ROLE_TEAM_ADMIN {
- return true
- }
-
- return false
-}
-
-func IsInTeamRole(teamRoles string, inRole string) bool {
- roles := strings.Split(teamRoles, " ")
-
- for _, r := range roles {
- if r == inRole {
- return true
- }
-
- }
-
- return false
-}
-
-func (o *TeamMember) IsTeamAdmin() bool {
- return IsInTeamRole(o.Roles, ROLE_TEAM_ADMIN)
-}
-
func (o *TeamMember) IsValid() *AppError {
if len(o.TeamId) != 26 {
@@ -111,11 +65,12 @@ func (o *TeamMember) IsValid() *AppError {
return NewLocAppError("TeamMember.IsValid", "model.team_member.is_valid.user_id.app_error", nil, "")
}
- for _, role := range strings.Split(o.Roles, " ") {
- if !(role == "" || role == ROLE_TEAM_ADMIN) {
- return NewLocAppError("TeamMember.IsValid", "model.team_member.is_valid.role.app_error", nil, "role="+role)
- }
- }
-
return nil
}
+
+func (o *TeamMember) PreUpdate() {
+}
+
+func (o *TeamMember) GetRoles() []string {
+ return strings.Fields(o.Roles)
+}
diff --git a/vendor/github.com/mattermost/platform/model/team_stats.go b/vendor/github.com/mattermost/platform/model/team_stats.go
new file mode 100644
index 00000000..9042e76d
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/team_stats.go
@@ -0,0 +1,35 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+)
+
+type TeamStats struct {
+ TeamId string `json:"team_id"`
+ TotalMemberCount int64 `json:"total_member_count"`
+ ActiveMemberCount int64 `json:"active_member_count"`
+}
+
+func (o *TeamStats) ToJson() string {
+ b, err := json.Marshal(o)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func TeamStatsFromJson(data io.Reader) *TeamStats {
+ decoder := json.NewDecoder(data)
+ var o TeamStats
+ err := decoder.Decode(&o)
+ if err == nil {
+ return &o
+ } else {
+ return nil
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/user.go b/vendor/github.com/mattermost/platform/model/user.go
index 680bc48c..330d26d8 100644
--- a/vendor/github.com/mattermost/platform/model/user.go
+++ b/vendor/github.com/mattermost/platform/model/user.go
@@ -15,7 +15,6 @@ import (
)
const (
- ROLE_SYSTEM_ADMIN = "system_admin"
USER_NOTIFY_ALL = "all"
USER_NOTIFY_MENTION = "mention"
USER_NOTIFY_NONE = "none"
@@ -233,14 +232,15 @@ func (u *User) Sanitize(options map[string]bool) {
if len(options) != 0 && !options["passwordupdate"] {
u.LastPasswordUpdate = 0
}
+ if len(options) != 0 && !options["authservice"] {
+ u.AuthService = ""
+ }
}
func (u *User) ClearNonProfileFields() {
u.Password = ""
u.AuthData = new(string)
*u.AuthData = ""
- u.AuthService = ""
- u.MfaActive = false
u.MfaSecret = ""
u.EmailVerified = false
u.AllowMarketing = false
@@ -319,9 +319,17 @@ func (u *User) GetDisplayNameForPreference(nameFormat string) string {
return displayName
}
+func (u *User) GetRoles() []string {
+ return strings.Fields(u.Roles)
+}
+
+func (u *User) GetRawRoles() string {
+ return u.Roles
+}
+
func IsValidUserRoles(userRoles string) bool {
- roles := strings.Split(userRoles, " ")
+ roles := strings.Fields(userRoles)
for _, r := range roles {
if !isValidRole(r) {
@@ -329,19 +337,17 @@ func IsValidUserRoles(userRoles string) bool {
}
}
- return true
-}
-
-func isValidRole(role string) bool {
- if role == "" {
- return true
+ // Exclude just the system_admin role explicitly to prevent mistakes
+ if len(roles) == 1 && roles[0] == "system_admin" {
+ return false
}
- if role == ROLE_SYSTEM_ADMIN {
- return true
- }
+ return true
+}
- return false
+func isValidRole(roleId string) bool {
+ _, ok := BuiltInRoles[roleId]
+ return ok
}
// Make sure you acually want to use this function. In context.go there are functions to check permissions
@@ -411,6 +417,26 @@ func UserMapFromJson(data io.Reader) map[string]*User {
}
}
+func UserListToJson(u []*User) string {
+ b, err := json.Marshal(u)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func UserListFromJson(data io.Reader) []*User {
+ decoder := json.NewDecoder(data)
+ var users []*User
+ err := decoder.Decode(&users)
+ if err == nil {
+ return users
+ } else {
+ return nil
+ }
+}
+
// HashPassword generates a hash using the bcrypt.GenerateFromPassword
func HashPassword(password string) string {
hash, err := bcrypt.GenerateFromPassword([]byte(password), 10)
diff --git a/vendor/github.com/mattermost/platform/model/user_search.go b/vendor/github.com/mattermost/platform/model/user_search.go
new file mode 100644
index 00000000..4bbd2bd7
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/user_search.go
@@ -0,0 +1,39 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+)
+
+type UserSearch struct {
+ Term string `json:"term"`
+ TeamId string `json:"team_id"`
+ InChannelId string `json:"in_channel_id"`
+ NotInChannelId string `json:"not_in_channel_id"`
+ AllowInactive bool `json:"allow_inactive"`
+}
+
+// ToJson convert a User to a json string
+func (u *UserSearch) ToJson() string {
+ b, err := json.Marshal(u)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+// UserSearchFromJson will decode the input and return a User
+func UserSearchFromJson(data io.Reader) *UserSearch {
+ decoder := json.NewDecoder(data)
+ var us UserSearch
+ err := decoder.Decode(&us)
+ if err == nil {
+ return &us
+ } else {
+ return nil
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/utils.go b/vendor/github.com/mattermost/platform/model/utils.go
index a4a4208c..457b64c0 100644
--- a/vendor/github.com/mattermost/platform/model/utils.go
+++ b/vendor/github.com/mattermost/platform/model/utils.go
@@ -10,6 +10,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/ioutil"
"net/mail"
"net/url"
"regexp"
@@ -74,13 +75,21 @@ func (er *AppError) ToJson() string {
// AppErrorFromJson will decode the input and return an AppError
func AppErrorFromJson(data io.Reader) *AppError {
- decoder := json.NewDecoder(data)
+ str := ""
+ bytes, rerr := ioutil.ReadAll(data)
+ if rerr != nil {
+ str = rerr.Error()
+ } else {
+ str = string(bytes)
+ }
+
+ decoder := json.NewDecoder(strings.NewReader(str))
var er AppError
err := decoder.Decode(&er)
if err == nil {
return &er
} else {
- return NewLocAppError("AppErrorFromJson", "model.utils.decode_json.app_error", nil, err.Error())
+ return NewLocAppError("AppErrorFromJson", "model.utils.decode_json.app_error", nil, "body: "+str)
}
}
@@ -166,6 +175,23 @@ func ArrayFromJson(data io.Reader) []string {
}
}
+func ArrayFromInterface(data interface{}) []string {
+ stringArray := []string{}
+
+ dataArray, ok := data.([]interface{})
+ if !ok {
+ return stringArray
+ }
+
+ for _, v := range dataArray {
+ if str, ok := v.(string); ok {
+ stringArray = append(stringArray, str)
+ }
+ }
+
+ return stringArray
+}
+
func StringInterfaceToJson(objmap map[string]interface{}) string {
if b, err := json.Marshal(objmap); err != nil {
return ""
@@ -227,58 +253,15 @@ func IsValidEmail(email string) bool {
}
var reservedName = []string{
- "www",
- "web",
+ "signup",
+ "login",
"admin",
- "support",
- "notify",
- "test",
- "demo",
- "mail",
- "team",
"channel",
- "internal",
- "localhost",
- "dockerhost",
- "stag",
"post",
- "cluster",
"api",
"oauth",
}
-var wwwStart = regexp.MustCompile(`^www`)
-var betaStart = regexp.MustCompile(`^beta`)
-var ciStart = regexp.MustCompile(`^ci`)
-
-func GetSubDomain(s string) (string, string) {
- s = strings.Replace(s, "http://", "", 1)
- s = strings.Replace(s, "https://", "", 1)
-
- match := wwwStart.MatchString(s)
- if match {
- return "", ""
- }
-
- match = betaStart.MatchString(s)
- if match {
- return "", ""
- }
-
- match = ciStart.MatchString(s)
- if match {
- return "", ""
- }
-
- parts := strings.Split(s, ".")
-
- if len(parts) != 3 {
- return "", ""
- }
-
- return parts[0], parts[1]
-}
-
func IsValidChannelIdentifier(s string) bool {
if !IsValidAlphaNum(s, true) {
@@ -413,6 +396,18 @@ func IsValidHttpsUrl(rawUrl string) bool {
return true
}
+func IsValidTurnOrStunServer(rawUri string) bool {
+ if strings.Index(rawUri, "turn:") != 0 && strings.Index(rawUri, "stun:") != 0 {
+ return false
+ }
+
+ if _, err := url.ParseRequestURI(rawUri); err != nil {
+ return false
+ }
+
+ return true
+}
+
func IsSafeLink(link *string) bool {
if link != nil {
if IsValidHttpUrl(*link) {
@@ -426,3 +421,15 @@ func IsSafeLink(link *string) bool {
return true
}
+
+func IsValidWebsocketUrl(rawUrl string) bool {
+ if strings.Index(rawUrl, "ws://") != 0 && strings.Index(rawUrl, "wss://") != 0 {
+ return false
+ }
+
+ if _, err := url.ParseRequestURI(rawUrl); err != nil {
+ return false
+ }
+
+ return true
+}
diff --git a/vendor/github.com/mattermost/platform/model/version.go b/vendor/github.com/mattermost/platform/model/version.go
index 6a0072cd..9d9d8fc1 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.5.0",
"3.4.0",
"3.3.0",
"3.2.0",
diff --git a/vendor/github.com/mattermost/platform/model/webrtc.go b/vendor/github.com/mattermost/platform/model/webrtc.go
new file mode 100644
index 00000000..e746d62a
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/webrtc.go
@@ -0,0 +1,21 @@
+package model
+
+import (
+ "encoding/json"
+ "io"
+)
+
+type GatewayResponse struct {
+ Status string `json:"janus"`
+}
+
+func GatewayResponseFromJson(data io.Reader) *GatewayResponse {
+ decoder := json.NewDecoder(data)
+ var o GatewayResponse
+ err := decoder.Decode(&o)
+ if err == nil {
+ return &o
+ } else {
+ return nil
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/websocket_client.go b/vendor/github.com/mattermost/platform/model/websocket_client.go
index a048bd85..453ae49b 100644
--- a/vendor/github.com/mattermost/platform/model/websocket_client.go
+++ b/vendor/github.com/mattermost/platform/model/websocket_client.go
@@ -6,7 +6,6 @@ package model
import (
"encoding/json"
"github.com/gorilla/websocket"
- "net/http"
)
type WebSocketClient struct {
@@ -17,19 +16,18 @@ type WebSocketClient struct {
Sequence int64 // The ever-incrementing sequence attached to each WebSocket action
EventChannel chan *WebSocketEvent
ResponseChannel chan *WebSocketResponse
+ ListenError *AppError
}
// NewWebSocketClient constructs a new WebSocket client with convienence
// methods for talking to the server.
func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
- header := http.Header{}
- header.Set(HEADER_AUTH, "BEARER "+authToken)
- conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX+"/users/websocket", header)
+ conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX+"/users/websocket", nil)
if err != nil {
return nil, NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
}
- return &WebSocketClient{
+ client := &WebSocketClient{
url,
url + API_URL_SUFFIX,
conn,
@@ -37,19 +35,26 @@ func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
1,
make(chan *WebSocketEvent, 100),
make(chan *WebSocketResponse, 100),
- }, nil
+ nil,
+ }
+
+ client.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": authToken})
+
+ return client, nil
}
func (wsc *WebSocketClient) Connect() *AppError {
- header := http.Header{}
- header.Set(HEADER_AUTH, "BEARER "+wsc.AuthToken)
-
var err error
- wsc.Conn, _, err = websocket.DefaultDialer.Dial(wsc.ApiUrl+"/users/websocket", header)
+ wsc.Conn, _, err = websocket.DefaultDialer.Dial(wsc.ApiUrl+"/users/websocket", nil)
if err != nil {
return NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
}
+ wsc.EventChannel = make(chan *WebSocketEvent, 100)
+ wsc.ResponseChannel = make(chan *WebSocketResponse, 100)
+
+ wsc.SendMessage(WEBSOCKET_AUTHENTICATION_CHALLENGE, map[string]interface{}{"token": wsc.AuthToken})
+
return nil
}
@@ -59,10 +64,20 @@ func (wsc *WebSocketClient) Close() {
func (wsc *WebSocketClient) Listen() {
go func() {
+ defer func() {
+ wsc.Conn.Close()
+ close(wsc.EventChannel)
+ close(wsc.ResponseChannel)
+ }()
+
for {
var rawMsg json.RawMessage
var err error
if _, rawMsg, err = wsc.Conn.ReadMessage(); err != nil {
+ if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
+ wsc.ListenError = NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
+ }
+
return
}
@@ -77,6 +92,7 @@ func (wsc *WebSocketClient) Listen() {
wsc.ResponseChannel <- &response
continue
}
+
}
}()
}
@@ -107,3 +123,12 @@ func (wsc *WebSocketClient) UserTyping(channelId, parentId string) {
func (wsc *WebSocketClient) GetStatuses() {
wsc.SendMessage("get_statuses", nil)
}
+
+// GetStatusesByIds will fetch certain user statuses based on ids and return
+// a map of string statuses using user id as the key
+func (wsc *WebSocketClient) GetStatusesByIds(userIds []string) {
+ data := map[string]interface{}{
+ "user_ids": userIds,
+ }
+ wsc.SendMessage("get_statuses_by_ids", data)
+}
diff --git a/vendor/github.com/mattermost/platform/model/websocket_message.go b/vendor/github.com/mattermost/platform/model/websocket_message.go
index 18e070af..5eb02642 100644
--- a/vendor/github.com/mattermost/platform/model/websocket_message.go
+++ b/vendor/github.com/mattermost/platform/model/websocket_message.go
@@ -25,33 +25,57 @@ const (
WEBSOCKET_EVENT_EPHEMERAL_MESSAGE = "ephemeral_message"
WEBSOCKET_EVENT_STATUS_CHANGE = "status_change"
WEBSOCKET_EVENT_HELLO = "hello"
+ WEBSOCKET_EVENT_WEBRTC = "webrtc"
+ WEBSOCKET_AUTHENTICATION_CHALLENGE = "authentication_challenge"
)
type WebSocketMessage interface {
ToJson() string
IsValid() bool
+ DoPreComputeJson()
+ GetPreComputeJson() []byte
+}
+
+type WebsocketBroadcast struct {
+ OmitUsers map[string]bool `json:"omit_users"` // broadcast is omitted for users listed here
+ UserId string `json:"user_id"` // broadcast only occurs for this user
+ ChannelId string `json:"channel_id"` // broadcast only occurs for users in this channel
+ TeamId string `json:"team_id"` // broadcast only occurs for users in this team
}
type WebSocketEvent struct {
- TeamId string `json:"team_id"`
- ChannelId string `json:"channel_id"`
- UserId string `json:"user_id"`
- Event string `json:"event"`
- Data map[string]interface{} `json:"data"`
+ Event string `json:"event"`
+ Data map[string]interface{} `json:"data"`
+ Broadcast *WebsocketBroadcast `json:"broadcast"`
+ PreComputeJson []byte `json:"-"`
}
func (m *WebSocketEvent) Add(key string, value interface{}) {
m.Data[key] = value
}
-func NewWebSocketEvent(teamId string, channelId string, userId string, event string) *WebSocketEvent {
- return &WebSocketEvent{TeamId: teamId, ChannelId: channelId, UserId: userId, Event: event, Data: make(map[string]interface{})}
+func NewWebSocketEvent(event, teamId, channelId, userId string, omitUsers map[string]bool) *WebSocketEvent {
+ return &WebSocketEvent{Event: event, Data: make(map[string]interface{}),
+ Broadcast: &WebsocketBroadcast{TeamId: teamId, ChannelId: channelId, UserId: userId, OmitUsers: omitUsers}}
}
func (o *WebSocketEvent) IsValid() bool {
return o.Event != ""
}
+func (o *WebSocketEvent) DoPreComputeJson() {
+ b, err := json.Marshal(o)
+ if err != nil {
+ o.PreComputeJson = []byte("")
+ } else {
+ o.PreComputeJson = b
+ }
+}
+
+func (o *WebSocketEvent) GetPreComputeJson() []byte {
+ return o.PreComputeJson
+}
+
func (o *WebSocketEvent) ToJson() string {
b, err := json.Marshal(o)
if err != nil {
@@ -73,10 +97,11 @@ func WebSocketEventFromJson(data io.Reader) *WebSocketEvent {
}
type WebSocketResponse struct {
- Status string `json:"status"`
- SeqReply int64 `json:"seq_reply,omitempty"`
- Data map[string]interface{} `json:"data,omitempty"`
- Error *AppError `json:"error,omitempty"`
+ Status string `json:"status"`
+ SeqReply int64 `json:"seq_reply,omitempty"`
+ Data map[string]interface{} `json:"data,omitempty"`
+ Error *AppError `json:"error,omitempty"`
+ PreComputeJson []byte `json:"-"`
}
func (m *WebSocketResponse) Add(key string, value interface{}) {
@@ -104,6 +129,19 @@ func (o *WebSocketResponse) ToJson() string {
}
}
+func (o *WebSocketResponse) DoPreComputeJson() {
+ b, err := json.Marshal(o)
+ if err != nil {
+ o.PreComputeJson = []byte("")
+ } else {
+ o.PreComputeJson = b
+ }
+}
+
+func (o *WebSocketResponse) GetPreComputeJson() []byte {
+ return o.PreComputeJson
+}
+
func WebSocketResponseFromJson(data io.Reader) *WebSocketResponse {
decoder := json.NewDecoder(data)
var o WebSocketResponse