4
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2025-07-03 22:27:44 +00:00

Update vendor (github.com/mattermost)

This commit is contained in:
Wim
2018-02-09 00:11:04 +01:00
parent 1d33e60e36
commit 5aab158c0b
267 changed files with 36409 additions and 5827 deletions

View File

@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
"net/http"
)
const (
@ -37,23 +38,23 @@ type AccessResponse struct {
func (ad *AccessData) IsValid() *AppError {
if len(ad.ClientId) == 0 || len(ad.ClientId) > 26 {
return NewLocAppError("AccessData.IsValid", "model.access.is_valid.client_id.app_error", nil, "")
return NewAppError("AccessData.IsValid", "model.access.is_valid.client_id.app_error", nil, "", http.StatusBadRequest)
}
if len(ad.UserId) == 0 || len(ad.UserId) > 26 {
return NewLocAppError("AccessData.IsValid", "model.access.is_valid.user_id.app_error", nil, "")
return NewAppError("AccessData.IsValid", "model.access.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
if len(ad.Token) != 26 {
return NewLocAppError("AccessData.IsValid", "model.access.is_valid.access_token.app_error", nil, "")
return NewAppError("AccessData.IsValid", "model.access.is_valid.access_token.app_error", nil, "", http.StatusBadRequest)
}
if len(ad.RefreshToken) > 26 {
return NewLocAppError("AccessData.IsValid", "model.access.is_valid.refresh_token.app_error", nil, "")
return NewAppError("AccessData.IsValid", "model.access.is_valid.refresh_token.app_error", nil, "", http.StatusBadRequest)
}
if len(ad.RedirectUri) == 0 || len(ad.RedirectUri) > 256 || !IsValidHttpUrl(ad.RedirectUri) {
return NewLocAppError("AccessData.IsValid", "model.access.is_valid.redirect_uri.app_error", nil, "")
return NewAppError("AccessData.IsValid", "model.access.is_valid.redirect_uri.app_error", nil, "", http.StatusBadRequest)
}
return nil

View File

@ -69,24 +69,24 @@ var PERMISSION_REVOKE_USER_ACCESS_TOKEN *Permission
// admin functions but not others
var PERMISSION_MANAGE_SYSTEM *Permission
var ROLE_SYSTEM_USER *Role
var ROLE_SYSTEM_ADMIN *Role
var ROLE_SYSTEM_POST_ALL *Role
var ROLE_SYSTEM_POST_ALL_PUBLIC *Role
var ROLE_SYSTEM_USER_ACCESS_TOKEN *Role
const (
SYSTEM_USER_ROLE_ID = "system_user"
SYSTEM_ADMIN_ROLE_ID = "system_admin"
SYSTEM_POST_ALL_ROLE_ID = "system_post_all"
SYSTEM_POST_ALL_PUBLIC_ROLE_ID = "system_post_all_public"
SYSTEM_USER_ACCESS_TOKEN_ROLE_ID = "system_user_access_token"
var ROLE_TEAM_USER *Role
var ROLE_TEAM_ADMIN *Role
var ROLE_TEAM_POST_ALL *Role
var ROLE_TEAM_POST_ALL_PUBLIC *Role
TEAM_USER_ROLE_ID = "team_user"
TEAM_ADMIN_ROLE_ID = "team_admin"
TEAM_POST_ALL_ROLE_ID = "team_post_all"
TEAM_POST_ALL_PUBLIC_ROLE_ID = "team_post_all_public"
var ROLE_CHANNEL_USER *Role
var ROLE_CHANNEL_ADMIN *Role
var ROLE_CHANNEL_GUEST *Role
CHANNEL_USER_ROLE_ID = "channel_user"
CHANNEL_ADMIN_ROLE_ID = "channel_admin"
CHANNEL_GUEST_ROLE_ID = "guest"
)
var BuiltInRoles map[string]*Role
func InitalizePermissions() {
func initializePermissions() {
PERMISSION_INVITE_USER = &Permission{
"invite_user",
"authentication.permissions.team_invite_user.name",
@ -329,11 +329,12 @@ func InitalizePermissions() {
}
}
func InitalizeRoles() {
InitalizePermissions()
BuiltInRoles = make(map[string]*Role)
var DefaultRoles map[string]*Role
ROLE_CHANNEL_USER = &Role{
func initializeDefaultRoles() {
DefaultRoles = make(map[string]*Role)
DefaultRoles[CHANNEL_USER_ROLE_ID] = &Role{
"channel_user",
"authentication.roles.channel_user.name",
"authentication.roles.channel_user.description",
@ -347,8 +348,8 @@ func InitalizeRoles() {
PERMISSION_USE_SLASH_COMMANDS.Id,
},
}
BuiltInRoles[ROLE_CHANNEL_USER.Id] = ROLE_CHANNEL_USER
ROLE_CHANNEL_ADMIN = &Role{
DefaultRoles[CHANNEL_ADMIN_ROLE_ID] = &Role{
"channel_admin",
"authentication.roles.channel_admin.name",
"authentication.roles.channel_admin.description",
@ -356,16 +357,15 @@ func InitalizeRoles() {
PERMISSION_MANAGE_CHANNEL_ROLES.Id,
},
}
BuiltInRoles[ROLE_CHANNEL_ADMIN.Id] = ROLE_CHANNEL_ADMIN
ROLE_CHANNEL_GUEST = &Role{
DefaultRoles[CHANNEL_GUEST_ROLE_ID] = &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{
DefaultRoles[TEAM_USER_ROLE_ID] = &Role{
"team_user",
"authentication.roles.team_user.name",
"authentication.roles.team_user.description",
@ -376,9 +376,8 @@ func InitalizeRoles() {
PERMISSION_VIEW_TEAM.Id,
},
}
BuiltInRoles[ROLE_TEAM_USER.Id] = ROLE_TEAM_USER
ROLE_TEAM_POST_ALL = &Role{
DefaultRoles[TEAM_POST_ALL_ROLE_ID] = &Role{
"team_post_all",
"authentication.roles.team_post_all.name",
"authentication.roles.team_post_all.description",
@ -386,9 +385,8 @@ func InitalizeRoles() {
PERMISSION_CREATE_POST.Id,
},
}
BuiltInRoles[ROLE_TEAM_POST_ALL.Id] = ROLE_TEAM_POST_ALL
ROLE_TEAM_POST_ALL_PUBLIC = &Role{
DefaultRoles[TEAM_POST_ALL_PUBLIC_ROLE_ID] = &Role{
"team_post_all_public",
"authentication.roles.team_post_all_public.name",
"authentication.roles.team_post_all_public.description",
@ -396,9 +394,8 @@ func InitalizeRoles() {
PERMISSION_CREATE_POST_PUBLIC.Id,
},
}
BuiltInRoles[ROLE_TEAM_POST_ALL_PUBLIC.Id] = ROLE_TEAM_POST_ALL_PUBLIC
ROLE_TEAM_ADMIN = &Role{
DefaultRoles[TEAM_ADMIN_ROLE_ID] = &Role{
"team_admin",
"authentication.roles.team_admin.name",
"authentication.roles.team_admin.description",
@ -415,9 +412,8 @@ func InitalizeRoles() {
PERMISSION_MANAGE_WEBHOOKS.Id,
},
}
BuiltInRoles[ROLE_TEAM_ADMIN.Id] = ROLE_TEAM_ADMIN
ROLE_SYSTEM_USER = &Role{
DefaultRoles[SYSTEM_USER_ROLE_ID] = &Role{
"system_user",
"authentication.roles.global_user.name",
"authentication.roles.global_user.description",
@ -427,9 +423,8 @@ func InitalizeRoles() {
PERMISSION_PERMANENT_DELETE_USER.Id,
},
}
BuiltInRoles[ROLE_SYSTEM_USER.Id] = ROLE_SYSTEM_USER
ROLE_SYSTEM_POST_ALL = &Role{
DefaultRoles[SYSTEM_POST_ALL_ROLE_ID] = &Role{
"system_post_all",
"authentication.roles.system_post_all.name",
"authentication.roles.system_post_all.description",
@ -437,9 +432,8 @@ func InitalizeRoles() {
PERMISSION_CREATE_POST.Id,
},
}
BuiltInRoles[ROLE_SYSTEM_POST_ALL.Id] = ROLE_SYSTEM_POST_ALL
ROLE_SYSTEM_POST_ALL_PUBLIC = &Role{
DefaultRoles[SYSTEM_POST_ALL_PUBLIC_ROLE_ID] = &Role{
"system_post_all_public",
"authentication.roles.system_post_all_public.name",
"authentication.roles.system_post_all_public.description",
@ -447,9 +441,8 @@ func InitalizeRoles() {
PERMISSION_CREATE_POST_PUBLIC.Id,
},
}
BuiltInRoles[ROLE_SYSTEM_POST_ALL_PUBLIC.Id] = ROLE_SYSTEM_POST_ALL_PUBLIC
ROLE_SYSTEM_USER_ACCESS_TOKEN = &Role{
DefaultRoles[SYSTEM_USER_ACCESS_TOKEN_ROLE_ID] = &Role{
"system_user_access_token",
"authentication.roles.system_user_access_token.name",
"authentication.roles.system_user_access_token.description",
@ -459,9 +452,8 @@ func InitalizeRoles() {
PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id,
},
}
BuiltInRoles[ROLE_SYSTEM_USER_ACCESS_TOKEN.Id] = ROLE_SYSTEM_USER_ACCESS_TOKEN
ROLE_SYSTEM_ADMIN = &Role{
DefaultRoles[SYSTEM_ADMIN_ROLE_ID] = &Role{
"system_admin",
"authentication.roles.global_admin.name",
"authentication.roles.global_admin.description",
@ -500,17 +492,15 @@ func InitalizeRoles() {
PERMISSION_READ_USER_ACCESS_TOKEN.Id,
PERMISSION_REVOKE_USER_ACCESS_TOKEN.Id,
},
ROLE_TEAM_USER.Permissions...,
DefaultRoles[TEAM_USER_ROLE_ID].Permissions...,
),
ROLE_CHANNEL_USER.Permissions...,
DefaultRoles[CHANNEL_USER_ROLE_ID].Permissions...,
),
ROLE_TEAM_ADMIN.Permissions...,
DefaultRoles[TEAM_ADMIN_ROLE_ID].Permissions...,
),
ROLE_CHANNEL_ADMIN.Permissions...,
DefaultRoles[CHANNEL_ADMIN_ROLE_ID].Permissions...,
),
}
BuiltInRoles[ROLE_SYSTEM_ADMIN.Id] = ROLE_SYSTEM_ADMIN
}
func RoleIdsToString(roles []string) string {
@ -527,5 +517,6 @@ func RoleIdsToString(roles []string) string {
}
func init() {
InitalizeRoles()
initializePermissions()
initializeDefaultRoles()
}

View File

@ -39,35 +39,35 @@ type AuthorizeRequest struct {
func (ad *AuthData) IsValid() *AppError {
if len(ad.ClientId) != 26 {
return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.client_id.app_error", nil, "")
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.client_id.app_error", nil, "", http.StatusBadRequest)
}
if len(ad.UserId) != 26 {
return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.user_id.app_error", nil, "")
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
if len(ad.Code) == 0 || len(ad.Code) > 128 {
return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.auth_code.app_error", nil, "client_id="+ad.ClientId)
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.auth_code.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest)
}
if ad.ExpiresIn == 0 {
return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.expires.app_error", nil, "")
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.expires.app_error", nil, "", http.StatusBadRequest)
}
if ad.CreateAt <= 0 {
return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.create_at.app_error", nil, "client_id="+ad.ClientId)
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.create_at.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest)
}
if len(ad.RedirectUri) == 0 || len(ad.RedirectUri) > 256 || !IsValidHttpUrl(ad.RedirectUri) {
return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.redirect_uri.app_error", nil, "client_id="+ad.ClientId)
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.redirect_uri.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest)
}
if len(ad.State) > 128 {
return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.state.app_error", nil, "client_id="+ad.ClientId)
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.state.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest)
}
if len(ad.Scope) > 128 {
return NewLocAppError("AuthData.IsValid", "model.authorize.is_valid.scope.app_error", nil, "client_id="+ad.ClientId)
return NewAppError("AuthData.IsValid", "model.authorize.is_valid.scope.app_error", nil, "client_id="+ad.ClientId, http.StatusBadRequest)
}
return nil
@ -155,10 +155,5 @@ func AuthorizeRequestFromJson(data io.Reader) *AuthorizeRequest {
}
func (ad *AuthData) IsExpired() bool {
if GetMillis() > ad.CreateAt+int64(ad.ExpiresIn*1000) {
return true
}
return false
return GetMillis() > ad.CreateAt+int64(ad.ExpiresIn*1000)
}

View File

@ -0,0 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
func NewBool(b bool) *bool { return &b }
func NewInt(n int) *int { return &n }
func NewInt64(n int64) *int64 { return &n }
func NewString(s string) *string { return &s }

View File

@ -0,0 +1,23 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
type BundleInfo struct {
Path string
Manifest *Manifest
ManifestPath string
ManifestError error
}
// Returns bundle info for the given path. The return value is never nil.
func BundleInfoForPath(path string) *BundleInfo {
m, mpath, err := FindManifest(path)
return &BundleInfo{
Path: path,
Manifest: m,
ManifestPath: mpath,
ManifestError: err,
}
}

View File

@ -8,6 +8,7 @@ import (
"encoding/hex"
"encoding/json"
"io"
"net/http"
"sort"
"strings"
"unicode/utf8"
@ -24,6 +25,7 @@ const (
CHANNEL_DISPLAY_NAME_MAX_RUNES = 64
CHANNEL_NAME_MIN_LENGTH = 2
CHANNEL_NAME_MAX_LENGTH = 64
CHANNEL_NAME_UI_MAX_LENGTH = 22
CHANNEL_HEADER_MAX_RUNES = 1024
CHANNEL_PURPOSE_MAX_RUNES = 250
CHANNEL_CACHE_SIZE = 25000
@ -53,6 +55,11 @@ type ChannelPatch struct {
Purpose *string `json:"purpose"`
}
func (o *Channel) DeepCopy() *Channel {
copy := *o
return &copy
}
func (o *Channel) ToJson() string {
b, err := json.Marshal(o)
if err != nil {
@ -104,39 +111,39 @@ func (o *Channel) StatsEtag() string {
func (o *Channel) IsValid() *AppError {
if len(o.Id) != 26 {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.id.app_error", nil, "")
return NewAppError("Channel.IsValid", "model.channel.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
if o.CreateAt == 0 {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.create_at.app_error", nil, "id="+o.Id)
return NewAppError("Channel.IsValid", "model.channel.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if o.UpdateAt == 0 {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.update_at.app_error", nil, "id="+o.Id)
return NewAppError("Channel.IsValid", "model.channel.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if utf8.RuneCountInString(o.DisplayName) > CHANNEL_DISPLAY_NAME_MAX_RUNES {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.display_name.app_error", nil, "id="+o.Id)
return NewAppError("Channel.IsValid", "model.channel.is_valid.display_name.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if !IsValidChannelIdentifier(o.Name) {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.2_or_more.app_error", nil, "id="+o.Id)
return NewAppError("Channel.IsValid", "model.channel.is_valid.2_or_more.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if !(o.Type == CHANNEL_OPEN || o.Type == CHANNEL_PRIVATE || o.Type == CHANNEL_DIRECT || o.Type == CHANNEL_GROUP) {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.type.app_error", nil, "id="+o.Id)
return NewAppError("Channel.IsValid", "model.channel.is_valid.type.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if utf8.RuneCountInString(o.Header) > CHANNEL_HEADER_MAX_RUNES {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.header.app_error", nil, "id="+o.Id)
return NewAppError("Channel.IsValid", "model.channel.is_valid.header.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if utf8.RuneCountInString(o.Purpose) > CHANNEL_PURPOSE_MAX_RUNES {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.purpose.app_error", nil, "id="+o.Id)
return NewAppError("Channel.IsValid", "model.channel.is_valid.purpose.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if len(o.CreatorId) > 26 {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.creator_id.app_error", nil, "")
return NewAppError("Channel.IsValid", "model.channel.is_valid.creator_id.app_error", nil, "", http.StatusBadRequest)
}
return nil

View File

@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
"net/http"
"strings"
)
@ -101,36 +102,32 @@ func ChannelMemberFromJson(data io.Reader) *ChannelMember {
func (o *ChannelMember) IsValid() *AppError {
if len(o.ChannelId) != 26 {
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.channel_id.app_error", nil, "")
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.UserId) != 26 {
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.user_id.app_error", nil, "")
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
notifyLevel := o.NotifyProps[DESKTOP_NOTIFY_PROP]
if len(notifyLevel) > 20 || !IsChannelNotifyLevelValid(notifyLevel) {
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.notify_level.app_error",
nil, "notify_level="+notifyLevel)
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.notify_level.app_error", nil, "notify_level="+notifyLevel, http.StatusBadRequest)
}
markUnreadLevel := o.NotifyProps[MARK_UNREAD_NOTIFY_PROP]
if len(markUnreadLevel) > 20 || !IsChannelMarkUnreadLevelValid(markUnreadLevel) {
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.unread_level.app_error",
nil, "mark_unread_level="+markUnreadLevel)
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.unread_level.app_error", nil, "mark_unread_level="+markUnreadLevel, http.StatusBadRequest)
}
if pushLevel, ok := o.NotifyProps[PUSH_NOTIFY_PROP]; ok {
if len(pushLevel) > 20 || !IsChannelNotifyLevelValid(pushLevel) {
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.push_level.app_error",
nil, "push_notification_level="+pushLevel)
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.push_level.app_error", nil, "push_notification_level="+pushLevel, http.StatusBadRequest)
}
}
if sendEmail, ok := o.NotifyProps[EMAIL_NOTIFY_PROP]; ok {
if len(sendEmail) > 20 || !IsSendEmailValid(sendEmail) {
return NewLocAppError("ChannelMember.IsValid", "model.channel_member.is_valid.email_value.app_error",
nil, "push_notification_level="+sendEmail)
return NewAppError("ChannelMember.IsValid", "model.channel_member.is_valid.email_value.app_error", nil, "push_notification_level="+sendEmail, http.StatusBadRequest)
}
}

View File

@ -0,0 +1,12 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
type ChannelMemberHistory struct {
ChannelId string
UserId string
UserEmail string `db:"Email"`
JoinTime int64
LeaveTime *int64
}

View File

@ -32,3 +32,28 @@ func ChannelViewFromJson(data io.Reader) *ChannelView {
return nil
}
}
type ChannelViewResponse struct {
Status string `json:"status"`
LastViewedAtTimes map[string]int64 `json:"last_viewed_at_times"`
}
func (o *ChannelViewResponse) ToJson() string {
b, err := json.Marshal(o)
if err != nil {
return ""
} else {
return string(b)
}
}
func ChannelViewResponseFromJson(data io.Reader) *ChannelViewResponse {
decoder := json.NewDecoder(data)
var o ChannelViewResponse
err := decoder.Decode(&o)
if err == nil {
return &o
} else {
return nil
}
}

View File

@ -18,6 +18,8 @@ import (
l4g "github.com/alecthomas/log4go"
)
var UsedApiV3 *int32 = new(int32)
const (
HEADER_REQUEST_ID = "X-Request-ID"
HEADER_VERSION_ID = "X-Version-ID"
@ -37,7 +39,7 @@ const (
STATUS_FAIL = "FAIL"
STATUS_REMOVE = "REMOVE"
CLIENT_DIR = "webapp/dist"
CLIENT_DIR = "client"
API_URL_SUFFIX_V1 = "/api/v1"
API_URL_SUFFIX_V3 = "/api/v3"
@ -144,7 +146,7 @@ func (c *Client) DoPost(url, data, contentType string) (*http.Response, *AppErro
rq.Close = true
if rp, err := c.HttpClient.Do(rq); err != nil {
return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
} else if rp.StatusCode >= 300 {
defer closeBody(rp)
return nil, AppErrorFromJson(rp.Body)
@ -162,7 +164,7 @@ func (c *Client) DoApiPost(url string, data string) (*http.Response, *AppError)
}
if rp, err := c.HttpClient.Do(rq); err != nil {
return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
} else if rp.StatusCode >= 300 {
defer closeBody(rp)
return nil, AppErrorFromJson(rp.Body)
@ -184,7 +186,7 @@ func (c *Client) DoApiGet(url string, data string, etag string) (*http.Response,
}
if rp, err := c.HttpClient.Do(rq); err != nil {
return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
} else if rp.StatusCode == 304 {
return rp, nil
} else if rp.StatusCode >= 300 {
@ -429,7 +431,7 @@ func (c *Client) UpdateTeam(team *Team) (*Result, *AppError) {
} else {
defer closeBody(r)
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
}
}
@ -677,7 +679,7 @@ func (c *Client) login(m map[string]string) (*Result, *AppError) {
sessionToken := getCookie(SESSION_COOKIE_TOKEN, r)
if c.AuthToken != sessionToken.Value {
NewLocAppError("/users/login", "model.client.login.app_error", nil, "")
NewAppError("/users/login", "model.client.login.app_error", nil, "", 0)
}
defer closeBody(r)
@ -1054,7 +1056,7 @@ func (c *Client) DownloadComplianceReport(id string) (*Result, *AppError) {
}
if rp, err := c.HttpClient.Do(rq); err != nil {
return nil, NewLocAppError("/admin/download_compliance_report", "model.client.connecting.app_error", nil, err.Error())
return nil, NewAppError("/admin/download_compliance_report", "model.client.connecting.app_error", nil, err.Error(), 0)
} else if rp.StatusCode >= 300 {
defer rp.Body.Close()
return nil, AppErrorFromJson(rp.Body)
@ -1527,19 +1529,19 @@ func (c *Client) UploadPostAttachment(data []byte, channelId string, filename st
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())
return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), 0)
} 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())
return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), 0)
}
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())
return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), 0)
} 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())
return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), 0)
}
if err := writer.Close(); err != nil {
return nil, NewLocAppError("UploadPostAttachment", "model.client.upload_post_attachment.writer.app_error", nil, err.Error())
return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), 0)
}
if result, err := c.uploadFile(c.ApiUrl+c.GetTeamRoute()+"/files/upload", body.Bytes(), writer.FormDataContentType()); err != nil {
@ -1559,7 +1561,7 @@ func (c *Client) uploadFile(url string, data []byte, contentType string) (*Resul
}
if rp, err := c.HttpClient.Do(rq); err != nil {
return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
} else if rp.StatusCode >= 300 {
return nil, AppErrorFromJson(rp.Body)
} else {
@ -2175,17 +2177,17 @@ func (c *Client) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoj
writer := multipart.NewWriter(body)
if part, err := writer.CreateFormFile("image", filename); err != nil {
return nil, NewLocAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error())
return nil, NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)
} else if _, err = io.Copy(part, bytes.NewBuffer(image)); err != nil {
return nil, NewLocAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error())
return nil, NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)
}
if err := writer.WriteField("emoji", emoji.ToJson()); err != nil {
return nil, NewLocAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error())
return nil, NewAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error(), 0)
}
if err := writer.Close(); err != nil {
return nil, NewLocAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error())
return nil, NewAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error(), 0)
}
rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetEmojiRoute()+"/create", body)
@ -2197,7 +2199,7 @@ func (c *Client) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoj
}
if r, err := c.HttpClient.Do(rq); err != nil {
return nil, NewLocAppError("CreateEmoji", "model.client.connecting.app_error", nil, err.Error())
return nil, NewAppError("CreateEmoji", "model.client.connecting.app_error", nil, err.Error(), 0)
} else if r.StatusCode >= 300 {
return nil, AppErrorFromJson(r.Body)
} else {
@ -2241,7 +2243,7 @@ func (c *Client) UploadCertificateFile(data []byte, contentType string) *AppErro
}
if rp, err := c.HttpClient.Do(rq); err != nil {
return NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
return NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
} else if rp.StatusCode >= 300 {
return AppErrorFromJson(rp.Body)
} else {

View File

@ -44,7 +44,7 @@ func BuildErrorResponse(r *http.Response, err *AppError) *Response {
header = r.Header
} else {
statusCode = 0
header = make(http.Header, 0)
header = make(http.Header)
}
return &Response{
@ -178,6 +178,14 @@ func (c *Client4) GetFileRoute(fileId string) string {
return fmt.Sprintf(c.GetFilesRoute()+"/%v", fileId)
}
func (c *Client4) GetPluginsRoute() string {
return fmt.Sprintf("/plugins")
}
func (c *Client4) GetPluginRoute(pluginId string) string {
return fmt.Sprintf(c.GetPluginsRoute()+"/%v", pluginId)
}
func (c *Client4) GetSystemRoute() string {
return fmt.Sprintf("/system")
}
@ -246,6 +254,10 @@ func (c *Client4) GetBrandRoute() string {
return fmt.Sprintf("/brand")
}
func (c *Client4) GetDataRetentionRoute() string {
return fmt.Sprintf("/data_retention")
}
func (c *Client4) GetElasticsearchRoute() string {
return fmt.Sprintf("/elasticsearch")
}
@ -319,7 +331,7 @@ func (c *Client4) DoApiRequest(method, url, data, etag string) (*http.Response,
}
if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
return nil, NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
} else if rp.StatusCode == 304 {
return rp, nil
} else if rp.StatusCode >= 300 {
@ -754,6 +766,16 @@ func (c *Client4) PatchUser(userId string, patch *UserPatch) (*User, *Response)
}
}
// UpdateUserAuth updates a user AuthData (uthData, authService and password) in the system.
func (c *Client4) UpdateUserAuth(userId string, userAuth *UserAuth) (*UserAuth, *Response) {
if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/auth", userAuth.ToJson()); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return UserAuthFromJson(r.Body), BuildResponse(r)
}
}
// UpdateUserMfa activates multi-factor authentication for a user if activate
// is true and a valid code is provided. If activate is false, then code is not
// required and multi-factor authentication is disabled for the user.
@ -889,6 +911,16 @@ func (c *Client4) RevokeSession(userId, sessionId string) (bool, *Response) {
}
}
// RevokeAllSessions revokes all sessions for the provided user id string.
func (c *Client4) RevokeAllSessions(userId string) (bool, *Response) {
if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke/all", ""); err != nil {
return false, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return CheckStatusOK(r), BuildResponse(r)
}
}
// AttachDeviceId attaches a mobile device ID to the current session.
func (c *Client4) AttachDeviceId(deviceId string) (bool, *Response) {
requestBody := map[string]string{"device_id": deviceId}
@ -1043,6 +1075,32 @@ func (c *Client4) RevokeUserAccessToken(tokenId string) (bool, *Response) {
}
}
// DisableUserAccessToken will disable a user access token by id. Must have the
// 'revoke_user_access_token' permission and if disabling for another user, must have the
// 'edit_other_users' permission.
func (c *Client4) DisableUserAccessToken(tokenId string) (bool, *Response) {
requestBody := map[string]string{"token_id": tokenId}
if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/disable", MapToJson(requestBody)); err != nil {
return false, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return CheckStatusOK(r), BuildResponse(r)
}
}
// EnableUserAccessToken will enable a user access token by id. Must have the
// 'create_user_access_token' permission and if enabling for another user, must have the
// 'edit_other_users' permission.
func (c *Client4) EnableUserAccessToken(tokenId string) (bool, *Response) {
requestBody := map[string]string{"token_id": tokenId}
if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/enable", MapToJson(requestBody)); err != nil {
return false, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return CheckStatusOK(r), BuildResponse(r)
}
}
// Team Section
// CreateTeam creates a team in the system based on the provided team struct.
@ -1562,13 +1620,13 @@ func (c *Client4) GetChannelMembersForUser(userId, teamId, etag string) (*Channe
}
// ViewChannel performs a view action for a user. Synonymous with switching channels or marking channels as read by a user.
func (c *Client4) ViewChannel(userId string, view *ChannelView) (bool, *Response) {
func (c *Client4) ViewChannel(userId string, view *ChannelView) (*ChannelViewResponse, *Response) {
url := fmt.Sprintf(c.GetChannelsRoute()+"/members/%v/view", userId)
if r, err := c.DoApiPost(url, view.ToJson()); err != nil {
return false, BuildErrorResponse(r, err)
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return CheckStatusOK(r), BuildResponse(r)
return ChannelViewResponseFromJson(r.Body), BuildResponse(r)
}
}
@ -1615,6 +1673,17 @@ func (c *Client4) AddChannelMember(channelId, userId string) (*ChannelMember, *R
}
}
// AddChannelMemberWithRootId adds user to channel and return a channel member. Post add to channel message has the postRootId.
func (c *Client4) AddChannelMemberWithRootId(channelId, userId, postRootId string) (*ChannelMember, *Response) {
requestBody := map[string]string{"user_id": userId, "post_root_id": postRootId}
if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return ChannelMemberFromJson(r.Body), BuildResponse(r)
}
}
// RemoveUserFromChannel will delete the channel member object for a user, effectively removing the user from a channel.
func (c *Client4) RemoveUserFromChannel(channelId, userId string) (bool, *Response) {
if r, err := c.DoApiDelete(c.GetChannelMemberRoute(channelId, userId)); err != nil {
@ -1803,6 +1872,16 @@ func (c *Client4) SearchPosts(teamId string, terms string, isOrSearch bool) (*Po
}
}
// DoPostAction performs a post action.
func (c *Client4) DoPostAction(postId, actionId string) (bool, *Response) {
if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, ""); err != nil {
return false, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return CheckStatusOK(r), BuildResponse(r)
}
}
// File Section
// UploadFile will upload a file to a channel, to be later attached to a post.
@ -2580,7 +2659,7 @@ func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) {
// GetLogs page of logs as a string array.
func (c *Client4) GetLogs(page, perPage int) ([]string, *Response) {
query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
query := fmt.Sprintf("?page=%v&logs_per_page=%v", page, perPage)
if r, err := c.DoApiGet("/logs"+query, ""); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
@ -2613,6 +2692,16 @@ func (c *Client4) CreateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
}
}
// UpdateOAuthApp
func (c *Client4) UpdateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
if r, err := c.DoApiPut(c.GetOAuthAppRoute(app.Id), app.ToJson()); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return OAuthAppFromJson(r.Body), BuildResponse(r)
}
}
// GetOAuthApps gets a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider.
func (c *Client4) GetOAuthApps(page, perPage int) ([]*OAuthApp, *Response) {
query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
@ -2711,7 +2800,7 @@ func (c *Client4) TestElasticsearch() (bool, *Response) {
// PurgeElasticsearchIndexes immediately deletes all Elasticsearch indexes.
func (c *Client4) PurgeElasticsearchIndexes() (bool, *Response) {
if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/test", ""); err != nil {
if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/purge_indexes", ""); err != nil {
return false, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
@ -2719,6 +2808,18 @@ func (c *Client4) PurgeElasticsearchIndexes() (bool, *Response) {
}
}
// Data Retention Section
// GetDataRetentionPolicy will get the current server data retention policy details.
func (c *Client4) GetDataRetentionPolicy() (*DataRetentionPolicy, *Response) {
if r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", ""); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return DataRetentionPolicyFromJson(r.Body), BuildResponse(r)
}
}
// Commands Section
// CreateCommand will create a new command if the user have the right permissions.
@ -2762,9 +2863,28 @@ func (c *Client4) ListCommands(teamId string, customOnly bool) ([]*Command, *Res
}
}
// ExecuteCommand executes a given command.
// ExecuteCommand executes a given slash command.
func (c *Client4) ExecuteCommand(channelId, command string) (*CommandResponse, *Response) {
commandArgs := &CommandArgs{ChannelId: channelId, Command: command}
commandArgs := &CommandArgs{
ChannelId: channelId,
Command: command,
}
if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return CommandResponseFromJson(r.Body), BuildResponse(r)
}
}
// ExecuteCommand executes a given slash command against the specified team
// Use this when executing slash commands in a DM/GM, since the team id cannot be inferred in that case
func (c *Client4) ExecuteCommandWithTeam(channelId, teamId, command string) (*CommandResponse, *Response) {
commandArgs := &CommandArgs{
ChannelId: channelId,
TeamId: teamId,
Command: command,
}
if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
@ -2849,17 +2969,17 @@ func (c *Client4) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emo
writer := multipart.NewWriter(body)
if part, err := writer.CreateFormFile("image", filename); err != nil {
return nil, &Response{StatusCode: http.StatusForbidden, Error: NewLocAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error())}
return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
} else if _, err = io.Copy(part, bytes.NewBuffer(image)); err != nil {
return nil, &Response{StatusCode: http.StatusForbidden, Error: NewLocAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error())}
return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
}
if err := writer.WriteField("emoji", emoji.ToJson()); err != nil {
return nil, &Response{StatusCode: http.StatusForbidden, Error: NewLocAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error())}
return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error(), 0)}
}
if err := writer.Close(); err != nil {
return nil, &Response{StatusCode: http.StatusForbidden, Error: NewLocAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error())}
return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error(), 0)}
}
return c.DoEmojiUploadFile(c.GetEmojisRoute(), body.Bytes(), writer.FormDataContentType())
@ -3009,3 +3129,97 @@ func (c *Client4) CancelJob(jobId string) (bool, *Response) {
return CheckStatusOK(r), BuildResponse(r)
}
}
// Plugin Section
// UploadPlugin takes an io.Reader stream pointing to the contents of a .tar.gz plugin.
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) {
body := new(bytes.Buffer)
writer := multipart.NewWriter(body)
if part, err := writer.CreateFormFile("plugin", "plugin.tar.gz"); err != nil {
return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
} else if _, err = io.Copy(part, file); err != nil {
return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
}
if err := writer.Close(); err != nil {
return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
}
rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetPluginsRoute(), body)
rq.Header.Set("Content-Type", writer.FormDataContentType())
rq.Close = true
if len(c.AuthToken) > 0 {
rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
}
if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
return nil, BuildErrorResponse(rp, NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), 0))
} else {
defer closeBody(rp)
if rp.StatusCode >= 300 {
return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
} else {
return ManifestFromJson(rp.Body), BuildResponse(rp)
}
}
}
// GetPlugins will return a list of plugin manifests for currently active plugins.
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
func (c *Client4) GetPlugins() (*PluginsResponse, *Response) {
if r, err := c.DoApiGet(c.GetPluginsRoute(), ""); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return PluginsResponseFromJson(r.Body), BuildResponse(r)
}
}
// RemovePlugin will deactivate and delete a plugin.
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
func (c *Client4) RemovePlugin(id string) (bool, *Response) {
if r, err := c.DoApiDelete(c.GetPluginRoute(id)); err != nil {
return false, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return CheckStatusOK(r), BuildResponse(r)
}
}
// GetWebappPlugins will return a list of plugins that the webapp should download.
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
func (c *Client4) GetWebappPlugins() ([]*Manifest, *Response) {
if r, err := c.DoApiGet(c.GetPluginsRoute()+"/webapp", ""); err != nil {
return nil, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return ManifestListFromJson(r.Body), BuildResponse(r)
}
}
// ActivatePlugin will activate an plugin installed.
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
func (c *Client4) ActivatePlugin(id string) (bool, *Response) {
if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/activate", ""); err != nil {
return false, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return CheckStatusOK(r), BuildResponse(r)
}
}
// DeactivatePlugin will deactivate an active plugin.
// WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
func (c *Client4) DeactivatePlugin(id string) (bool, *Response) {
if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/deactivate", ""); err != nil {
return false, BuildErrorResponse(r, err)
} else {
defer closeBody(r)
return CheckStatusOK(r), BuildResponse(r)
}
}

View File

@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
"net/http"
"os"
)
@ -85,27 +86,27 @@ func FilterClusterDiscovery(vs []*ClusterDiscovery, f func(*ClusterDiscovery) bo
func (o *ClusterDiscovery) IsValid() *AppError {
if len(o.Id) != 26 {
return NewLocAppError("Channel.IsValid", "model.channel.is_valid.id.app_error", nil, "")
return NewAppError("Channel.IsValid", "model.channel.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.ClusterName) == 0 {
return NewLocAppError("ClusterDiscovery.IsValid", "ClusterName must be set", nil, "")
return NewAppError("ClusterDiscovery.IsValid", "ClusterName must be set", nil, "", http.StatusBadRequest)
}
if len(o.Type) == 0 {
return NewLocAppError("ClusterDiscovery.IsValid", "Type must be set", nil, "")
return NewAppError("ClusterDiscovery.IsValid", "Type must be set", nil, "", http.StatusBadRequest)
}
if len(o.Hostname) == 0 {
return NewLocAppError("ClusterDiscovery.IsValid", "Hostname must be set", nil, "")
return NewAppError("ClusterDiscovery.IsValid", "Hostname must be set", nil, "", http.StatusBadRequest)
}
if o.CreateAt == 0 {
return NewLocAppError("ClusterDiscovery.IsValid", "CreateAt must be set", nil, "")
return NewAppError("ClusterDiscovery.IsValid", "CreateAt must be set", nil, "", http.StatusBadRequest)
}
if o.LastPingAt == 0 {
return NewLocAppError("ClusterDiscovery.IsValid", "LastPingAt must be set", nil, "")
return NewAppError("ClusterDiscovery.IsValid", "LastPingAt must be set", nil, "", http.StatusBadRequest)
}
return nil

View File

@ -10,6 +10,7 @@ import (
)
type ClusterInfo struct {
Id string `json:"id"`
Version string `json:"version"`
ConfigHash string `json:"config_hash"`
IpAddress string `json:"ipaddress"`

View File

@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
"net/http"
"strings"
)
@ -79,51 +80,51 @@ func CommandListFromJson(data io.Reader) []*Command {
func (o *Command) IsValid() *AppError {
if len(o.Id) != 26 {
return NewLocAppError("Command.IsValid", "model.command.is_valid.id.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.Token) != 26 {
return NewLocAppError("Command.IsValid", "model.command.is_valid.token.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.token.app_error", nil, "", http.StatusBadRequest)
}
if o.CreateAt == 0 {
return NewLocAppError("Command.IsValid", "model.command.is_valid.create_at.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.create_at.app_error", nil, "", http.StatusBadRequest)
}
if o.UpdateAt == 0 {
return NewLocAppError("Command.IsValid", "model.command.is_valid.update_at.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.update_at.app_error", nil, "", http.StatusBadRequest)
}
if len(o.CreatorId) != 26 {
return NewLocAppError("Command.IsValid", "model.command.is_valid.user_id.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.TeamId) != 26 {
return NewLocAppError("Command.IsValid", "model.command.is_valid.team_id.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.team_id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.Trigger) < MIN_TRIGGER_LENGTH || len(o.Trigger) > MAX_TRIGGER_LENGTH || strings.Index(o.Trigger, "/") == 0 || strings.Contains(o.Trigger, " ") {
return NewLocAppError("Command.IsValid", "model.command.is_valid.trigger.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.trigger.app_error", nil, "", http.StatusBadRequest)
}
if len(o.URL) == 0 || len(o.URL) > 1024 {
return NewLocAppError("Command.IsValid", "model.command.is_valid.url.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.url.app_error", nil, "", http.StatusBadRequest)
}
if !IsValidHttpUrl(o.URL) {
return NewLocAppError("Command.IsValid", "model.command.is_valid.url_http.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.url_http.app_error", nil, "", http.StatusBadRequest)
}
if !(o.Method == COMMAND_METHOD_GET || o.Method == COMMAND_METHOD_POST) {
return NewLocAppError("Command.IsValid", "model.command.is_valid.method.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.method.app_error", nil, "", http.StatusBadRequest)
}
if len(o.DisplayName) > 64 {
return NewLocAppError("Command.IsValid", "model.command.is_valid.display_name.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.display_name.app_error", nil, "", http.StatusBadRequest)
}
if len(o.Description) > 128 {
return NewLocAppError("Command.IsValid", "model.command.is_valid.description.app_error", nil, "")
return NewAppError("Command.IsValid", "model.command.is_valid.description.app_error", nil, "", http.StatusBadRequest)
}
return nil

View File

@ -6,6 +6,8 @@ package model
import (
"encoding/json"
"io"
"io/ioutil"
"strings"
)
const (
@ -18,6 +20,8 @@ type CommandResponse struct {
Text string `json:"text"`
Username string `json:"username"`
IconURL string `json:"icon_url"`
Type string `json:"type"`
Props StringInterface `json:"props"`
GotoLocation string `json:"goto_location"`
Attachments []*SlackAttachment `json:"attachments"`
}
@ -31,6 +35,22 @@ func (o *CommandResponse) ToJson() string {
}
}
func CommandResponseFromHTTPBody(contentType string, body io.Reader) *CommandResponse {
if strings.TrimSpace(strings.Split(contentType, ";")[0]) == "application/json" {
return CommandResponseFromJson(body)
}
if b, err := ioutil.ReadAll(body); err == nil {
return CommandResponseFromPlainText(string(b))
}
return nil
}
func CommandResponseFromPlainText(text string) *CommandResponse {
return &CommandResponse{
Text: text,
}
}
func CommandResponseFromJson(data io.Reader) *CommandResponse {
decoder := json.NewDecoder(data)
var o CommandResponse
@ -39,8 +59,7 @@ func CommandResponseFromJson(data io.Reader) *CommandResponse {
return nil
}
o.Text = ExpandAnnouncement(o.Text)
o.Attachments = ProcessSlackAttachments(o.Attachments)
o.Attachments = StringifySlackFieldValue(o.Attachments)
return &o
}

View File

@ -0,0 +1,65 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"net/http"
)
type CommandWebhook struct {
Id string
CreateAt int64
CommandId string
UserId string
ChannelId string
RootId string
ParentId string
UseCount int
}
const (
COMMAND_WEBHOOK_LIFETIME = 1000 * 60 * 30
)
func (o *CommandWebhook) PreSave() {
if o.Id == "" {
o.Id = NewId()
}
if o.CreateAt == 0 {
o.CreateAt = GetMillis()
}
}
func (o *CommandWebhook) IsValid() *AppError {
if len(o.Id) != 26 {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.id.app_error", nil, "", http.StatusBadRequest)
}
if o.CreateAt == 0 {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if len(o.CommandId) != 26 {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.command_id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.UserId) != 26 {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.user_id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.ChannelId) != 26 {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.channel_id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.RootId) != 0 && len(o.RootId) != 26 {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.root_id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.ParentId) != 0 && len(o.ParentId) != 26 {
return NewAppError("CommandWebhook.IsValid", "model.command_hook.parent_id.app_error", nil, "", http.StatusBadRequest)
}
return nil
}

View File

@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
"net/http"
"strings"
)
@ -75,27 +76,27 @@ func (me *Compliance) JobName() string {
func (me *Compliance) IsValid() *AppError {
if len(me.Id) != 26 {
return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.id.app_error", nil, "")
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
if me.CreateAt == 0 {
return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.create_at.app_error", nil, "")
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.create_at.app_error", nil, "", http.StatusBadRequest)
}
if len(me.Desc) > 512 || len(me.Desc) == 0 {
return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.desc.app_error", nil, "")
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.desc.app_error", nil, "", http.StatusBadRequest)
}
if me.StartAt == 0 {
return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.start_at.app_error", nil, "")
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.start_at.app_error", nil, "", http.StatusBadRequest)
}
if me.EndAt == 0 {
return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.end_at.app_error", nil, "")
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.end_at.app_error", nil, "", http.StatusBadRequest)
}
if me.EndAt <= me.StartAt {
return NewLocAppError("Compliance.IsValid", "model.compliance.is_valid.start_end_at.app_error", nil, "")
return NewAppError("Compliance.IsValid", "model.compliance.is_valid.start_end_at.app_error", nil, "", http.StatusBadRequest)
}
return nil

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"encoding/json"
"io"
)
type DataRetentionPolicy struct {
MessageDeletionEnabled bool `json:"message_deletion_enabled"`
FileDeletionEnabled bool `json:"file_deletion_enabled"`
MessageRetentionCutoff int64 `json:"message_retention_cutoff"`
FileRetentionCutoff int64 `json:"file_retention_cutoff"`
}
func (me *DataRetentionPolicy) ToJson() string {
b, err := json.Marshal(me)
if err != nil {
return ""
} else {
return string(b)
}
}
func DataRetentionPolicyFromJson(data io.Reader) *DataRetentionPolicy {
decoder := json.NewDecoder(data)
var me DataRetentionPolicy
err := decoder.Decode(&me)
if err == nil {
return &me
} else {
return nil
}
}

View File

@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
"net/http"
)
type Emoji struct {
@ -19,23 +20,23 @@ type Emoji struct {
func (emoji *Emoji) IsValid() *AppError {
if len(emoji.Id) != 26 {
return NewLocAppError("Emoji.IsValid", "model.emoji.id.app_error", nil, "")
return NewAppError("Emoji.IsValid", "model.emoji.id.app_error", nil, "", http.StatusBadRequest)
}
if emoji.CreateAt == 0 {
return NewLocAppError("Emoji.IsValid", "model.emoji.create_at.app_error", nil, "id="+emoji.Id)
return NewAppError("Emoji.IsValid", "model.emoji.create_at.app_error", nil, "id="+emoji.Id, http.StatusBadRequest)
}
if emoji.UpdateAt == 0 {
return NewLocAppError("Emoji.IsValid", "model.emoji.update_at.app_error", nil, "id="+emoji.Id)
return NewAppError("Emoji.IsValid", "model.emoji.update_at.app_error", nil, "id="+emoji.Id, http.StatusBadRequest)
}
if len(emoji.CreatorId) != 26 {
return NewLocAppError("Emoji.IsValid", "model.emoji.user_id.app_error", nil, "")
return NewAppError("Emoji.IsValid", "model.emoji.user_id.app_error", nil, "", http.StatusBadRequest)
}
if len(emoji.Name) == 0 || len(emoji.Name) > 64 || !IsValidAlphaNumHyphenUnderscore(emoji.Name, false) {
return NewLocAppError("Emoji.IsValid", "model.emoji.name.app_error", nil, "")
return NewAppError("Emoji.IsValid", "model.emoji.name.app_error", nil, "", http.StatusBadRequest)
}
return nil

View File

@ -10,6 +10,7 @@ import (
"image/gif"
"io"
"mime"
"net/http"
"path/filepath"
"strings"
)
@ -80,33 +81,36 @@ func (o *FileInfo) PreSave() {
if o.CreateAt == 0 {
o.CreateAt = GetMillis()
}
if o.UpdateAt < o.CreateAt {
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, "")
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.CreatorId) != 26 {
return NewLocAppError("FileInfo.IsValid", "model.file_info.is_valid.user_id.app_error", nil, "id="+o.Id)
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.user_id.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
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)
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.post_id.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if o.CreateAt == 0 {
return NewLocAppError("FileInfo.IsValid", "model.file_info.is_valid.create_at.app_error", nil, "id="+o.Id)
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if o.UpdateAt == 0 {
return NewLocAppError("FileInfo.IsValid", "model.file_info.is_valid.update_at.app_error", nil, "id="+o.Id)
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if o.Path == "" {
return NewLocAppError("FileInfo.IsValid", "model.file_info.is_valid.path.app_error", nil, "id="+o.Id)
return NewAppError("FileInfo.IsValid", "model.file_info.is_valid.path.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
return nil
@ -144,7 +148,7 @@ func GetInfoForBytes(name string, data []byte) (*FileInfo, *AppError) {
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)
err = NewAppError("GetInfoForBytes", "model.file_info.get.gif.app_error", nil, "name="+name, http.StatusBadRequest)
} else {
info.HasPreviewImage = len(gifConfig.Image) == 1
}

View File

@ -5,11 +5,12 @@ package oauthgitlab
import (
"encoding/json"
"github.com/mattermost/platform/einterfaces"
"github.com/mattermost/platform/model"
"io"
"strconv"
"strings"
"github.com/mattermost/mattermost-server/einterfaces"
"github.com/mattermost/mattermost-server/model"
)
type GitLabProvider struct {
@ -45,7 +46,6 @@ func userFromGitLabUser(glu *GitLabUser) *model.User {
} else {
user.FirstName = glu.Name
}
strings.TrimSpace(user.Email)
user.Email = glu.Email
userId := strconv.FormatInt(glu.Id, 10)
user.AuthData = &userId

View File

@ -25,6 +25,8 @@ type IncomingWebhook struct {
TeamId string `json:"team_id"`
DisplayName string `json:"display_name"`
Description string `json:"description"`
Username string `json:"username"`
IconURL string `json:"icon_url"`
}
type IncomingWebhookRequest struct {
@ -112,6 +114,14 @@ func (o *IncomingWebhook) IsValid() *AppError {
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.description.app_error", nil, "", http.StatusBadRequest)
}
if len(o.Username) > 64 {
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.username.app_error", nil, "", http.StatusBadRequest)
}
if len(o.IconURL) > 1024 {
return NewAppError("IncomingWebhook.IsValid", "model.incoming_hook.icon_url.app_error", nil, "", http.StatusBadRequest)
}
return nil
}
@ -193,7 +203,7 @@ func decodeIncomingWebhookRequest(by []byte) (*IncomingWebhookRequest, error) {
}
}
func IncomingWebhookRequestFromJson(data io.Reader) *IncomingWebhookRequest {
func IncomingWebhookRequestFromJson(data io.Reader) (*IncomingWebhookRequest, *AppError) {
buf := new(bytes.Buffer)
buf.ReadFrom(data)
by := buf.Bytes()
@ -204,12 +214,11 @@ func IncomingWebhookRequestFromJson(data io.Reader) *IncomingWebhookRequest {
if err != nil {
o, err = decodeIncomingWebhookRequest(escapeControlCharsFromPayload(by))
if err != nil {
return nil
return nil, NewAppError("IncomingWebhookRequestFromJson", "Unable to parse incoming data", nil, err.Error(), http.StatusBadRequest)
}
}
o.Text = ExpandAnnouncement(o.Text)
o.Attachments = ProcessSlackAttachments(o.Attachments)
o.Attachments = StringifySlackFieldValue(o.Attachments)
return o
return o, nil
}

View File

@ -7,11 +7,15 @@ import (
"encoding/json"
"io"
"net/http"
"time"
)
const (
JOB_TYPE_DATA_RETENTION = "data_retention"
JOB_TYPE_ELASTICSEARCH_POST_INDEXING = "elasticsearch_post_indexing"
JOB_TYPE_DATA_RETENTION = "data_retention"
JOB_TYPE_MESSAGE_EXPORT = "message_export"
JOB_TYPE_ELASTICSEARCH_POST_INDEXING = "elasticsearch_post_indexing"
JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION = "elasticsearch_post_aggregation"
JOB_TYPE_LDAP_SYNC = "ldap_sync"
JOB_STATUS_PENDING = "pending"
JOB_STATUS_IN_PROGRESS = "in_progress"
@ -22,15 +26,15 @@ const (
)
type Job struct {
Id string `json:"id"`
Type string `json:"type"`
Priority int64 `json:"priority"`
CreateAt int64 `json:"create_at"`
StartAt int64 `json:"start_at"`
LastActivityAt int64 `json:"last_activity_at"`
Status string `json:"status"`
Progress int64 `json:"progress"`
Data map[string]interface{} `json:"data"`
Id string `json:"id"`
Type string `json:"type"`
Priority int64 `json:"priority"`
CreateAt int64 `json:"create_at"`
StartAt int64 `json:"start_at"`
LastActivityAt int64 `json:"last_activity_at"`
Status string `json:"status"`
Progress int64 `json:"progress"`
Data map[string]string `json:"data"`
}
func (j *Job) IsValid() *AppError {
@ -45,6 +49,9 @@ func (j *Job) IsValid() *AppError {
switch j.Type {
case JOB_TYPE_DATA_RETENTION:
case JOB_TYPE_ELASTICSEARCH_POST_INDEXING:
case JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION:
case JOB_TYPE_LDAP_SYNC:
case JOB_TYPE_MESSAGE_EXPORT:
default:
return NewAppError("Job.IsValid", "model.job.is_valid.type.app_error", nil, "id="+j.Id, http.StatusBadRequest)
}
@ -112,6 +119,9 @@ type Worker interface {
}
type Scheduler interface {
Run()
Stop()
Name() string
JobType() string
Enabled(cfg *Config) bool
NextScheduleTime(cfg *Config, now time.Time, pendingJobs bool, lastSuccessfulJob *Job) *time.Time
ScheduleJob(cfg *Config, pendingJobs bool, lastSuccessfulJob *Job) (*Job, *AppError)
}

View File

@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
"net/http"
)
const (
@ -51,7 +52,10 @@ type Features struct {
PasswordRequirements *bool `json:"password_requirements"`
Elasticsearch *bool `json:"elastic_search"`
Announcement *bool `json:"announcement"`
ThemeManagement *bool `json:"theme_management"`
EmailNotificationContents *bool `json:"email_notification_contents"`
DataRetention *bool `json:"data_retention"`
MessageExport *bool `json:"message_export"`
// after we enabled more features for webrtc we'll need to control them with this
FutureFeatures *bool `json:"future_features"`
@ -72,106 +76,96 @@ func (f *Features) ToMap() map[string]interface{} {
"password": *f.PasswordRequirements,
"elastic_search": *f.Elasticsearch,
"email_notification_contents": *f.EmailNotificationContents,
"data_retention": *f.DataRetention,
"message_export": *f.MessageExport,
"future": *f.FutureFeatures,
}
}
func (f *Features) SetDefaults() {
if f.FutureFeatures == nil {
f.FutureFeatures = new(bool)
*f.FutureFeatures = true
f.FutureFeatures = NewBool(true)
}
if f.Users == nil {
f.Users = new(int)
*f.Users = 0
f.Users = NewInt(0)
}
if f.LDAP == nil {
f.LDAP = new(bool)
*f.LDAP = *f.FutureFeatures
f.LDAP = NewBool(*f.FutureFeatures)
}
if f.MFA == nil {
f.MFA = new(bool)
*f.MFA = *f.FutureFeatures
f.MFA = NewBool(*f.FutureFeatures)
}
if f.GoogleOAuth == nil {
f.GoogleOAuth = new(bool)
*f.GoogleOAuth = *f.FutureFeatures
f.GoogleOAuth = NewBool(*f.FutureFeatures)
}
if f.Office365OAuth == nil {
f.Office365OAuth = new(bool)
*f.Office365OAuth = *f.FutureFeatures
f.Office365OAuth = NewBool(*f.FutureFeatures)
}
if f.Compliance == nil {
f.Compliance = new(bool)
*f.Compliance = *f.FutureFeatures
f.Compliance = NewBool(*f.FutureFeatures)
}
if f.Cluster == nil {
f.Cluster = new(bool)
*f.Cluster = *f.FutureFeatures
f.Cluster = NewBool(*f.FutureFeatures)
}
if f.Metrics == nil {
f.Metrics = new(bool)
*f.Metrics = *f.FutureFeatures
f.Metrics = NewBool(*f.FutureFeatures)
}
if f.CustomBrand == nil {
f.CustomBrand = new(bool)
*f.CustomBrand = *f.FutureFeatures
f.CustomBrand = NewBool(*f.FutureFeatures)
}
if f.MHPNS == nil {
f.MHPNS = new(bool)
*f.MHPNS = *f.FutureFeatures
f.MHPNS = NewBool(*f.FutureFeatures)
}
if f.SAML == nil {
f.SAML = new(bool)
*f.SAML = *f.FutureFeatures
f.SAML = NewBool(*f.FutureFeatures)
}
if f.PasswordRequirements == nil {
f.PasswordRequirements = new(bool)
*f.PasswordRequirements = *f.FutureFeatures
f.PasswordRequirements = NewBool(*f.FutureFeatures)
}
if f.Elasticsearch == nil {
f.Elasticsearch = new(bool)
*f.Elasticsearch = *f.FutureFeatures
f.Elasticsearch = NewBool(*f.FutureFeatures)
}
if f.Announcement == nil {
f.Announcement = new(bool)
*f.Announcement = true
f.Announcement = NewBool(true)
}
if f.ThemeManagement == nil {
f.ThemeManagement = NewBool(true)
}
if f.EmailNotificationContents == nil {
f.EmailNotificationContents = new(bool)
*f.EmailNotificationContents = *f.FutureFeatures
f.EmailNotificationContents = NewBool(*f.FutureFeatures)
}
if f.DataRetention == nil {
f.DataRetention = NewBool(*f.FutureFeatures)
}
if f.MessageExport == nil {
f.MessageExport = NewBool(*f.FutureFeatures)
}
}
func (l *License) IsExpired() bool {
now := GetMillis()
if l.ExpiresAt < now {
return true
}
return false
return l.ExpiresAt < GetMillis()
}
func (l *License) IsStarted() bool {
now := GetMillis()
if l.StartsAt < now {
return true
}
return false
return l.StartsAt < GetMillis()
}
func (l *License) ToJson() string {
@ -196,15 +190,15 @@ func LicenseFromJson(data io.Reader) *License {
func (lr *LicenseRecord) IsValid() *AppError {
if len(lr.Id) != 26 {
return NewLocAppError("LicenseRecord.IsValid", "model.license_record.is_valid.id.app_error", nil, "")
return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
if lr.CreateAt == 0 {
return NewLocAppError("LicenseRecord.IsValid", "model.license_record.is_valid.create_at.app_error", nil, "")
return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.create_at.app_error", nil, "", http.StatusBadRequest)
}
if len(lr.Bytes) == 0 || len(lr.Bytes) > 10000 {
return NewLocAppError("LicenseRecord.IsValid", "model.license_record.is_valid.create_at.app_error", nil, "")
return NewAppError("LicenseRecord.IsValid", "model.license_record.is_valid.create_at.app_error", nil, "", http.StatusBadRequest)
}
return nil

246
vendor/github.com/mattermost/platform/model/manifest.go generated vendored Normal file
View File

@ -0,0 +1,246 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"encoding/json"
"io"
"io/ioutil"
"os"
"path/filepath"
"gopkg.in/yaml.v2"
)
const (
PLUGIN_CONFIG_TYPE_TEXT = "text"
PLUGIN_CONFIG_TYPE_BOOL = "bool"
PLUGIN_CONFIG_TYPE_RADIO = "radio"
PLUGIN_CONFIG_TYPE_DROPDOWN = "dropdown"
PLUGIN_CONFIG_TYPE_GENERATED = "generated"
PLUGIN_CONFIG_TYPE_USERNAME = "username"
)
type PluginOption struct {
// The display name for the option.
DisplayName string `json:"display_name" yaml:"display_name"`
// The string value for the option.
Value string `json:"value" yaml:"value"`
}
type PluginSetting struct {
// The key that the setting will be assigned to in the configuration file.
Key string `json:"key" yaml:"key"`
// The display name for the setting.
DisplayName string `json:"display_name" yaml:"display_name"`
// The type of the setting.
//
// "bool" will result in a boolean true or false setting.
//
// "dropdown" will result in a string setting that allows the user to select from a list of
// pre-defined options.
//
// "generated" will result in a string setting that is set to a random, cryptographically secure
// string.
//
// "radio" will result in a string setting that allows the user to select from a short selection
// of pre-defined options.
//
// "text" will result in a string setting that can be typed in manually.
//
// "username" will result in a text setting that will autocomplete to a username.
Type string `json:"type" yaml:"type"`
// The help text to display to the user.
HelpText string `json:"help_text" yaml:"help_text"`
// The help text to display alongside the "Regenerate" button for settings of the "generated" type.
RegenerateHelpText string `json:"regenerate_help_text,omitempty" yaml:"regenerate_help_text,omitempty"`
// The placeholder to display for "text", "generated" and "username" types when blank.
Placeholder string `json:"placeholder" yaml:"placeholder"`
// The default value of the setting.
Default interface{} `json:"default" yaml:"default"`
// For "radio" or "dropdown" settings, this is the list of pre-defined options that the user can choose
// from.
Options []*PluginOption `json:"options,omitempty" yaml:"options,omitempty"`
}
type PluginSettingsSchema struct {
// Optional text to display above the settings.
Header string `json:"header" yaml:"header"`
// Optional text to display below the settings.
Footer string `json:"footer" yaml:"footer"`
// A list of setting definitions.
Settings []*PluginSetting `json:"settings" yaml:"settings"`
}
// The plugin manifest defines the metadata required to load and present your plugin. The manifest
// file should be named plugin.json or plugin.yaml and placed in the top of your
// plugin bundle.
//
// Example plugin.yaml:
//
// id: com.mycompany.myplugin
// name: My Plugin
// description: This is my plugin. It does stuff.
// backend:
// executable: myplugin
// settings_schema:
// settings:
// - key: enable_extra_thing
// type: bool
// display_name: Enable Extra Thing
// help_text: When true, an extra thing will be enabled!
// default: false
type Manifest struct {
// The id is a globally unique identifier that represents your plugin. Ids are limited
// to 190 characters. Reverse-DNS notation using a name you control is a good option.
// For example, "com.mycompany.myplugin".
Id string `json:"id" yaml:"id"`
// The name to be displayed for the plugin.
Name string `json:"name,omitempty" yaml:"name,omitempty"`
// A description of what your plugin is and does.
Description string `json:"description,omitempty" yaml:"description,omitempty"`
// A version number for your plugin. Semantic versioning is recommended: http://semver.org
Version string `json:"version" yaml:"version"`
// If your plugin extends the server, you'll need define backend.
Backend *ManifestBackend `json:"backend,omitempty" yaml:"backend,omitempty"`
// If your plugin extends the web app, you'll need to define webapp.
Webapp *ManifestWebapp `json:"webapp,omitempty" yaml:"webapp,omitempty"`
// To allow administrators to configure your plugin via the Mattermost system console, you can
// provide your settings schema.
SettingsSchema *PluginSettingsSchema `json:"settings_schema,omitempty" yaml:"settings_schema,omitempty"`
}
type ManifestBackend struct {
// The path to your executable binary. This should be relative to the root of your bundle and the
// location of the manifest file.
//
// On Windows, this file must have a ".exe" extension.
Executable string `json:"executable" yaml:"executable"`
}
type ManifestWebapp struct {
// The path to your webapp bundle. This should be relative to the root of your bundle and the
// location of the manifest file.
BundlePath string `json:"bundle_path" yaml:"bundle_path"`
}
func (m *Manifest) ToJson() string {
b, err := json.Marshal(m)
if err != nil {
return ""
} else {
return string(b)
}
}
func ManifestListToJson(m []*Manifest) string {
b, err := json.Marshal(m)
if err != nil {
return ""
} else {
return string(b)
}
}
func ManifestFromJson(data io.Reader) *Manifest {
decoder := json.NewDecoder(data)
var m Manifest
err := decoder.Decode(&m)
if err == nil {
return &m
} else {
return nil
}
}
func ManifestListFromJson(data io.Reader) []*Manifest {
decoder := json.NewDecoder(data)
var manifests []*Manifest
err := decoder.Decode(&manifests)
if err == nil {
return manifests
} else {
return nil
}
}
func (m *Manifest) HasClient() bool {
return m.Webapp != nil
}
func (m *Manifest) ClientManifest() *Manifest {
cm := new(Manifest)
*cm = *m
cm.Name = ""
cm.Description = ""
cm.Backend = nil
return cm
}
// FindManifest will find and parse the manifest in a given directory.
//
// In all cases other than a does-not-exist error, path is set to the path of the manifest file that was
// found.
//
// Manifests are JSON or YAML files named plugin.json, plugin.yaml, or plugin.yml.
func FindManifest(dir string) (manifest *Manifest, path string, err error) {
for _, name := range []string{"plugin.yml", "plugin.yaml"} {
path = filepath.Join(dir, name)
f, ferr := os.Open(path)
if ferr != nil {
if !os.IsNotExist(ferr) {
err = ferr
return
}
continue
}
b, ioerr := ioutil.ReadAll(f)
f.Close()
if ioerr != nil {
err = ioerr
return
}
var parsed Manifest
err = yaml.Unmarshal(b, &parsed)
if err != nil {
return
}
manifest = &parsed
return
}
path = filepath.Join(dir, "plugin.json")
f, ferr := os.Open(path)
if ferr != nil {
if os.IsNotExist(ferr) {
path = ""
}
err = ferr
return
}
defer f.Close()
var parsed Manifest
err = json.NewDecoder(f).Decode(&parsed)
if err != nil {
return
}
manifest = &parsed
return
}

View File

@ -0,0 +1,18 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
type MessageExport struct {
ChannelId *string
ChannelDisplayName *string
UserId *string
UserEmail *string
PostId *string
PostCreateAt *int64
PostMessage *string
PostType *string
PostFileIds StringArray
}

View File

@ -45,6 +45,17 @@ type OutgoingWebhookPayload struct {
FileIds string `json:"file_ids"`
}
type OutgoingWebhookResponse struct {
Text *string `json:"text"`
Username string `json:"username"`
IconURL string `json:"icon_url"`
Props StringInterface `json:"props"`
Type string `json:"type"`
ResponseType string `json:"response_type"`
}
const OUTGOING_HOOK_RESPONSE_TYPE_COMMENT = "comment"
func (o *OutgoingWebhookPayload) ToJSON() string {
b, err := json.Marshal(o)
if err != nil {
@ -112,6 +123,26 @@ func OutgoingWebhookListFromJson(data io.Reader) []*OutgoingWebhook {
}
}
func (o *OutgoingWebhookResponse) ToJson() string {
b, err := json.Marshal(o)
if err != nil {
return ""
} else {
return string(b)
}
}
func OutgoingWebhookResponseFromJson(data io.Reader) *OutgoingWebhookResponse {
decoder := json.NewDecoder(data)
var o OutgoingWebhookResponse
err := decoder.Decode(&o)
if err == nil {
return &o
} else {
return nil
}
}
func (o *OutgoingWebhook) IsValid() *AppError {
if len(o.Id) != 26 {

View File

@ -0,0 +1,32 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"net/http"
"unicode/utf8"
)
const (
KEY_VALUE_PLUGIN_ID_MAX_RUNES = 190
KEY_VALUE_KEY_MAX_RUNES = 50
)
type PluginKeyValue struct {
PluginId string `json:"plugin_id"`
Key string `json:"key" db:"PKey"`
Value []byte `json:"value" db:"PValue"`
}
func (kv *PluginKeyValue) IsValid() *AppError {
if len(kv.PluginId) == 0 || utf8.RuneCountInString(kv.PluginId) > KEY_VALUE_PLUGIN_ID_MAX_RUNES {
return NewAppError("PluginKeyValue.IsValid", "model.plugin_key_value.is_valid.plugin_id.app_error", map[string]interface{}{"Max": KEY_VALUE_KEY_MAX_RUNES, "Min": 0}, "key="+kv.Key, http.StatusBadRequest)
}
if len(kv.Key) == 0 || utf8.RuneCountInString(kv.Key) > KEY_VALUE_KEY_MAX_RUNES {
return NewAppError("PluginKeyValue.IsValid", "model.plugin_key_value.is_valid.key.app_error", map[string]interface{}{"Max": KEY_VALUE_KEY_MAX_RUNES, "Min": 0}, "key="+kv.Key, http.StatusBadRequest)
}
return nil
}

View File

@ -0,0 +1,39 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"encoding/json"
"io"
)
type PluginInfo struct {
Manifest
Prepackaged bool `json:"prepackaged"`
}
type PluginsResponse struct {
Active []*PluginInfo `json:"active"`
Inactive []*PluginInfo `json:"inactive"`
}
func (m *PluginsResponse) ToJson() string {
b, err := json.Marshal(m)
if err != nil {
return ""
} else {
return string(b)
}
}
func PluginsResponseFromJson(data io.Reader) *PluginsResponse {
decoder := json.NewDecoder(data)
var m PluginsResponse
err := decoder.Decode(&m)
if err == nil {
return &m
} else {
return nil
}
}

View File

@ -6,6 +6,9 @@ package model
import (
"encoding/json"
"io"
"net/http"
"regexp"
"strings"
"unicode/utf8"
)
@ -17,9 +20,13 @@ const (
POST_JOIN_LEAVE = "system_join_leave" // Deprecated, use POST_JOIN_CHANNEL or POST_LEAVE_CHANNEL instead
POST_JOIN_CHANNEL = "system_join_channel"
POST_LEAVE_CHANNEL = "system_leave_channel"
POST_JOIN_TEAM = "system_join_team"
POST_LEAVE_TEAM = "system_leave_team"
POST_ADD_REMOVE = "system_add_remove" // Deprecated, use POST_ADD_TO_CHANNEL or POST_REMOVE_FROM_CHANNEL instead
POST_ADD_TO_CHANNEL = "system_add_to_channel"
POST_REMOVE_FROM_CHANNEL = "system_remove_from_channel"
POST_ADD_TO_TEAM = "system_add_to_team"
POST_REMOVE_FROM_TEAM = "system_remove_from_team"
POST_HEADER_CHANGE = "system_header_change"
POST_DISPLAYNAME_CHANGE = "system_displayname_change"
POST_PURPOSE_CHANGE = "system_purpose_change"
@ -30,6 +37,9 @@ const (
POST_HASHTAGS_MAX_RUNES = 1000
POST_MESSAGE_MAX_RUNES = 4000
POST_PROPS_MAX_RUNES = 8000
POST_PROPS_MAX_USER_RUNES = POST_PROPS_MAX_RUNES - 400 // Leave some room for system / pre-save modifications
POST_CUSTOM_TYPE_PREFIX = "custom_"
PROPS_ADD_CHANNEL_MEMBER = "add_channel_member"
)
type Post struct {
@ -68,8 +78,31 @@ type PostForIndexing struct {
ParentCreateAt *int64 `json:"parent_create_at"`
}
type PostAction struct {
Id string `json:"id"`
Name string `json:"name"`
Integration *PostActionIntegration `json:"integration,omitempty"`
}
type PostActionIntegration struct {
URL string `json:"url,omitempty"`
Context StringInterface `json:"context,omitempty"`
}
type PostActionIntegrationRequest struct {
UserId string `json:"user_id"`
Context StringInterface `json:"context,omitempty"`
}
type PostActionIntegrationResponse struct {
Update *Post `json:"update"`
EphemeralText string `json:"ephemeral_text"`
}
func (o *Post) ToJson() string {
b, err := json.Marshal(o)
copy := *o
copy.StripActionIntegrations()
b, err := json.Marshal(&copy)
if err != nil {
return ""
} else {
@ -95,73 +128,100 @@ func (o *Post) Etag() string {
func (o *Post) IsValid() *AppError {
if len(o.Id) != 26 {
return NewLocAppError("Post.IsValid", "model.post.is_valid.id.app_error", nil, "")
return NewAppError("Post.IsValid", "model.post.is_valid.id.app_error", nil, "", http.StatusBadRequest)
}
if o.CreateAt == 0 {
return NewLocAppError("Post.IsValid", "model.post.is_valid.create_at.app_error", nil, "id="+o.Id)
return NewAppError("Post.IsValid", "model.post.is_valid.create_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if o.UpdateAt == 0 {
return NewLocAppError("Post.IsValid", "model.post.is_valid.update_at.app_error", nil, "id="+o.Id)
return NewAppError("Post.IsValid", "model.post.is_valid.update_at.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if len(o.UserId) != 26 {
return NewLocAppError("Post.IsValid", "model.post.is_valid.user_id.app_error", nil, "")
return NewAppError("Post.IsValid", "model.post.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.ChannelId) != 26 {
return NewLocAppError("Post.IsValid", "model.post.is_valid.channel_id.app_error", nil, "")
return NewAppError("Post.IsValid", "model.post.is_valid.channel_id.app_error", nil, "", http.StatusBadRequest)
}
if !(len(o.RootId) == 26 || len(o.RootId) == 0) {
return NewLocAppError("Post.IsValid", "model.post.is_valid.root_id.app_error", nil, "")
return NewAppError("Post.IsValid", "model.post.is_valid.root_id.app_error", nil, "", http.StatusBadRequest)
}
if !(len(o.ParentId) == 26 || len(o.ParentId) == 0) {
return NewLocAppError("Post.IsValid", "model.post.is_valid.parent_id.app_error", nil, "")
return NewAppError("Post.IsValid", "model.post.is_valid.parent_id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.ParentId) == 26 && len(o.RootId) == 0 {
return NewLocAppError("Post.IsValid", "model.post.is_valid.root_parent.app_error", nil, "")
return NewAppError("Post.IsValid", "model.post.is_valid.root_parent.app_error", nil, "", http.StatusBadRequest)
}
if !(len(o.OriginalId) == 26 || len(o.OriginalId) == 0) {
return NewLocAppError("Post.IsValid", "model.post.is_valid.original_id.app_error", nil, "")
return NewAppError("Post.IsValid", "model.post.is_valid.original_id.app_error", nil, "", http.StatusBadRequest)
}
if utf8.RuneCountInString(o.Message) > POST_MESSAGE_MAX_RUNES {
return NewLocAppError("Post.IsValid", "model.post.is_valid.msg.app_error", nil, "id="+o.Id)
return NewAppError("Post.IsValid", "model.post.is_valid.msg.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if utf8.RuneCountInString(o.Hashtags) > POST_HASHTAGS_MAX_RUNES {
return NewLocAppError("Post.IsValid", "model.post.is_valid.hashtags.app_error", nil, "id="+o.Id)
return NewAppError("Post.IsValid", "model.post.is_valid.hashtags.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
// should be removed once more message types are supported
if !(o.Type == POST_DEFAULT || o.Type == POST_JOIN_LEAVE || o.Type == POST_ADD_REMOVE ||
o.Type == POST_JOIN_CHANNEL || o.Type == POST_LEAVE_CHANNEL ||
o.Type == POST_REMOVE_FROM_CHANNEL || o.Type == POST_ADD_TO_CHANNEL ||
o.Type == POST_SLACK_ATTACHMENT || o.Type == POST_HEADER_CHANGE || o.Type == POST_PURPOSE_CHANGE ||
o.Type == POST_DISPLAYNAME_CHANGE || o.Type == POST_CHANNEL_DELETED) {
return NewLocAppError("Post.IsValid", "model.post.is_valid.type.app_error", nil, "id="+o.Type)
switch o.Type {
case
POST_DEFAULT,
POST_JOIN_LEAVE,
POST_ADD_REMOVE,
POST_JOIN_CHANNEL,
POST_LEAVE_CHANNEL,
POST_JOIN_TEAM,
POST_LEAVE_TEAM,
POST_ADD_TO_CHANNEL,
POST_REMOVE_FROM_CHANNEL,
POST_ADD_TO_TEAM,
POST_REMOVE_FROM_TEAM,
POST_SLACK_ATTACHMENT,
POST_HEADER_CHANGE,
POST_PURPOSE_CHANGE,
POST_DISPLAYNAME_CHANGE,
POST_CHANNEL_DELETED:
default:
if !strings.HasPrefix(o.Type, POST_CUSTOM_TYPE_PREFIX) {
return NewAppError("Post.IsValid", "model.post.is_valid.type.app_error", nil, "id="+o.Type, http.StatusBadRequest)
}
}
if utf8.RuneCountInString(ArrayToJson(o.Filenames)) > POST_FILENAMES_MAX_RUNES {
return NewLocAppError("Post.IsValid", "model.post.is_valid.filenames.app_error", nil, "id="+o.Id)
return NewAppError("Post.IsValid", "model.post.is_valid.filenames.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if utf8.RuneCountInString(ArrayToJson(o.FileIds)) > POST_FILEIDS_MAX_RUNES {
return NewLocAppError("Post.IsValid", "model.post.is_valid.file_ids.app_error", nil, "id="+o.Id)
return NewAppError("Post.IsValid", "model.post.is_valid.file_ids.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
if utf8.RuneCountInString(StringInterfaceToJson(o.Props)) > POST_PROPS_MAX_RUNES {
return NewLocAppError("Post.IsValid", "model.post.is_valid.props.app_error", nil, "id="+o.Id)
return NewAppError("Post.IsValid", "model.post.is_valid.props.app_error", nil, "id="+o.Id, http.StatusBadRequest)
}
return nil
}
func (o *Post) SanitizeProps() {
membersToSanitize := []string{
PROPS_ADD_CHANNEL_MEMBER,
}
for _, member := range membersToSanitize {
if _, ok := o.Props[member]; ok {
delete(o.Props, member)
}
}
}
func (o *Post) PreSave() {
if o.Id == "" {
o.Id = NewId()
@ -174,7 +234,10 @@ func (o *Post) PreSave() {
}
o.UpdateAt = o.CreateAt
o.PreCommit()
}
func (o *Post) PreCommit() {
if o.Props == nil {
o.Props = make(map[string]interface{})
}
@ -186,6 +249,8 @@ func (o *Post) PreSave() {
if o.FileIds == nil {
o.FileIds = []string{}
}
o.GenerateActionIds()
}
func (o *Post) MakeNonNil() {
@ -246,3 +311,84 @@ func PostPatchFromJson(data io.Reader) *PostPatch {
return &post
}
var channelMentionRegexp = regexp.MustCompile(`\B~[a-zA-Z0-9\-_]+`)
func (o *Post) ChannelMentions() (names []string) {
if strings.Contains(o.Message, "~") {
alreadyMentioned := make(map[string]bool)
for _, match := range channelMentionRegexp.FindAllString(o.Message, -1) {
name := match[1:]
if !alreadyMentioned[name] {
names = append(names, name)
alreadyMentioned[name] = true
}
}
}
return
}
func (r *PostActionIntegrationRequest) ToJson() string {
b, err := json.Marshal(r)
if err != nil {
return ""
} else {
return string(b)
}
}
func (o *Post) Attachments() []*SlackAttachment {
if attachments, ok := o.Props["attachments"].([]*SlackAttachment); ok {
return attachments
}
var ret []*SlackAttachment
if attachments, ok := o.Props["attachments"].([]interface{}); ok {
for _, attachment := range attachments {
if enc, err := json.Marshal(attachment); err == nil {
var decoded SlackAttachment
if json.Unmarshal(enc, &decoded) == nil {
ret = append(ret, &decoded)
}
}
}
}
return ret
}
func (o *Post) StripActionIntegrations() {
attachments := o.Attachments()
if o.Props["attachments"] != nil {
o.Props["attachments"] = attachments
}
for _, attachment := range attachments {
for _, action := range attachment.Actions {
action.Integration = nil
}
}
}
func (o *Post) GetAction(id string) *PostAction {
for _, attachment := range o.Attachments() {
for _, action := range attachment.Actions {
if action.Id == id {
return action
}
}
}
return nil
}
func (o *Post) GenerateActionIds() {
if o.Props["attachments"] != nil {
o.Props["attachments"] = o.Attachments()
}
if attachments, ok := o.Props["attachments"].([]*SlackAttachment); ok {
for _, attachment := range attachments {
for _, action := range attachment.Actions {
if action.Id == "" {
action.Id = NewId()
}
}
}
}
}

View File

@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
"sort"
)
type PostList struct {
@ -20,8 +21,20 @@ func NewPostList() *PostList {
}
}
func (o *PostList) StripActionIntegrations() {
posts := o.Posts
o.Posts = make(map[string]*Post)
for id, post := range posts {
pcopy := *post
pcopy.StripActionIntegrations()
o.Posts[id] = &pcopy
}
}
func (o *PostList) ToJson() string {
b, err := json.Marshal(o)
copy := *o
copy.StripActionIntegrations()
b, err := json.Marshal(&copy)
if err != nil {
return ""
} else {
@ -70,6 +83,12 @@ func (o *PostList) Extend(other *PostList) {
}
}
func (o *PostList) SortByCreateAt() {
sort.Slice(o.Order, func(i, j int) bool {
return o.Posts[o.Order[i]].CreateAt > o.Posts[o.Order[j]].CreateAt
})
}
func (o *PostList) Etag() string {
id := "0"

View File

@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
"net/http"
"regexp"
"strings"
"unicode/utf8"
@ -67,25 +68,25 @@ func PreferenceFromJson(data io.Reader) *Preference {
func (o *Preference) IsValid() *AppError {
if len(o.UserId) != 26 {
return NewLocAppError("Preference.IsValid", "model.preference.is_valid.id.app_error", nil, "user_id="+o.UserId)
return NewAppError("Preference.IsValid", "model.preference.is_valid.id.app_error", nil, "user_id="+o.UserId, http.StatusBadRequest)
}
if len(o.Category) == 0 || len(o.Category) > 32 {
return NewLocAppError("Preference.IsValid", "model.preference.is_valid.category.app_error", nil, "category="+o.Category)
return NewAppError("Preference.IsValid", "model.preference.is_valid.category.app_error", nil, "category="+o.Category, http.StatusBadRequest)
}
if len(o.Name) > 32 {
return NewLocAppError("Preference.IsValid", "model.preference.is_valid.name.app_error", nil, "name="+o.Name)
return NewAppError("Preference.IsValid", "model.preference.is_valid.name.app_error", nil, "name="+o.Name, http.StatusBadRequest)
}
if utf8.RuneCountInString(o.Value) > 2000 {
return NewLocAppError("Preference.IsValid", "model.preference.is_valid.value.app_error", nil, "value="+o.Value)
return NewAppError("Preference.IsValid", "model.preference.is_valid.value.app_error", nil, "value="+o.Value, http.StatusBadRequest)
}
if o.Category == PREFERENCE_CATEGORY_THEME {
var unused map[string]string
if err := json.NewDecoder(strings.NewReader(o.Value)).Decode(&unused); err != nil {
return NewLocAppError("Preference.IsValid", "model.preference.is_valid.theme.app_error", nil, "value="+o.Value)
return NewAppError("Preference.IsValid", "model.preference.is_valid.theme.app_error", nil, "value="+o.Value, http.StatusBadRequest)
}
}

View File

@ -18,7 +18,9 @@ const (
PUSH_TYPE_MESSAGE = "message"
PUSH_TYPE_CLEAR = "clear"
CATEGORY_DM = "DIRECT_MESSAGE"
// The category is set to handle a set of interactive Actions
// with the push notifications
CATEGORY_CAN_REPLY = "CAN_REPLY"
MHPNS = "https://push.mattermost.com"
)
@ -34,6 +36,8 @@ type PushNotification struct {
ContentAvailable int `json:"cont_ava"`
TeamId string `json:"team_id"`
ChannelId string `json:"channel_id"`
PostId string `json:"post_id"`
RootId string `json:"root_id"`
ChannelName string `json:"channel_name"`
Type string `json:"type"`
SenderId string `json:"sender_id"`

View File

@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
"net/http"
"regexp"
)
@ -54,21 +55,21 @@ func ReactionsFromJson(data io.Reader) []*Reaction {
func (o *Reaction) IsValid() *AppError {
if len(o.UserId) != 26 {
return NewLocAppError("Reaction.IsValid", "model.reaction.is_valid.user_id.app_error", nil, "user_id="+o.UserId)
return NewAppError("Reaction.IsValid", "model.reaction.is_valid.user_id.app_error", nil, "user_id="+o.UserId, http.StatusBadRequest)
}
if len(o.PostId) != 26 {
return NewLocAppError("Reaction.IsValid", "model.reaction.is_valid.post_id.app_error", nil, "post_id="+o.PostId)
return NewAppError("Reaction.IsValid", "model.reaction.is_valid.post_id.app_error", nil, "post_id="+o.PostId, http.StatusBadRequest)
}
validName := regexp.MustCompile(`^[a-zA-Z0-9\-\+_]+$`)
if len(o.EmojiName) == 0 || len(o.EmojiName) > 64 || !validName.MatchString(o.EmojiName) {
return NewLocAppError("Reaction.IsValid", "model.reaction.is_valid.emoji_name.app_error", nil, "emoji_name="+o.EmojiName)
return NewAppError("Reaction.IsValid", "model.reaction.is_valid.emoji_name.app_error", nil, "emoji_name="+o.EmojiName, http.StatusBadRequest)
}
if o.CreateAt == 0 {
return NewLocAppError("Reaction.IsValid", "model.reaction.is_valid.create_at.app_error", nil, "")
return NewAppError("Reaction.IsValid", "model.reaction.is_valid.create_at.app_error", nil, "", http.StatusBadRequest)
}
return nil

View File

@ -31,16 +31,6 @@ func (o *SearchParams) ToJson() string {
var searchFlags = [...]string{"from", "channel", "in"}
func splitWordsNoQuotes(text string) []string {
words := []string{}
for _, word := range strings.Fields(text) {
words = append(words, word)
}
return words
}
func splitWords(text string) []string {
words := []string{}
@ -55,14 +45,14 @@ func splitWords(text string) []string {
foundQuote = false
location = i + 1
} else {
words = append(words, splitWordsNoQuotes(text[location:i])...)
words = append(words, strings.Fields(text[location:i])...)
foundQuote = true
location = i
}
}
}
words = append(words, splitWordsNoQuotes(text[location:])...)
words = append(words, strings.Fields(text[location:])...)
return words
}

View File

@ -37,6 +37,11 @@ type Session struct {
TeamMembers []*TeamMember `json:"team_members" db:"-"`
}
func (me *Session) DeepCopy() *Session {
copy := *me
return &copy
}
func (me *Session) ToJson() string {
b, err := json.Marshal(me)
if err != nil {

View File

@ -5,7 +5,6 @@ package model
import (
"fmt"
"strings"
)
type SlackAttachment struct {
@ -25,6 +24,7 @@ type SlackAttachment struct {
Footer string `json:"footer"`
FooterIcon string `json:"footer_icon"`
Timestamp interface{} `json:"ts"` // This is either a string or an int64
Actions []*PostAction `json:"actions,omitempty"`
}
type SlackAttachmentField struct {
@ -33,23 +33,7 @@ type SlackAttachmentField struct {
Short bool `json:"short"`
}
// To mention @channel via a webhook in Slack, the message should contain
// <!channel>, as explained at the bottom of this article:
// https://get.slack.help/hc/en-us/articles/202009646-Making-announcements
func ExpandAnnouncement(text string) string {
c1 := "<!channel>"
c2 := "@channel"
if strings.Contains(text, c1) {
return strings.Replace(text, c1, c2, -1)
}
return text
}
// Expand announcements in incoming webhooks from Slack. Those announcements
// can be found in the text attribute, or in the pretext, text, title and value
// attributes of the attachment structure. The Slack attachment structure is
// documented here: https://api.slack.com/docs/attachments
func ProcessSlackAttachments(a []*SlackAttachment) []*SlackAttachment {
func StringifySlackFieldValue(a []*SlackAttachment) []*SlackAttachment {
var nonNilAttachments []*SlackAttachment
for _, attachment := range a {
if attachment == nil {
@ -57,10 +41,6 @@ func ProcessSlackAttachments(a []*SlackAttachment) []*SlackAttachment {
}
nonNilAttachments = append(nonNilAttachments, attachment)
attachment.Pretext = ExpandAnnouncement(attachment.Pretext)
attachment.Text = ExpandAnnouncement(attachment.Text)
attachment.Title = ExpandAnnouncement(attachment.Title)
var nonNilFields []*SlackAttachmentField
for _, field := range attachment.Fields {
if field == nil {
@ -70,7 +50,7 @@ func ProcessSlackAttachments(a []*SlackAttachment) []*SlackAttachment {
if field.Value != nil {
// Ensure the value is set to a string if it is set
field.Value = ExpandAnnouncement(fmt.Sprintf("%v", field.Value))
field.Value = fmt.Sprintf("%v", field.Value)
}
}
attachment.Fields = nonNilFields

View File

@ -11,6 +11,7 @@ import (
const (
STATUS_OFFLINE = "offline"
STATUS_AWAY = "away"
STATUS_DND = "dnd"
STATUS_ONLINE = "online"
STATUS_CACHE_SIZE = SESSION_CACHE_SIZE
STATUS_CHANNEL_TIMEOUT = 20000 // 20 seconds

View File

@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
"net/http"
"strings"
)
@ -103,11 +104,11 @@ func TeamsUnreadFromJson(data io.Reader) []*TeamUnread {
func (o *TeamMember) IsValid() *AppError {
if len(o.TeamId) != 26 {
return NewLocAppError("TeamMember.IsValid", "model.team_member.is_valid.team_id.app_error", nil, "")
return NewAppError("TeamMember.IsValid", "model.team_member.is_valid.team_id.app_error", nil, "", http.StatusBadRequest)
}
if len(o.UserId) != 26 {
return NewLocAppError("TeamMember.IsValid", "model.team_member.is_valid.user_id.app_error", nil, "")
return NewAppError("TeamMember.IsValid", "model.team_member.is_valid.user_id.app_error", nil, "", http.StatusBadRequest)
}
return nil

View File

@ -88,6 +88,12 @@ type UserPatch struct {
Locale *string `json:"locale"`
}
type UserAuth struct {
Password string `json:"password,omitempty"`
AuthData *string `json:"auth_data,omitempty"`
AuthService string `json:"auth_service,omitempty"`
}
// IsValid validates the user and returns an error if it isn't configured
// correctly.
func (u *User) IsValid() *AppError {
@ -228,16 +234,13 @@ func (u *User) SetDefaultNotifications() {
u.NotifyProps = make(map[string]string)
u.NotifyProps["email"] = "true"
u.NotifyProps["push"] = USER_NOTIFY_MENTION
u.NotifyProps["desktop"] = USER_NOTIFY_ALL
u.NotifyProps["desktop"] = USER_NOTIFY_MENTION
u.NotifyProps["desktop_sound"] = "true"
u.NotifyProps["mention_keys"] = u.Username + ",@" + u.Username
u.NotifyProps["channel"] = "true"
if u.FirstName == "" {
u.NotifyProps["first_name"] = "false"
} else {
u.NotifyProps["first_name"] = "true"
}
u.NotifyProps["push_status"] = STATUS_AWAY
u.NotifyProps["comments"] = "never"
u.NotifyProps["first_name"] = "false"
}
func (user *User) UpdateMentionKeysFromUsername(oldUsername string) {
@ -312,6 +315,15 @@ func (u *UserPatch) ToJson() string {
}
}
func (u *UserAuth) ToJson() string {
b, err := json.Marshal(u)
if err != nil {
return ""
} else {
return string(b)
}
}
// Generate a valid strong etag so the browser can cache the results
func (u *User) Etag(showFullName, showEmail bool) string {
return Etag(u.Id, u.UpdateAt, showFullName, showEmail)
@ -320,8 +332,7 @@ func (u *User) Etag(showFullName, showEmail bool) string {
// Remove any private data from the user object
func (u *User) Sanitize(options map[string]bool) {
u.Password = ""
u.AuthData = new(string)
*u.AuthData = ""
u.AuthData = NewString("")
u.MfaSecret = ""
if len(options) != 0 && !options["email"] {
@ -341,12 +352,10 @@ func (u *User) Sanitize(options map[string]bool) {
func (u *User) ClearNonProfileFields() {
u.Password = ""
u.AuthData = new(string)
*u.AuthData = ""
u.AuthData = NewString("")
u.MfaSecret = ""
u.EmailVerified = false
u.AllowMarketing = false
u.Props = StringMap{}
u.NotifyProps = StringMap{}
u.LastPasswordUpdate = 0
u.FailedAttempts = 0
@ -437,7 +446,7 @@ func IsValidUserRoles(userRoles string) bool {
}
func isValidRole(roleId string) bool {
_, ok := BuiltInRoles[roleId]
_, ok := DefaultRoles[roleId]
return ok
}
@ -500,6 +509,17 @@ func UserPatchFromJson(data io.Reader) *UserPatch {
}
}
func UserAuthFromJson(data io.Reader) *UserAuth {
decoder := json.NewDecoder(data)
var user UserAuth
err := decoder.Decode(&user)
if err == nil {
return &user
} else {
return nil
}
}
func UserMapToJson(u map[string]*User) string {
b, err := json.Marshal(u)
if err != nil {

View File

@ -14,6 +14,7 @@ type UserAccessToken struct {
Token string `json:"token,omitempty"`
UserId string `json:"user_id"`
Description string `json:"description"`
IsActive bool `json:"is_active"`
}
func (t *UserAccessToken) IsValid() *AppError {
@ -38,6 +39,7 @@ func (t *UserAccessToken) IsValid() *AppError {
func (t *UserAccessToken) PreSave() {
t.Id = NewId()
t.IsActive = true
}
func (t *UserAccessToken) ToJson() string {

View File

@ -12,12 +12,14 @@ import (
"io"
"io/ioutil"
"net"
"net/http"
"net/mail"
"net/url"
"regexp"
"strconv"
"strings"
"time"
"unicode"
goi18n "github.com/nicksnyder/go-i18n/i18n"
"github.com/pborman/uuid"
@ -90,7 +92,7 @@ func AppErrorFromJson(data io.Reader) *AppError {
if err == nil {
return &er
} else {
return NewLocAppError("AppErrorFromJson", "model.utils.decode_json.app_error", nil, "body: "+str)
return NewAppError("AppErrorFromJson", "model.utils.decode_json.app_error", nil, "body: "+str, http.StatusInternalServerError)
}
}
@ -106,18 +108,6 @@ func NewAppError(where string, id string, params map[string]interface{}, details
return ap
}
func NewLocAppError(where string, id string, params map[string]interface{}, details string) *AppError {
ap := &AppError{}
ap.Id = id
ap.params = params
ap.Message = id
ap.Where = where
ap.DetailedError = details
ap.StatusCode = 500
ap.IsOAuth = false
return ap
}
var encoding = base32.NewEncoding("ybndrfg8ejkmcpqxot1uwisza345h769")
// NewId is a globally unique identifier. It is a [A-Z0-9] string 26
@ -283,11 +273,7 @@ func GetServerIpAddress() string {
}
func IsLower(s string) bool {
if strings.ToLower(s) == s {
return true
}
return false
return strings.ToLower(s) == s
}
func IsValidEmail(email string) bool {
@ -492,3 +478,17 @@ func IsValidNumberString(value string) bool {
return true
}
func IsValidId(value string) bool {
if len(value) != 26 {
return false
}
for _, r := range value {
if !unicode.IsLetter(r) && !unicode.IsNumber(r) {
return false
}
}
return true
}

View File

@ -13,6 +13,11 @@ import (
// It should be maitained in chronological order with most current
// release at the front of the list.
var versions = []string{
"4.6.0",
"4.5.0",
"4.4.0",
"4.3.0",
"4.2.0",
"4.1.0",
"4.0.0",
"3.10.0",

View File

@ -5,6 +5,8 @@ package model
import (
"encoding/json"
"net/http"
"github.com/gorilla/websocket"
)
@ -29,7 +31,7 @@ type WebSocketClient struct {
func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX_V3+"/users/websocket", nil)
if err != nil {
return nil, NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
return nil, NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
}
client := &WebSocketClient{
@ -54,7 +56,7 @@ func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
func NewWebSocketClient4(url, authToken string) (*WebSocketClient, *AppError) {
conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX+"/websocket", nil)
if err != nil {
return nil, NewLocAppError("NewWebSocketClient4", "model.websocket_client.connect_fail.app_error", nil, err.Error())
return nil, NewAppError("NewWebSocketClient4", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
}
client := &WebSocketClient{
@ -78,7 +80,7 @@ func (wsc *WebSocketClient) Connect() *AppError {
var err error
wsc.Conn, _, err = websocket.DefaultDialer.Dial(wsc.ConnectUrl, nil)
if err != nil {
return NewLocAppError("Connect", "model.websocket_client.connect_fail.app_error", nil, err.Error())
return NewAppError("Connect", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
}
wsc.EventChannel = make(chan *WebSocketEvent, 100)
@ -106,7 +108,7 @@ func (wsc *WebSocketClient) Listen() {
var err error
if _, rawMsg, err = wsc.Conn.ReadMessage(); err != nil {
if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
wsc.ListenError = NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
wsc.ListenError = NewAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return

View File

@ -24,6 +24,7 @@ const (
WEBSOCKET_EVENT_UPDATE_TEAM = "update_team"
WEBSOCKET_EVENT_USER_ADDED = "user_added"
WEBSOCKET_EVENT_USER_UPDATED = "user_updated"
WEBSOCKET_EVENT_USER_ROLE_UPDATED = "user_role_updated"
WEBSOCKET_EVENT_MEMBERROLE_UPDATED = "memberrole_updated"
WEBSOCKET_EVENT_USER_REMOVED = "user_removed"
WEBSOCKET_EVENT_PREFERENCE_CHANGED = "preference_changed"
@ -39,6 +40,8 @@ const (
WEBSOCKET_EVENT_RESPONSE = "response"
WEBSOCKET_EVENT_EMOJI_ADDED = "emoji_added"
WEBSOCKET_EVENT_CHANNEL_VIEWED = "channel_viewed"
WEBSOCKET_EVENT_PLUGIN_ACTIVATED = "plugin_activated" // EXPERIMENTAL - SUBJECT TO CHANGE
WEBSOCKET_EVENT_PLUGIN_DEACTIVATED = "plugin_deactivated" // EXPERIMENTAL - SUBJECT TO CHANGE
)
type WebSocketMessage interface {