Sync with mattermost 3.5.0
This commit is contained in:
parent
08ebee6b4f
commit
1d5cd1d7c4
|
@ -153,7 +153,7 @@ func (b *Bmattermost) handleMatterClient(mchan chan *MMMessage) {
|
||||||
for message := range b.mc.MessageChan {
|
for message := range b.mc.MessageChan {
|
||||||
// do not post our own messages back to irc
|
// do not post our own messages back to irc
|
||||||
// only listen to message from our team
|
// only listen to message from our team
|
||||||
if message.Raw.Event == "posted" && b.mc.User.Username != message.Username && message.Raw.TeamId == b.TeamId {
|
if message.Raw.Event == "posted" && b.mc.User.Username != message.Username && message.Raw.Data["team_id"].(string) == b.TeamId {
|
||||||
flog.Debugf("Receiving from matterclient %#v", message)
|
flog.Debugf("Receiving from matterclient %#v", message)
|
||||||
m := &MMMessage{}
|
m := &MMMessage{}
|
||||||
m.Username = message.Username
|
m.Username = message.Username
|
||||||
|
|
|
@ -264,7 +264,7 @@ func (m *MMClient) parseActionPost(rmsg *Message) {
|
||||||
}
|
}
|
||||||
rmsg.Username = m.GetUser(data.UserId).Username
|
rmsg.Username = m.GetUser(data.UserId).Username
|
||||||
rmsg.Channel = m.GetChannelName(data.ChannelId)
|
rmsg.Channel = m.GetChannelName(data.ChannelId)
|
||||||
rmsg.Team = m.GetTeamName(rmsg.Raw.TeamId)
|
rmsg.Team = m.GetTeamName(rmsg.Raw.Data["team_id"].(string))
|
||||||
// direct message
|
// direct message
|
||||||
if rmsg.Raw.Data["channel_type"] == "D" {
|
if rmsg.Raw.Data["channel_type"] == "D" {
|
||||||
rmsg.Channel = m.GetUser(data.UserId).Username
|
rmsg.Channel = m.GetUser(data.UserId).Username
|
||||||
|
@ -275,7 +275,7 @@ func (m *MMClient) parseActionPost(rmsg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MMClient) UpdateUsers() error {
|
func (m *MMClient) UpdateUsers() error {
|
||||||
mmusers, err := m.Client.GetProfilesForDirectMessageList(m.Team.Id)
|
mmusers, err := m.Client.GetProfiles(0, 1000, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New(err.DetailedError)
|
return errors.New(err.DetailedError)
|
||||||
}
|
}
|
||||||
|
@ -305,7 +305,7 @@ func (m *MMClient) GetChannelName(channelId string) string {
|
||||||
m.RLock()
|
m.RLock()
|
||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
for _, t := range m.OtherTeams {
|
for _, t := range m.OtherTeams {
|
||||||
for _, channel := range append(t.Channels.Channels, t.MoreChannels.Channels...) {
|
for _, channel := range append(*t.Channels, *t.MoreChannels...) {
|
||||||
if channel.Id == channelId {
|
if channel.Id == channelId {
|
||||||
return channel.Name
|
return channel.Name
|
||||||
}
|
}
|
||||||
|
@ -322,7 +322,7 @@ func (m *MMClient) GetChannelId(name string, teamId string) string {
|
||||||
}
|
}
|
||||||
for _, t := range m.OtherTeams {
|
for _, t := range m.OtherTeams {
|
||||||
if t.Id == teamId {
|
if t.Id == teamId {
|
||||||
for _, channel := range append(t.Channels.Channels, t.MoreChannels.Channels...) {
|
for _, channel := range append(*t.Channels, *t.MoreChannels...) {
|
||||||
if channel.Name == name {
|
if channel.Name == name {
|
||||||
return channel.Id
|
return channel.Id
|
||||||
}
|
}
|
||||||
|
@ -336,7 +336,7 @@ func (m *MMClient) GetChannelHeader(channelId string) string {
|
||||||
m.RLock()
|
m.RLock()
|
||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
for _, t := range m.OtherTeams {
|
for _, t := range m.OtherTeams {
|
||||||
for _, channel := range append(t.Channels.Channels, t.MoreChannels.Channels...) {
|
for _, channel := range append(*t.Channels, *t.MoreChannels...) {
|
||||||
if channel.Id == channelId {
|
if channel.Id == channelId {
|
||||||
return channel.Header
|
return channel.Header
|
||||||
}
|
}
|
||||||
|
@ -354,7 +354,7 @@ func (m *MMClient) PostMessage(channelId string, text string) {
|
||||||
func (m *MMClient) JoinChannel(channelId string) error {
|
func (m *MMClient) JoinChannel(channelId string) error {
|
||||||
m.RLock()
|
m.RLock()
|
||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
for _, c := range m.Team.Channels.Channels {
|
for _, c := range *m.Team.Channels {
|
||||||
if c.Id == channelId {
|
if c.Id == channelId {
|
||||||
m.log.Debug("Not joining ", channelId, " already joined.")
|
m.log.Debug("Not joining ", channelId, " already joined.")
|
||||||
return nil
|
return nil
|
||||||
|
@ -397,7 +397,7 @@ func (m *MMClient) GetPublicLink(filename string) string {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return res.Data.(string)
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MMClient) GetPublicLinks(filenames []string) []string {
|
func (m *MMClient) GetPublicLinks(filenames []string) []string {
|
||||||
|
@ -407,7 +407,7 @@ func (m *MMClient) GetPublicLinks(filenames []string) []string {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
output = append(output, res.Data.(string))
|
output = append(output, res)
|
||||||
}
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
@ -432,15 +432,17 @@ func (m *MMClient) UpdateLastViewed(channelId string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MMClient) UsernamesInChannel(channelId string) []string {
|
func (m *MMClient) UsernamesInChannel(channelId string) []string {
|
||||||
ceiRes, err := m.Client.GetChannelExtraInfo(channelId, 5000, "")
|
res, err := m.Client.GetMyChannelMembers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.log.Errorf("UsernamesInChannel(%s) failed: %s", channelId, err)
|
m.log.Errorf("UsernamesInChannel(%s) failed: %s", channelId, err)
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
extra := ceiRes.Data.(*model.ChannelExtra)
|
members := res.Data.(*model.ChannelMembers)
|
||||||
result := []string{}
|
result := []string{}
|
||||||
for _, member := range extra.Members {
|
for _, channel := range *members {
|
||||||
result = append(result, member.Username)
|
if channel.ChannelId == channelId {
|
||||||
|
result = append(result, m.GetUser(channel.UserId).Username)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -500,10 +502,10 @@ func (m *MMClient) GetChannels() []*model.Channel {
|
||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
var channels []*model.Channel
|
var channels []*model.Channel
|
||||||
// our primary team channels first
|
// our primary team channels first
|
||||||
channels = append(channels, m.Team.Channels.Channels...)
|
channels = append(channels, *m.Team.Channels...)
|
||||||
for _, t := range m.OtherTeams {
|
for _, t := range m.OtherTeams {
|
||||||
if t.Id != m.Team.Id {
|
if t.Id != m.Team.Id {
|
||||||
channels = append(channels, t.Channels.Channels...)
|
channels = append(channels, *t.Channels...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return channels
|
return channels
|
||||||
|
@ -515,7 +517,7 @@ func (m *MMClient) GetMoreChannels() []*model.Channel {
|
||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
var channels []*model.Channel
|
var channels []*model.Channel
|
||||||
for _, t := range m.OtherTeams {
|
for _, t := range m.OtherTeams {
|
||||||
channels = append(channels, t.MoreChannels.Channels...)
|
channels = append(channels, *t.MoreChannels...)
|
||||||
}
|
}
|
||||||
return channels
|
return channels
|
||||||
}
|
}
|
||||||
|
@ -526,8 +528,8 @@ func (m *MMClient) GetTeamFromChannel(channelId string) string {
|
||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
var channels []*model.Channel
|
var channels []*model.Channel
|
||||||
for _, t := range m.OtherTeams {
|
for _, t := range m.OtherTeams {
|
||||||
channels = append(channels, t.Channels.Channels...)
|
channels = append(channels, *t.Channels...)
|
||||||
channels = append(channels, t.MoreChannels.Channels...)
|
channels = append(channels, *t.MoreChannels...)
|
||||||
for _, c := range channels {
|
for _, c := range channels {
|
||||||
if c.Id == channelId {
|
if c.Id == channelId {
|
||||||
return t.Id
|
return t.Id
|
||||||
|
@ -540,11 +542,13 @@ func (m *MMClient) GetTeamFromChannel(channelId string) string {
|
||||||
func (m *MMClient) GetLastViewedAt(channelId string) int64 {
|
func (m *MMClient) GetLastViewedAt(channelId string) int64 {
|
||||||
m.RLock()
|
m.RLock()
|
||||||
defer m.RUnlock()
|
defer m.RUnlock()
|
||||||
|
/*
|
||||||
for _, t := range m.OtherTeams {
|
for _, t := range m.OtherTeams {
|
||||||
if _, ok := t.Channels.Members[channelId]; ok {
|
if _, ok := t.Channels.Members[channelId]; ok {
|
||||||
return t.Channels.Members[channelId].LastViewedAt
|
return t.Channels.Members[channelId].LastViewedAt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,7 +623,7 @@ func (m *MMClient) initUser() error {
|
||||||
//m.log.Debug("initUser(): loading all team data")
|
//m.log.Debug("initUser(): loading all team data")
|
||||||
for _, v := range initData.Teams {
|
for _, v := range initData.Teams {
|
||||||
m.Client.SetTeamId(v.Id)
|
m.Client.SetTeamId(v.Id)
|
||||||
mmusers, _ := m.Client.GetProfiles(v.Id, "")
|
mmusers, _ := m.Client.GetProfiles(0, 1000, "")
|
||||||
t := &Team{Team: v, Users: mmusers.Data.(map[string]*model.User), Id: v.Id}
|
t := &Team{Team: v, Users: mmusers.Data.(map[string]*model.User), Id: v.Id}
|
||||||
mmchannels, _ := m.Client.GetChannels("")
|
mmchannels, _ := m.Client.GetChannels("")
|
||||||
t.Channels = mmchannels.Data.(*model.ChannelList)
|
t.Channels = mmchannels.Data.(*model.ChannelList)
|
||||||
|
|
|
@ -13,7 +13,6 @@ type ClusterInterface interface {
|
||||||
GetClusterInfos() []*model.ClusterInfo
|
GetClusterInfos() []*model.ClusterInfo
|
||||||
RemoveAllSessionsForUserId(userId string)
|
RemoveAllSessionsForUserId(userId string)
|
||||||
InvalidateCacheForUser(userId string)
|
InvalidateCacheForUser(userId string)
|
||||||
InvalidateCacheForChannel(channelId string)
|
|
||||||
Publish(event *model.WebSocketEvent)
|
Publish(event *model.WebSocketEvent)
|
||||||
UpdateStatus(status *model.Status)
|
UpdateStatus(status *model.Status)
|
||||||
GetLogs() ([]string, *model.AppError)
|
GetLogs() ([]string, *model.AppError)
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type MfaInterface interface {
|
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
|
Activate(user *model.User, token string) *model.AppError
|
||||||
Deactivate(userId string) *model.AppError
|
Deactivate(userId string) *model.AppError
|
||||||
ValidateToken(secret, token string) (bool, *model.AppError)
|
ValidateToken(secret, token string) (bool, *model.AppError)
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,10 @@ const (
|
||||||
CHANNEL_PRIVATE = "P"
|
CHANNEL_PRIVATE = "P"
|
||||||
CHANNEL_DIRECT = "D"
|
CHANNEL_DIRECT = "D"
|
||||||
DEFAULT_CHANNEL = "town-square"
|
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 {
|
type Channel struct {
|
||||||
|
@ -57,8 +61,8 @@ func (o *Channel) Etag() string {
|
||||||
return Etag(o.Id, o.UpdateAt)
|
return Etag(o.Id, o.UpdateAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Channel) ExtraEtag(memberLimit int) string {
|
func (o *Channel) StatsEtag() string {
|
||||||
return Etag(o.Id, o.ExtraUpdateAt, memberLimit)
|
return Etag(o.Id, o.ExtraUpdateAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Channel) IsValid() *AppError {
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.purpose.app_error", nil, "id="+o.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,15 +8,11 @@ import (
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ChannelList struct {
|
type ChannelList []*Channel
|
||||||
Channels []*Channel `json:"channels"`
|
|
||||||
Members map[string]*ChannelMember `json:"members"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *ChannelList) ToJson() string {
|
func (o *ChannelList) ToJson() string {
|
||||||
b, err := json.Marshal(o)
|
if b, err := json.Marshal(o); err != nil {
|
||||||
if err != nil {
|
return "[]"
|
||||||
return ""
|
|
||||||
} else {
|
} else {
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
@ -28,7 +24,7 @@ func (o *ChannelList) Etag() string {
|
||||||
var t int64 = 0
|
var t int64 = 0
|
||||||
var delta int64 = 0
|
var delta int64 = 0
|
||||||
|
|
||||||
for _, v := range o.Channels {
|
for _, v := range *o {
|
||||||
if v.LastPostAt > t {
|
if v.LastPostAt > t {
|
||||||
t = v.LastPostAt
|
t = v.LastPostAt
|
||||||
id = v.Id
|
id = v.Id
|
||||||
|
@ -39,30 +35,9 @@ func (o *ChannelList) Etag() string {
|
||||||
id = v.Id
|
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
|
return Etag(id, t, delta, len(*o))
|
||||||
|
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChannelListFromJson(data io.Reader) *ChannelList {
|
func ChannelListFromJson(data io.Reader) *ChannelList {
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CHANNEL_ROLE_ADMIN = "admin"
|
|
||||||
CHANNEL_NOTIFY_DEFAULT = "default"
|
CHANNEL_NOTIFY_DEFAULT = "default"
|
||||||
CHANNEL_NOTIFY_ALL = "all"
|
CHANNEL_NOTIFY_ALL = "all"
|
||||||
CHANNEL_NOTIFY_MENTION = "mention"
|
CHANNEL_NOTIFY_MENTION = "mention"
|
||||||
|
@ -30,6 +29,27 @@ type ChannelMember struct {
|
||||||
LastUpdateAt int64 `json:"last_update_at"`
|
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 {
|
func (o *ChannelMember) ToJson() string {
|
||||||
b, err := json.Marshal(o)
|
b, err := json.Marshal(o)
|
||||||
if err != nil {
|
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, "")
|
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"]
|
notifyLevel := o.NotifyProps["desktop"]
|
||||||
if len(notifyLevel) > 20 || !IsChannelNotifyLevelValid(notifyLevel) {
|
if len(notifyLevel) > 20 || !IsChannelNotifyLevelValid(notifyLevel) {
|
||||||
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.notify_level.app_error",
|
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.notify_level.app_error",
|
||||||
|
@ -89,6 +103,10 @@ func (o *ChannelMember) PreUpdate() {
|
||||||
o.LastUpdateAt = GetMillis()
|
o.LastUpdateAt = GetMillis()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *ChannelMember) GetRoles() []string {
|
||||||
|
return strings.Fields(o.Roles)
|
||||||
|
}
|
||||||
|
|
||||||
func IsChannelNotifyLevelValid(notifyLevel string) bool {
|
func IsChannelNotifyLevelValid(notifyLevel string) bool {
|
||||||
return notifyLevel == CHANNEL_NOTIFY_DEFAULT ||
|
return notifyLevel == CHANNEL_NOTIFY_DEFAULT ||
|
||||||
notifyLevel == CHANNEL_NOTIFY_ALL ||
|
notifyLevel == CHANNEL_NOTIFY_ALL ||
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -108,6 +108,10 @@ func (c *Client) GetChannelRoute(channelId string) string {
|
||||||
return fmt.Sprintf("/teams/%v/channels/%v", c.GetTeamId(), channelId)
|
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 {
|
func (c *Client) GetChannelNameRoute(channelName string) string {
|
||||||
return fmt.Sprintf("/teams/%v/channels/name/%v", c.GetTeamId(), channelName)
|
return fmt.Sprintf("/teams/%v/channels/name/%v", c.GetTeamId(), channelName)
|
||||||
}
|
}
|
||||||
|
@ -120,9 +124,14 @@ func (c *Client) GetGeneralRoute() string {
|
||||||
return "/general"
|
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) {
|
func (c *Client) DoPost(url, data, contentType string) (*http.Response, *AppError) {
|
||||||
rq, _ := http.NewRequest("POST", c.Url+url, strings.NewReader(data))
|
rq, _ := http.NewRequest("POST", c.Url+url, strings.NewReader(data))
|
||||||
rq.Header.Set("Content-Type", contentType)
|
rq.Header.Set("Content-Type", contentType)
|
||||||
|
rq.Close = true
|
||||||
|
|
||||||
if rp, err := c.HttpClient.Do(rq); err != nil {
|
if rp, err := c.HttpClient.Do(rq); err != nil {
|
||||||
return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
|
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) {
|
func (c *Client) DoApiPost(url string, data string) (*http.Response, *AppError) {
|
||||||
rq, _ := http.NewRequest("POST", c.ApiUrl+url, strings.NewReader(data))
|
rq, _ := http.NewRequest("POST", c.ApiUrl+url, strings.NewReader(data))
|
||||||
|
rq.Close = true
|
||||||
|
|
||||||
if len(c.AuthToken) > 0 {
|
if len(c.AuthToken) > 0 {
|
||||||
rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
|
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) {
|
func (c *Client) DoApiGet(url string, data string, etag string) (*http.Response, *AppError) {
|
||||||
rq, _ := http.NewRequest("GET", c.ApiUrl+url, strings.NewReader(data))
|
rq, _ := http.NewRequest("GET", c.ApiUrl+url, strings.NewReader(data))
|
||||||
|
rq.Close = true
|
||||||
|
|
||||||
if len(etag) > 0 {
|
if len(etag) > 0 {
|
||||||
rq.Header.Set(HEADER_ETAG_CLIENT, etag)
|
rq.Header.Set(HEADER_ETAG_CLIENT, etag)
|
||||||
|
@ -500,10 +511,9 @@ func (c *Client) GetMe(etag string) (*Result, *AppError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetProfilesForDirectMessageList returns a map of users for a team that can be direct
|
// GetProfiles returns a map of users using user id as the key. Must be authenticated.
|
||||||
// messaged, using user id as the key. Must be authenticated.
|
func (c *Client) GetProfiles(offset int, limit int, etag string) (*Result, *AppError) {
|
||||||
func (c *Client) GetProfilesForDirectMessageList(teamId string) (*Result, *AppError) {
|
if r, err := c.DoApiGet(fmt.Sprintf("/users/%v/%v", offset, limit), "", etag); err != nil {
|
||||||
if r, err := c.DoApiGet("/users/profiles_for_dm_list/"+teamId, "", ""); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
defer closeBody(r)
|
defer closeBody(r)
|
||||||
|
@ -512,10 +522,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
|
// GetProfilesInTeam returns a map of users for a team using user id as the key. Must
|
||||||
// be authenticated.
|
// be authenticated.
|
||||||
func (c *Client) GetProfiles(teamId string, etag string) (*Result, *AppError) {
|
func (c *Client) GetProfilesInTeam(teamId string, offset int, limit int, etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/profiles/"+teamId, "", etag); err != nil {
|
if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/users/%v/%v", teamId, offset, limit), "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
defer closeBody(r)
|
defer closeBody(r)
|
||||||
|
@ -524,10 +534,10 @@ func (c *Client) GetProfiles(teamId string, etag string) (*Result, *AppError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDirectProfiles gets a map of users that are currently shown in the sidebar,
|
// GetProfilesInChannel returns a map of users for a channel using user id as the key. Must
|
||||||
// using user id as the key. Must be authenticated.
|
// be authenticated.
|
||||||
func (c *Client) GetDirectProfiles(etag string) (*Result, *AppError) {
|
func (c *Client) GetProfilesInChannel(channelId string, offset int, limit int, etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet("/users/direct_profiles", "", etag); err != nil {
|
if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/users/%v/%v", offset, limit), "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
defer closeBody(r)
|
defer closeBody(r)
|
||||||
|
@ -536,6 +546,70 @@ func (c *Client) GetDirectProfiles(etag string) (*Result, *AppError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) 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)
|
||||||
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
|
r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, 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)
|
||||||
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
|
r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
// LoginById authenticates a user by user id and password.
|
||||||
func (c *Client) LoginById(id string, password string) (*Result, *AppError) {
|
func (c *Client) LoginById(id string, password string) (*Result, *AppError) {
|
||||||
m := make(map[string]string)
|
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
|
// GenerateMfaSecret returns a QR code image containing the secret, to be scanned
|
||||||
// by a multi-factor authentication mobile application. Must be authenticated.
|
// by a multi-factor authentication mobile application. It also returns the secret
|
||||||
func (c *Client) GenerateMfaQrCode() (*Result, *AppError) {
|
// for manual entry. Must be authenticated.
|
||||||
if r, err := c.DoApiGet("/users/generate_mfa_qr", "", ""); err != nil {
|
func (c *Client) GenerateMfaSecret() (*Result, *AppError) {
|
||||||
|
if r, err := c.DoApiGet("/users/generate_mfa_secret", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
defer closeBody(r)
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
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) {
|
func (c *Client) DownloadComplianceReport(id string) (*Result, *AppError) {
|
||||||
var rq *http.Request
|
var rq *http.Request
|
||||||
rq, _ = http.NewRequest("GET", c.ApiUrl+"/admin/download_compliance_report/"+id, nil)
|
rq, _ = http.NewRequest("GET", c.ApiUrl+"/admin/download_compliance_report/"+id, nil)
|
||||||
|
rq.Close = true
|
||||||
|
|
||||||
if len(c.AuthToken) > 0 {
|
if len(c.AuthToken) > 0 {
|
||||||
rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
|
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) {
|
func (c *Client) GetMyChannelMembers() (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/", "", etag); err != nil {
|
if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/members", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
defer closeBody(r)
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
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) {
|
func (c *Client) JoinChannel(id string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/join", ""); err != nil {
|
if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/join", ""); err != nil {
|
||||||
return nil, err
|
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) {
|
func (c *Client) GetChannelStats(id string, etag string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/extra_info/"+strconv.FormatInt(int64(memberLimit), 10), "", etag); err != nil {
|
if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/stats", "", etag); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
defer closeBody(r)
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), ChannelExtraFromJson(r.Body)}, nil
|
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), 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)
|
return c.uploadFile(c.ApiUrl+"/users/newimage", data, contentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) UploadPostAttachment(data []byte, contentType string) (*Result, *AppError) {
|
func (c *Client) UploadPostAttachment(data []byte, channelId string, filename string) (*FileUploadResponse, *AppError) {
|
||||||
return c.uploadFile(c.ApiUrl+c.GetTeamRoute()+"/files/upload", data, contentType)
|
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) {
|
func (c *Client) uploadFile(url string, data []byte, contentType string) (*Result, *AppError) {
|
||||||
rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
|
rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
|
||||||
rq.Header.Set("Content-Type", contentType)
|
rq.Header.Set("Content-Type", contentType)
|
||||||
|
rq.Close = true
|
||||||
|
|
||||||
if len(c.AuthToken) > 0 {
|
if len(c.AuthToken) > 0 {
|
||||||
rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
|
rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
|
||||||
|
@ -1308,55 +1430,51 @@ func (c *Client) uploadFile(url string, data []byte, contentType string) (*Resul
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) GetFile(url string, isFullUrl bool) (*Result, *AppError) {
|
func (c *Client) GetFile(fileId string) (io.ReadCloser, *AppError) {
|
||||||
var rq *http.Request
|
if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get", "", ""); err != nil {
|
||||||
if isFullUrl {
|
return nil, err
|
||||||
rq, _ = http.NewRequest("GET", url, nil)
|
|
||||||
} else {
|
} 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
} else {
|
|
||||||
defer closeBody(rp)
|
|
||||||
return &Result{rp.Header.Get(HEADER_REQUEST_ID),
|
|
||||||
rp.Header.Get(HEADER_ETAG_SERVER), rp.Body}, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) GetFileInfo(url string) (*Result, *AppError) {
|
func (c *Client) GetFileThumbnail(fileId string) (io.ReadCloser, *AppError) {
|
||||||
var rq *http.Request
|
if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_thumbnail", "", ""); err != nil {
|
||||||
rq, _ = http.NewRequest("GET", c.ApiUrl+c.GetTeamRoute()+"/files/get_info"+url, nil)
|
return nil, err
|
||||||
|
|
||||||
if len(c.AuthToken) > 0 {
|
|
||||||
rq.Header.Set(HEADER_AUTH, "BEARER "+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 >= 300 {
|
|
||||||
return nil, AppErrorFromJson(rp.Body)
|
|
||||||
} else {
|
} else {
|
||||||
defer closeBody(rp)
|
c.fillInExtraProperties(r)
|
||||||
return &Result{rp.Header.Get(HEADER_REQUEST_ID),
|
return r.Body, nil
|
||||||
rp.Header.Get(HEADER_ETAG_SERVER), FileInfoFromJson(rp.Body)}, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) GetPublicLink(filename string) (*Result, *AppError) {
|
func (c *Client) GetFilePreview(fileId string) (io.ReadCloser, *AppError) {
|
||||||
if r, err := c.DoApiPost(c.GetTeamRoute()+"/files/get_public_link", MapToJson(map[string]string{"filename": filename})); err != nil {
|
if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_preview", "", ""); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
defer closeBody(r)
|
defer closeBody(r)
|
||||||
return &Result{r.Header.Get(HEADER_REQUEST_ID),
|
c.fillInExtraProperties(r)
|
||||||
r.Header.Get(HEADER_ETAG_SERVER), StringFromJson(r.Body)}, nil
|
return r.Body, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(r)
|
||||||
|
c.fillInExtraProperties(r)
|
||||||
|
return StringFromJson(r.Body), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1370,8 +1488,25 @@ func (c *Client) UpdateUser(user *User) (*Result, *AppError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) UpdateUserRoles(data map[string]string) (*Result, *AppError) {
|
func (c *Client) UpdateUserRoles(userId string, roles string) (*Result, *AppError) {
|
||||||
if r, err := c.DoApiPost("/users/update_roles", MapToJson(data)); err != nil {
|
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), MapFromJson(r.Body)}, 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
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
defer closeBody(r)
|
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.
|
// SetActiveChannel sets the the channel id the user is currently viewing.
|
||||||
// The channelId key is required but the value can be blank. Returns standard
|
// The channelId key is required but the value can be blank. Returns standard
|
||||||
// response.
|
// response.
|
||||||
|
@ -1504,8 +1651,46 @@ func (c *Client) GetMyTeam(etag string) (*Result, *AppError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) GetTeamMembers(teamId string) (*Result, *AppError) {
|
// GetTeamMembers will return a page of team member objects as an array paged based on the
|
||||||
if r, err := c.DoApiGet("/teams/members/"+teamId, "", ""); err != nil {
|
// 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
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
defer closeBody(r)
|
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, _ := http.NewRequest("POST", c.ApiUrl+c.GetEmojiRoute()+"/create", body)
|
||||||
rq.Header.Set("Content-Type", writer.FormDataContentType())
|
rq.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
rq.Close = true
|
||||||
|
|
||||||
if len(c.AuthToken) > 0 {
|
if len(c.AuthToken) > 0 {
|
||||||
rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
|
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"
|
url := c.ApiUrl + "/admin/add_certificate"
|
||||||
rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
|
rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
|
||||||
rq.Header.Set("Content-Type", contentType)
|
rq.Header.Set("Content-Type", contentType)
|
||||||
|
rq.Close = true
|
||||||
|
|
||||||
if len(c.AuthToken) > 0 {
|
if len(c.AuthToken) > 0 {
|
||||||
rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
|
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
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ type CompliancePost struct {
|
||||||
PostType string
|
PostType string
|
||||||
PostProps string
|
PostProps string
|
||||||
PostHashtags string
|
PostHashtags string
|
||||||
PostFilenames string
|
PostFileIds string
|
||||||
}
|
}
|
||||||
|
|
||||||
func CompliancePostHeader() []string {
|
func CompliancePostHeader() []string {
|
||||||
|
@ -60,7 +60,7 @@ func CompliancePostHeader() []string {
|
||||||
"PostType",
|
"PostType",
|
||||||
"PostProps",
|
"PostProps",
|
||||||
"PostHashtags",
|
"PostHashtags",
|
||||||
"PostFilenames",
|
"PostFileIds",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,6 +99,6 @@ func (me *CompliancePost) Row() []string {
|
||||||
me.PostType,
|
me.PostType,
|
||||||
me.PostProps,
|
me.PostProps,
|
||||||
me.PostHashtags,
|
me.PostHashtags,
|
||||||
me.PostFilenames,
|
me.PostFileIds,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,14 @@ const (
|
||||||
type ServiceSettings struct {
|
type ServiceSettings struct {
|
||||||
SiteURL *string
|
SiteURL *string
|
||||||
ListenAddress string
|
ListenAddress string
|
||||||
|
ConnectionSecurity *string
|
||||||
|
TLSCertFile *string
|
||||||
|
TLSKeyFile *string
|
||||||
|
UseLetsEncrypt *bool
|
||||||
|
LetsEncryptCertificateCacheFile *string
|
||||||
|
Forward80To443 *bool
|
||||||
|
ReadTimeout *int
|
||||||
|
WriteTimeout *int
|
||||||
MaximumLoginAttempts int
|
MaximumLoginAttempts int
|
||||||
SegmentDeveloperKey string
|
SegmentDeveloperKey string
|
||||||
GoogleDeveloperKey string
|
GoogleDeveloperKey string
|
||||||
|
@ -147,9 +155,7 @@ type FileSettings struct {
|
||||||
AmazonS3Bucket string
|
AmazonS3Bucket string
|
||||||
AmazonS3Region string
|
AmazonS3Region string
|
||||||
AmazonS3Endpoint string
|
AmazonS3Endpoint string
|
||||||
AmazonS3BucketEndpoint string
|
AmazonS3SSL *bool
|
||||||
AmazonS3LocationConstraint *bool
|
|
||||||
AmazonS3LowercaseBucket *bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmailSettings struct {
|
type EmailSettings struct {
|
||||||
|
@ -177,8 +183,9 @@ type EmailSettings struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type RateLimitSettings struct {
|
type RateLimitSettings struct {
|
||||||
EnableRateLimiter bool
|
Enable *bool
|
||||||
PerSec int
|
PerSec int
|
||||||
|
MaxBurst *int
|
||||||
MemoryStoreSize int
|
MemoryStoreSize int
|
||||||
VaryByRemoteAddr bool
|
VaryByRemoteAddr bool
|
||||||
VaryByHeader string
|
VaryByHeader string
|
||||||
|
@ -205,7 +212,6 @@ type TeamSettings struct {
|
||||||
EnableUserCreation bool
|
EnableUserCreation bool
|
||||||
EnableOpenServer *bool
|
EnableOpenServer *bool
|
||||||
RestrictCreationToDomains string
|
RestrictCreationToDomains string
|
||||||
RestrictTeamNames *bool
|
|
||||||
EnableCustomBrand *bool
|
EnableCustomBrand *bool
|
||||||
CustomBrandText *string
|
CustomBrandText *string
|
||||||
CustomDescriptionText *string
|
CustomDescriptionText *string
|
||||||
|
@ -214,6 +220,7 @@ type TeamSettings struct {
|
||||||
RestrictPublicChannelManagement *string
|
RestrictPublicChannelManagement *string
|
||||||
RestrictPrivateChannelManagement *string
|
RestrictPrivateChannelManagement *string
|
||||||
UserStatusAwayTimeout *int64
|
UserStatusAwayTimeout *int64
|
||||||
|
MaxChannelsPerTeam *int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type LdapSettings struct {
|
type LdapSettings struct {
|
||||||
|
@ -292,6 +299,17 @@ type NativeAppSettings struct {
|
||||||
IosAppDownloadLink *string
|
IosAppDownloadLink *string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebrtcSettings struct {
|
||||||
|
Enable *bool
|
||||||
|
GatewayWebsocketUrl *string
|
||||||
|
GatewayAdminUrl *string
|
||||||
|
GatewayAdminSecret *string
|
||||||
|
StunURI *string
|
||||||
|
TurnURI *string
|
||||||
|
TurnUsername *string
|
||||||
|
TurnSharedKey *string
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ServiceSettings ServiceSettings
|
ServiceSettings ServiceSettings
|
||||||
TeamSettings TeamSettings
|
TeamSettings TeamSettings
|
||||||
|
@ -312,6 +330,7 @@ type Config struct {
|
||||||
SamlSettings SamlSettings
|
SamlSettings SamlSettings
|
||||||
NativeAppSettings NativeAppSettings
|
NativeAppSettings NativeAppSettings
|
||||||
ClusterSettings ClusterSettings
|
ClusterSettings ClusterSettings
|
||||||
|
WebrtcSettings WebrtcSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Config) ToJson() string {
|
func (o *Config) ToJson() string {
|
||||||
|
@ -353,26 +372,27 @@ func (o *Config) SetDefaults() {
|
||||||
o.SqlSettings.AtRestEncryptKey = NewRandomString(32)
|
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 {
|
if o.FileSettings.MaxFileSize == nil {
|
||||||
o.FileSettings.MaxFileSize = new(int64)
|
o.FileSettings.MaxFileSize = new(int64)
|
||||||
*o.FileSettings.MaxFileSize = 52428800 // 50 MB
|
*o.FileSettings.MaxFileSize = 52428800 // 50 MB
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(*o.FileSettings.PublicLinkSalt) == 0 {
|
if len(*o.FileSettings.PublicLinkSalt) == 0 {
|
||||||
o.FileSettings.PublicLinkSalt = new(string)
|
o.FileSettings.PublicLinkSalt = new(string)
|
||||||
*o.FileSettings.PublicLinkSalt = NewRandomString(32)
|
*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 {
|
if len(o.EmailSettings.InviteSalt) == 0 {
|
||||||
o.EmailSettings.InviteSalt = NewRandomString(32)
|
o.EmailSettings.InviteSalt = NewRandomString(32)
|
||||||
}
|
}
|
||||||
|
@ -431,11 +451,6 @@ func (o *Config) SetDefaults() {
|
||||||
*o.PasswordSettings.Symbol = false
|
*o.PasswordSettings.Symbol = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.TeamSettings.RestrictTeamNames == nil {
|
|
||||||
o.TeamSettings.RestrictTeamNames = new(bool)
|
|
||||||
*o.TeamSettings.RestrictTeamNames = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if o.TeamSettings.EnableCustomBrand == nil {
|
if o.TeamSettings.EnableCustomBrand == nil {
|
||||||
o.TeamSettings.EnableCustomBrand = new(bool)
|
o.TeamSettings.EnableCustomBrand = new(bool)
|
||||||
*o.TeamSettings.EnableCustomBrand = false
|
*o.TeamSettings.EnableCustomBrand = false
|
||||||
|
@ -481,6 +496,11 @@ func (o *Config) SetDefaults() {
|
||||||
*o.TeamSettings.UserStatusAwayTimeout = 300
|
*o.TeamSettings.UserStatusAwayTimeout = 300
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.TeamSettings.MaxChannelsPerTeam == nil {
|
||||||
|
o.TeamSettings.MaxChannelsPerTeam = new(int64)
|
||||||
|
*o.TeamSettings.MaxChannelsPerTeam = 2000
|
||||||
|
}
|
||||||
|
|
||||||
if o.EmailSettings.EnableSignInWithEmail == nil {
|
if o.EmailSettings.EnableSignInWithEmail == nil {
|
||||||
o.EmailSettings.EnableSignInWithEmail = new(bool)
|
o.EmailSettings.EnableSignInWithEmail = new(bool)
|
||||||
|
|
||||||
|
@ -881,6 +901,58 @@ func (o *Config) SetDefaults() {
|
||||||
o.NativeAppSettings.IosAppDownloadLink = new(string)
|
o.NativeAppSettings.IosAppDownloadLink = new(string)
|
||||||
*o.NativeAppSettings.IosAppDownloadLink = "https://about.mattermost.com/mattermost-ios-app/"
|
*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 {
|
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, "")
|
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) {
|
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, "")
|
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}, "")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1121,3 +1217,71 @@ func (o *Config) Sanitize() {
|
||||||
o.SqlSettings.DataSourceReplicas[i] = FAKE_SETTING
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileUploadResponse struct {
|
type FileUploadResponse struct {
|
||||||
Filenames []string `json:"filenames"`
|
FileInfos []*FileInfo `json:"file_infos"`
|
||||||
ClientIds []string `json:"client_ids"`
|
ClientIds []string `json:"client_ids"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,54 +6,31 @@ package model
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"image"
|
||||||
"image/gif"
|
"image/gif"
|
||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileInfo struct {
|
type FileInfo struct {
|
||||||
Filename string `json:"filename"`
|
Id string `json:"id"`
|
||||||
Size int `json:"size"`
|
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"`
|
Extension string `json:"extension"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
MimeType string `json:"mime_type"`
|
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)
|
|
||||||
} else {
|
|
||||||
mimeType = mime.TypeByExtension(extension)
|
|
||||||
}
|
|
||||||
|
|
||||||
if extension != "" && extension[0] == '.' {
|
|
||||||
// the client expects a file extension without the leading period
|
|
||||||
extension = extension[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &FileInfo{
|
|
||||||
Filename: filename,
|
|
||||||
Size: size,
|
|
||||||
Extension: extension,
|
|
||||||
MimeType: mimeType,
|
|
||||||
HasPreviewImage: hasPreviewImage,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (info *FileInfo) ToJson() string {
|
func (info *FileInfo) ToJson() string {
|
||||||
|
@ -75,3 +52,123 @@ func FileInfoFromJson(data io.Reader) *FileInfo {
|
||||||
return &info
|
return &info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FileInfosToJson(infos []*FileInfo) string {
|
||||||
|
b, err := json.Marshal(infos)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
} else {
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FileInfosFromJson(data io.Reader) []*FileInfo {
|
||||||
|
decoder := json.NewDecoder(data)
|
||||||
|
|
||||||
|
var infos []*FileInfo
|
||||||
|
if err := decoder.Decode(&infos); err != nil {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ type InitialLoad struct {
|
||||||
User *User `json:"user"`
|
User *User `json:"user"`
|
||||||
TeamMembers []*TeamMember `json:"team_members"`
|
TeamMembers []*TeamMember `json:"team_members"`
|
||||||
Teams []*Team `json:"teams"`
|
Teams []*Team `json:"teams"`
|
||||||
DirectProfiles map[string]*User `json:"direct_profiles"`
|
|
||||||
Preferences Preferences `json:"preferences"`
|
Preferences Preferences `json:"preferences"`
|
||||||
ClientCfg map[string]string `json:"client_cfg"`
|
ClientCfg map[string]string `json:"client_cfg"`
|
||||||
LicenseCfg map[string]string `json:"license_cfg"`
|
LicenseCfg map[string]string `json:"license_cfg"`
|
||||||
|
|
|
@ -43,6 +43,7 @@ type Features struct {
|
||||||
MHPNS *bool `json:"mhpns"`
|
MHPNS *bool `json:"mhpns"`
|
||||||
SAML *bool `json:"saml"`
|
SAML *bool `json:"saml"`
|
||||||
PasswordRequirements *bool `json:"password_requirements"`
|
PasswordRequirements *bool `json:"password_requirements"`
|
||||||
|
// after we enabled more features for webrtc we'll need to control them with this
|
||||||
FutureFeatures *bool `json:"future_features"`
|
FutureFeatures *bool `json:"future_features"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,8 @@ type Post struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Props StringInterface `json:"props"`
|
Props StringInterface `json:"props"`
|
||||||
Hashtags string `json:"hashtags"`
|
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:"-"`
|
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)
|
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 {
|
if utf8.RuneCountInString(StringInterfaceToJson(o.Props)) > 8000 {
|
||||||
return NewLocAppError("Post.IsValid", "model.post.is_valid.props.app_error", nil, "id="+o.Id)
|
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 {
|
if o.Filenames == nil {
|
||||||
o.Filenames = []string{}
|
o.Filenames = []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.FileIds == nil {
|
||||||
|
o.FileIds = []string{}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Post) MakeNonNil() {
|
func (o *Post) MakeNonNil() {
|
||||||
if o.Props == nil {
|
if o.Props == nil {
|
||||||
o.Props = make(map[string]interface{})
|
o.Props = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
if o.Filenames == nil {
|
|
||||||
o.Filenames = []string{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Post) AddProp(key string, value interface{}) {
|
func (o *Post) AddProp(key string, value interface{}) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SESSION_COOKIE_TOKEN = "MMAUTHTOKEN"
|
SESSION_COOKIE_TOKEN = "MMAUTHTOKEN"
|
||||||
SESSION_CACHE_SIZE = 10000
|
SESSION_CACHE_SIZE = 25000
|
||||||
SESSION_PROP_PLATFORM = "platform"
|
SESSION_PROP_PLATFORM = "platform"
|
||||||
SESSION_PROP_OS = "os"
|
SESSION_PROP_OS = "os"
|
||||||
SESSION_PROP_BROWSER = "browser"
|
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+":"))
|
(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 {
|
func SessionsToJson(o []*Session) string {
|
||||||
if b, err := json.Marshal(o); err != nil {
|
if b, err := json.Marshal(o); err != nil {
|
||||||
return "[]"
|
return "[]"
|
||||||
|
|
|
@ -12,8 +12,9 @@ const (
|
||||||
STATUS_OFFLINE = "offline"
|
STATUS_OFFLINE = "offline"
|
||||||
STATUS_AWAY = "away"
|
STATUS_AWAY = "away"
|
||||||
STATUS_ONLINE = "online"
|
STATUS_ONLINE = "online"
|
||||||
STATUS_CACHE_SIZE = 10000
|
STATUS_CACHE_SIZE = 25000
|
||||||
STATUS_CHANNEL_TIMEOUT = 20000 // 20 seconds
|
STATUS_CHANNEL_TIMEOUT = 20000 // 20 seconds
|
||||||
|
STATUS_MIN_UPDATE_TIME = 120000 // 2 minutes
|
||||||
)
|
)
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
|
|
|
@ -100,7 +100,7 @@ func (o *Team) Etag() string {
|
||||||
return Etag(o.Id, o.UpdateAt)
|
return Etag(o.Id, o.UpdateAt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Team) IsValid(restrictTeamNames bool) *AppError {
|
func (o *Team) IsValid() *AppError {
|
||||||
|
|
||||||
if len(o.Id) != 26 {
|
if len(o.Id) != 26 {
|
||||||
return NewLocAppError("Team.IsValid", "model.team.is_valid.id.app_error", nil, "")
|
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)
|
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)
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s) <= 3 {
|
if len(s) <= 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
ROLE_TEAM_ADMIN = "admin"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TeamMember struct {
|
type TeamMember struct {
|
||||||
TeamId string `json:"team_id"`
|
TeamId string `json:"team_id"`
|
||||||
UserId string `json:"user_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 {
|
func (o *TeamMember) IsValid() *AppError {
|
||||||
|
|
||||||
if len(o.TeamId) != 26 {
|
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, "")
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *TeamMember) PreUpdate() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *TeamMember) GetRoles() []string {
|
||||||
|
return strings.Fields(o.Roles)
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,7 +15,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ROLE_SYSTEM_ADMIN = "system_admin"
|
|
||||||
USER_NOTIFY_ALL = "all"
|
USER_NOTIFY_ALL = "all"
|
||||||
USER_NOTIFY_MENTION = "mention"
|
USER_NOTIFY_MENTION = "mention"
|
||||||
USER_NOTIFY_NONE = "none"
|
USER_NOTIFY_NONE = "none"
|
||||||
|
@ -233,14 +232,15 @@ func (u *User) Sanitize(options map[string]bool) {
|
||||||
if len(options) != 0 && !options["passwordupdate"] {
|
if len(options) != 0 && !options["passwordupdate"] {
|
||||||
u.LastPasswordUpdate = 0
|
u.LastPasswordUpdate = 0
|
||||||
}
|
}
|
||||||
|
if len(options) != 0 && !options["authservice"] {
|
||||||
|
u.AuthService = ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *User) ClearNonProfileFields() {
|
func (u *User) ClearNonProfileFields() {
|
||||||
u.Password = ""
|
u.Password = ""
|
||||||
u.AuthData = new(string)
|
u.AuthData = new(string)
|
||||||
*u.AuthData = ""
|
*u.AuthData = ""
|
||||||
u.AuthService = ""
|
|
||||||
u.MfaActive = false
|
|
||||||
u.MfaSecret = ""
|
u.MfaSecret = ""
|
||||||
u.EmailVerified = false
|
u.EmailVerified = false
|
||||||
u.AllowMarketing = false
|
u.AllowMarketing = false
|
||||||
|
@ -319,9 +319,17 @@ func (u *User) GetDisplayNameForPreference(nameFormat string) string {
|
||||||
return displayName
|
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 {
|
func IsValidUserRoles(userRoles string) bool {
|
||||||
|
|
||||||
roles := strings.Split(userRoles, " ")
|
roles := strings.Fields(userRoles)
|
||||||
|
|
||||||
for _, r := range roles {
|
for _, r := range roles {
|
||||||
if !isValidRole(r) {
|
if !isValidRole(r) {
|
||||||
|
@ -329,19 +337,17 @@ func IsValidUserRoles(userRoles string) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exclude just the system_admin role explicitly to prevent mistakes
|
||||||
|
if len(roles) == 1 && roles[0] == "system_admin" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func isValidRole(role string) bool {
|
func isValidRole(roleId string) bool {
|
||||||
if role == "" {
|
_, ok := BuiltInRoles[roleId]
|
||||||
return true
|
return ok
|
||||||
}
|
|
||||||
|
|
||||||
if role == ROLE_SYSTEM_ADMIN {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure you acually want to use this function. In context.go there are functions to check permissions
|
// 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
|
// HashPassword generates a hash using the bcrypt.GenerateFromPassword
|
||||||
func HashPassword(password string) string {
|
func HashPassword(password string) string {
|
||||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), 10)
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), 10)
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -74,13 +75,21 @@ func (er *AppError) ToJson() string {
|
||||||
|
|
||||||
// AppErrorFromJson will decode the input and return an AppError
|
// AppErrorFromJson will decode the input and return an AppError
|
||||||
func AppErrorFromJson(data io.Reader) *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
|
var er AppError
|
||||||
err := decoder.Decode(&er)
|
err := decoder.Decode(&er)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return &er
|
return &er
|
||||||
} else {
|
} 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 {
|
func StringInterfaceToJson(objmap map[string]interface{}) string {
|
||||||
if b, err := json.Marshal(objmap); err != nil {
|
if b, err := json.Marshal(objmap); err != nil {
|
||||||
return ""
|
return ""
|
||||||
|
@ -227,58 +253,15 @@ func IsValidEmail(email string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
var reservedName = []string{
|
var reservedName = []string{
|
||||||
"www",
|
"signup",
|
||||||
"web",
|
"login",
|
||||||
"admin",
|
"admin",
|
||||||
"support",
|
|
||||||
"notify",
|
|
||||||
"test",
|
|
||||||
"demo",
|
|
||||||
"mail",
|
|
||||||
"team",
|
|
||||||
"channel",
|
"channel",
|
||||||
"internal",
|
|
||||||
"localhost",
|
|
||||||
"dockerhost",
|
|
||||||
"stag",
|
|
||||||
"post",
|
"post",
|
||||||
"cluster",
|
|
||||||
"api",
|
"api",
|
||||||
"oauth",
|
"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 {
|
func IsValidChannelIdentifier(s string) bool {
|
||||||
|
|
||||||
if !IsValidAlphaNum(s, true) {
|
if !IsValidAlphaNum(s, true) {
|
||||||
|
@ -413,6 +396,18 @@ func IsValidHttpsUrl(rawUrl string) bool {
|
||||||
return true
|
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 {
|
func IsSafeLink(link *string) bool {
|
||||||
if link != nil {
|
if link != nil {
|
||||||
if IsValidHttpUrl(*link) {
|
if IsValidHttpUrl(*link) {
|
||||||
|
@ -426,3 +421,15 @@ func IsSafeLink(link *string) bool {
|
||||||
|
|
||||||
return true
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
// It should be maitained in chronological order with most current
|
// It should be maitained in chronological order with most current
|
||||||
// release at the front of the list.
|
// release at the front of the list.
|
||||||
var versions = []string{
|
var versions = []string{
|
||||||
|
"3.5.0",
|
||||||
"3.4.0",
|
"3.4.0",
|
||||||
"3.3.0",
|
"3.3.0",
|
||||||
"3.2.0",
|
"3.2.0",
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,6 @@ package model
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"net/http"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebSocketClient struct {
|
type WebSocketClient struct {
|
||||||
|
@ -17,19 +16,18 @@ type WebSocketClient struct {
|
||||||
Sequence int64 // The ever-incrementing sequence attached to each WebSocket action
|
Sequence int64 // The ever-incrementing sequence attached to each WebSocket action
|
||||||
EventChannel chan *WebSocketEvent
|
EventChannel chan *WebSocketEvent
|
||||||
ResponseChannel chan *WebSocketResponse
|
ResponseChannel chan *WebSocketResponse
|
||||||
|
ListenError *AppError
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebSocketClient constructs a new WebSocket client with convienence
|
// NewWebSocketClient constructs a new WebSocket client with convienence
|
||||||
// methods for talking to the server.
|
// methods for talking to the server.
|
||||||
func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
|
func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
|
||||||
header := http.Header{}
|
conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX+"/users/websocket", nil)
|
||||||
header.Set(HEADER_AUTH, "BEARER "+authToken)
|
|
||||||
conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX+"/users/websocket", header)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
|
return nil, NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return &WebSocketClient{
|
client := &WebSocketClient{
|
||||||
url,
|
url,
|
||||||
url + API_URL_SUFFIX,
|
url + API_URL_SUFFIX,
|
||||||
conn,
|
conn,
|
||||||
|
@ -37,19 +35,26 @@ func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
|
||||||
1,
|
1,
|
||||||
make(chan *WebSocketEvent, 100),
|
make(chan *WebSocketEvent, 100),
|
||||||
make(chan *WebSocketResponse, 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 {
|
func (wsc *WebSocketClient) Connect() *AppError {
|
||||||
header := http.Header{}
|
|
||||||
header.Set(HEADER_AUTH, "BEARER "+wsc.AuthToken)
|
|
||||||
|
|
||||||
var err error
|
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 {
|
if err != nil {
|
||||||
return NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,10 +64,20 @@ func (wsc *WebSocketClient) Close() {
|
||||||
|
|
||||||
func (wsc *WebSocketClient) Listen() {
|
func (wsc *WebSocketClient) Listen() {
|
||||||
go func() {
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
wsc.Conn.Close()
|
||||||
|
close(wsc.EventChannel)
|
||||||
|
close(wsc.ResponseChannel)
|
||||||
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
var rawMsg json.RawMessage
|
var rawMsg json.RawMessage
|
||||||
var err error
|
var err error
|
||||||
if _, rawMsg, err = wsc.Conn.ReadMessage(); err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +92,7 @@ func (wsc *WebSocketClient) Listen() {
|
||||||
wsc.ResponseChannel <- &response
|
wsc.ResponseChannel <- &response
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -107,3 +123,12 @@ func (wsc *WebSocketClient) UserTyping(channelId, parentId string) {
|
||||||
func (wsc *WebSocketClient) GetStatuses() {
|
func (wsc *WebSocketClient) GetStatuses() {
|
||||||
wsc.SendMessage("get_statuses", nil)
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -25,33 +25,57 @@ const (
|
||||||
WEBSOCKET_EVENT_EPHEMERAL_MESSAGE = "ephemeral_message"
|
WEBSOCKET_EVENT_EPHEMERAL_MESSAGE = "ephemeral_message"
|
||||||
WEBSOCKET_EVENT_STATUS_CHANGE = "status_change"
|
WEBSOCKET_EVENT_STATUS_CHANGE = "status_change"
|
||||||
WEBSOCKET_EVENT_HELLO = "hello"
|
WEBSOCKET_EVENT_HELLO = "hello"
|
||||||
|
WEBSOCKET_EVENT_WEBRTC = "webrtc"
|
||||||
|
WEBSOCKET_AUTHENTICATION_CHALLENGE = "authentication_challenge"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebSocketMessage interface {
|
type WebSocketMessage interface {
|
||||||
ToJson() string
|
ToJson() string
|
||||||
IsValid() bool
|
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 {
|
type WebSocketEvent struct {
|
||||||
TeamId string `json:"team_id"`
|
|
||||||
ChannelId string `json:"channel_id"`
|
|
||||||
UserId string `json:"user_id"`
|
|
||||||
Event string `json:"event"`
|
Event string `json:"event"`
|
||||||
Data map[string]interface{} `json:"data"`
|
Data map[string]interface{} `json:"data"`
|
||||||
|
Broadcast *WebsocketBroadcast `json:"broadcast"`
|
||||||
|
PreComputeJson []byte `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *WebSocketEvent) Add(key string, value interface{}) {
|
func (m *WebSocketEvent) Add(key string, value interface{}) {
|
||||||
m.Data[key] = value
|
m.Data[key] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebSocketEvent(teamId string, channelId string, userId string, event string) *WebSocketEvent {
|
func NewWebSocketEvent(event, teamId, channelId, userId string, omitUsers map[string]bool) *WebSocketEvent {
|
||||||
return &WebSocketEvent{TeamId: teamId, ChannelId: channelId, UserId: userId, Event: event, Data: make(map[string]interface{})}
|
return &WebSocketEvent{Event: event, Data: make(map[string]interface{}),
|
||||||
|
Broadcast: &WebsocketBroadcast{TeamId: teamId, ChannelId: channelId, UserId: userId, OmitUsers: omitUsers}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *WebSocketEvent) IsValid() bool {
|
func (o *WebSocketEvent) IsValid() bool {
|
||||||
return o.Event != ""
|
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 {
|
func (o *WebSocketEvent) ToJson() string {
|
||||||
b, err := json.Marshal(o)
|
b, err := json.Marshal(o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -77,6 +101,7 @@ type WebSocketResponse struct {
|
||||||
SeqReply int64 `json:"seq_reply,omitempty"`
|
SeqReply int64 `json:"seq_reply,omitempty"`
|
||||||
Data map[string]interface{} `json:"data,omitempty"`
|
Data map[string]interface{} `json:"data,omitempty"`
|
||||||
Error *AppError `json:"error,omitempty"`
|
Error *AppError `json:"error,omitempty"`
|
||||||
|
PreComputeJson []byte `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *WebSocketResponse) Add(key string, value interface{}) {
|
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 {
|
func WebSocketResponseFromJson(data io.Reader) *WebSocketResponse {
|
||||||
decoder := json.NewDecoder(data)
|
decoder := json.NewDecoder(data)
|
||||||
var o WebSocketResponse
|
var o WebSocketResponse
|
||||||
|
|
|
@ -87,8 +87,8 @@
|
||||||
"importpath": "github.com/mattermost/platform/einterfaces",
|
"importpath": "github.com/mattermost/platform/einterfaces",
|
||||||
"repository": "https://github.com/mattermost/platform",
|
"repository": "https://github.com/mattermost/platform",
|
||||||
"vcs": "git",
|
"vcs": "git",
|
||||||
"revision": "57f25fa59c71821cc38fd220b133aa6a40815e12",
|
"revision": "b55ec6148caa93d54b660afe55408c643d217108",
|
||||||
"branch": "release-3.4",
|
"branch": "release-3.5",
|
||||||
"path": "/einterfaces",
|
"path": "/einterfaces",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
|
@ -96,8 +96,8 @@
|
||||||
"importpath": "github.com/mattermost/platform/model",
|
"importpath": "github.com/mattermost/platform/model",
|
||||||
"repository": "https://github.com/mattermost/platform",
|
"repository": "https://github.com/mattermost/platform",
|
||||||
"vcs": "git",
|
"vcs": "git",
|
||||||
"revision": "57f25fa59c71821cc38fd220b133aa6a40815e12",
|
"revision": "b55ec6148caa93d54b660afe55408c643d217108",
|
||||||
"branch": "release-3.4",
|
"branch": "release-3.5",
|
||||||
"path": "/model",
|
"path": "/model",
|
||||||
"notests": true
|
"notests": true
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue