summaryrefslogtreecommitdiffstats
path: root/vendor/github.com
diff options
context:
space:
mode:
authorWim <wim@42.be>2016-08-15 18:47:31 +0200
committerWim <wim@42.be>2016-08-15 18:47:31 +0200
commit24defcb970838133eb82f4fbbc516630fb81cae6 (patch)
treede88bd0761b08ee35d8f2ddbcb133f7899b4264d /vendor/github.com
parenta1a11a88b334a4deb78915336def0113eec9738b (diff)
downloadmatterbridge-msglm-24defcb970838133eb82f4fbbc516630fb81cae6.tar.gz
matterbridge-msglm-24defcb970838133eb82f4fbbc516630fb81cae6.tar.bz2
matterbridge-msglm-24defcb970838133eb82f4fbbc516630fb81cae6.zip
Sync with mattermost 3.3.0
Diffstat (limited to 'vendor/github.com')
-rw-r--r--vendor/github.com/mattermost/platform/einterfaces/account_migration.go20
-rw-r--r--vendor/github.com/mattermost/platform/einterfaces/cluster.go32
-rw-r--r--vendor/github.com/mattermost/platform/einterfaces/ldap.go2
-rw-r--r--vendor/github.com/mattermost/platform/model/access.go25
-rw-r--r--vendor/github.com/mattermost/platform/model/authorize.go5
-rw-r--r--vendor/github.com/mattermost/platform/model/channel.go3
-rw-r--r--vendor/github.com/mattermost/platform/model/client.go174
-rw-r--r--vendor/github.com/mattermost/platform/model/cluster_info.go66
-rw-r--r--vendor/github.com/mattermost/platform/model/config.go130
-rw-r--r--vendor/github.com/mattermost/platform/model/job.go6
-rw-r--r--vendor/github.com/mattermost/platform/model/license.go20
-rw-r--r--vendor/github.com/mattermost/platform/model/message.go61
-rw-r--r--vendor/github.com/mattermost/platform/model/oauth.go40
-rw-r--r--vendor/github.com/mattermost/platform/model/outgoing_webhook.go20
-rw-r--r--vendor/github.com/mattermost/platform/model/post.go3
-rw-r--r--vendor/github.com/mattermost/platform/model/preference.go48
-rw-r--r--vendor/github.com/mattermost/platform/model/session.go6
-rw-r--r--vendor/github.com/mattermost/platform/model/status.go42
-rw-r--r--vendor/github.com/mattermost/platform/model/team.go3
-rw-r--r--vendor/github.com/mattermost/platform/model/user.go49
-rw-r--r--vendor/github.com/mattermost/platform/model/utils.go12
-rw-r--r--vendor/github.com/mattermost/platform/model/version.go1
-rw-r--r--vendor/github.com/mattermost/platform/model/websocket_client.go109
-rw-r--r--vendor/github.com/mattermost/platform/model/websocket_message.go114
-rw-r--r--vendor/github.com/mattermost/platform/model/websocket_request.go43
25 files changed, 874 insertions, 160 deletions
diff --git a/vendor/github.com/mattermost/platform/einterfaces/account_migration.go b/vendor/github.com/mattermost/platform/einterfaces/account_migration.go
new file mode 100644
index 00000000..4824de6d
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/einterfaces/account_migration.go
@@ -0,0 +1,20 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package einterfaces
+
+import "github.com/mattermost/platform/model"
+
+type AccountMigrationInterface interface {
+ MigrateToLdap(fromAuthService string, forignUserFieldNameToMatch string) *model.AppError
+}
+
+var theAccountMigrationInterface AccountMigrationInterface
+
+func RegisterAccountMigrationInterface(newInterface AccountMigrationInterface) {
+ theAccountMigrationInterface = newInterface
+}
+
+func GetAccountMigrationInterface() AccountMigrationInterface {
+ return theAccountMigrationInterface
+}
diff --git a/vendor/github.com/mattermost/platform/einterfaces/cluster.go b/vendor/github.com/mattermost/platform/einterfaces/cluster.go
new file mode 100644
index 00000000..921576ad
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/einterfaces/cluster.go
@@ -0,0 +1,32 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package einterfaces
+
+import (
+ "github.com/mattermost/platform/model"
+)
+
+type ClusterInterface interface {
+ StartInterNodeCommunication()
+ StopInterNodeCommunication()
+ GetClusterInfos() []*model.ClusterInfo
+ RemoveAllSessionsForUserId(userId string)
+ InvalidateCacheForUser(userId string)
+ InvalidateCacheForChannel(channelId string)
+ Publish(event *model.WebSocketEvent)
+ UpdateStatus(status *model.Status)
+ GetLogs() ([]string, *model.AppError)
+ GetClusterId() string
+ ConfigChanged(previousConfig *model.Config, newConfig *model.Config, sendToOtherServer bool) *model.AppError
+}
+
+var theClusterInterface ClusterInterface
+
+func RegisterClusterInterface(newInterface ClusterInterface) {
+ theClusterInterface = newInterface
+}
+
+func GetClusterInterface() ClusterInterface {
+ return theClusterInterface
+}
diff --git a/vendor/github.com/mattermost/platform/einterfaces/ldap.go b/vendor/github.com/mattermost/platform/einterfaces/ldap.go
index 4f1b5611..fb14a8f0 100644
--- a/vendor/github.com/mattermost/platform/einterfaces/ldap.go
+++ b/vendor/github.com/mattermost/platform/einterfaces/ldap.go
@@ -15,6 +15,8 @@ type LdapInterface interface {
ValidateFilter(filter string) *model.AppError
Syncronize() *model.AppError
StartLdapSyncJob()
+ SyncNow()
+ GetAllLdapUsers() ([]*model.User, *model.AppError)
}
var theLdapInterface LdapInterface
diff --git a/vendor/github.com/mattermost/platform/model/access.go b/vendor/github.com/mattermost/platform/model/access.go
index 877b3c4f..85417fce 100644
--- a/vendor/github.com/mattermost/platform/model/access.go
+++ b/vendor/github.com/mattermost/platform/model/access.go
@@ -15,10 +15,12 @@ const (
)
type AccessData struct {
- AuthCode string `json:"auth_code"`
+ ClientId string `json:"client_id"`
+ UserId string `json:"user_id"`
Token string `json:"token"`
RefreshToken string `json:"refresh_token"`
RedirectUri string `json:"redirect_uri"`
+ ExpiresAt int64 `json:"expires_at"`
}
type AccessResponse struct {
@@ -33,8 +35,12 @@ type AccessResponse struct {
// correctly.
func (ad *AccessData) IsValid() *AppError {
- if len(ad.AuthCode) == 0 || len(ad.AuthCode) > 128 {
- return NewLocAppError("AccessData.IsValid", "model.access.is_valid.auth_code.app_error", nil, "")
+ if len(ad.ClientId) == 0 || len(ad.ClientId) > 26 {
+ return NewLocAppError("AccessData.IsValid", "model.access.is_valid.client_id.app_error", nil, "")
+ }
+
+ if len(ad.UserId) == 0 || len(ad.UserId) > 26 {
+ return NewLocAppError("AccessData.IsValid", "model.access.is_valid.user_id.app_error", nil, "")
}
if len(ad.Token) != 26 {
@@ -52,6 +58,19 @@ func (ad *AccessData) IsValid() *AppError {
return nil
}
+func (me *AccessData) IsExpired() bool {
+
+ if me.ExpiresAt <= 0 {
+ return false
+ }
+
+ if GetMillis() > me.ExpiresAt {
+ return true
+ }
+
+ return false
+}
+
func (ad *AccessData) ToJson() string {
b, err := json.Marshal(ad)
if err != nil {
diff --git a/vendor/github.com/mattermost/platform/model/authorize.go b/vendor/github.com/mattermost/platform/model/authorize.go
index e0d665ba..2b4017e9 100644
--- a/vendor/github.com/mattermost/platform/model/authorize.go
+++ b/vendor/github.com/mattermost/platform/model/authorize.go
@@ -11,6 +11,7 @@ import (
const (
AUTHCODE_EXPIRE_TIME = 60 * 10 // 10 minutes
AUTHCODE_RESPONSE_TYPE = "code"
+ DEFAULT_SCOPE = "user"
)
type AuthData struct {
@@ -71,6 +72,10 @@ func (ad *AuthData) PreSave() {
if ad.CreateAt == 0 {
ad.CreateAt = GetMillis()
}
+
+ if len(ad.Scope) == 0 {
+ ad.Scope = DEFAULT_SCOPE
+ }
}
func (ad *AuthData) ToJson() string {
diff --git a/vendor/github.com/mattermost/platform/model/channel.go b/vendor/github.com/mattermost/platform/model/channel.go
index e7002e3c..3da9f4fe 100644
--- a/vendor/github.com/mattermost/platform/model/channel.go
+++ b/vendor/github.com/mattermost/platform/model/channel.go
@@ -124,9 +124,6 @@ func (o *Channel) ExtraUpdated() {
o.ExtraUpdateAt = GetMillis()
}
-func (o *Channel) PreExport() {
-}
-
func GetDMNameFromIds(userId1, userId2 string) string {
if userId1 > userId2 {
return userId2 + "__" + userId1
diff --git a/vendor/github.com/mattermost/platform/model/client.go b/vendor/github.com/mattermost/platform/model/client.go
index 2f1e846c..2d154e49 100644
--- a/vendor/github.com/mattermost/platform/model/client.go
+++ b/vendor/github.com/mattermost/platform/model/client.go
@@ -20,6 +20,7 @@ import (
const (
HEADER_REQUEST_ID = "X-Request-ID"
HEADER_VERSION_ID = "X-Version-ID"
+ HEADER_CLUSTER_ID = "X-Cluster-ID"
HEADER_ETAG_SERVER = "ETag"
HEADER_ETAG_CLIENT = "If-None-Match"
HEADER_FORWARDED = "X-Forwarded-For"
@@ -32,6 +33,7 @@ const (
HEADER_REQUESTED_WITH_XML = "XMLHttpRequest"
STATUS = "status"
STATUS_OK = "OK"
+ STATUS_FAIL = "FAIL"
API_URL_SUFFIX_V1 = "/api/v1"
API_URL_SUFFIX_V3 = "/api/v3"
@@ -276,6 +278,9 @@ func (c *Client) GetPing() (map[string]string, *AppError) {
// Team Routes Section
+// SignupTeam sends an email with a team sign-up link to the provided address if email
+// verification is enabled, otherwise it returns a map with a "follow_link" entry
+// containing the team sign-up link.
func (c *Client) SignupTeam(email string, displayName string) (*Result, *AppError) {
m := make(map[string]string)
m["email"] = email
@@ -289,6 +294,8 @@ func (c *Client) SignupTeam(email string, displayName string) (*Result, *AppErro
}
}
+// CreateTeamFromSignup creates a team based on the provided TeamSignup struct. On success
+// it returns the TeamSignup struct.
func (c *Client) CreateTeamFromSignup(teamSignup *TeamSignup) (*Result, *AppError) {
if r, err := c.DoApiPost("/teams/create_from_signup", teamSignup.ToJson()); err != nil {
return nil, err
@@ -299,6 +306,8 @@ func (c *Client) CreateTeamFromSignup(teamSignup *TeamSignup) (*Result, *AppErro
}
}
+// CreateTeam creates a team based on the provided Team struct. On success it returns
+// the Team struct with the Id, CreateAt and other server-decided fields populated.
func (c *Client) CreateTeam(team *Team) (*Result, *AppError) {
if r, err := c.DoApiPost("/teams/create", team.ToJson()); err != nil {
return nil, err
@@ -309,6 +318,7 @@ func (c *Client) CreateTeam(team *Team) (*Result, *AppError) {
}
}
+// GetAllTeams returns a map of all teams using team ids as the key.
func (c *Client) GetAllTeams() (*Result, *AppError) {
if r, err := c.DoApiGet("/teams/all", "", ""); err != nil {
return nil, err
@@ -319,6 +329,8 @@ func (c *Client) GetAllTeams() (*Result, *AppError) {
}
}
+// GetAllTeamListings returns a map of all teams that are available to join
+// using team ids as the key. Must be authenticated.
func (c *Client) GetAllTeamListings() (*Result, *AppError) {
if r, err := c.DoApiGet("/teams/all_team_listings", "", ""); err != nil {
return nil, err
@@ -329,6 +341,8 @@ func (c *Client) GetAllTeamListings() (*Result, *AppError) {
}
}
+// FindTeamByName returns the strings "true" or "false" depending on if a team
+// with the provided name was found.
func (c *Client) FindTeamByName(name string) (*Result, *AppError) {
m := make(map[string]string)
m["name"] = name
@@ -365,6 +379,8 @@ func (c *Client) AddUserToTeam(teamId string, userId string) (*Result, *AppError
}
}
+// AddUserToTeamFromInvite adds a user to a team based off data provided in an invite link.
+// Either hash and dataToHash are required or inviteId is required.
func (c *Client) AddUserToTeamFromInvite(hash, dataToHash, inviteId string) (*Result, *AppError) {
data := make(map[string]string)
data["hash"] = hash
@@ -409,6 +425,9 @@ func (c *Client) InviteMembers(invites *Invites) (*Result, *AppError) {
}
}
+// UpdateTeam updates a team based on the changes in the provided team struct. On success
+// it returns a sanitized version of the updated team. Must be authenticated as a team admin
+// for that team or a system admin.
func (c *Client) UpdateTeam(team *Team) (*Result, *AppError) {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/update", team.ToJson()); err != nil {
return nil, err
@@ -419,6 +438,9 @@ func (c *Client) UpdateTeam(team *Team) (*Result, *AppError) {
}
}
+// User Routes Section
+
+// CreateUser creates a user in the system based on the provided user struct.
func (c *Client) CreateUser(user *User, hash string) (*Result, *AppError) {
if r, err := c.DoApiPost("/users/create", user.ToJson()); err != nil {
return nil, err
@@ -429,6 +451,8 @@ func (c *Client) CreateUser(user *User, hash string) (*Result, *AppError) {
}
}
+// CreateUserWithInvite creates a user based on the provided user struct. Either the hash and
+// data strings or the inviteId is required from the invite.
func (c *Client) CreateUserWithInvite(user *User, hash string, data string, inviteId string) (*Result, *AppError) {
url := "/users/create?d=" + url.QueryEscape(data) + "&h=" + url.QueryEscape(hash) + "&iid=" + url.QueryEscape(inviteId)
@@ -452,6 +476,7 @@ func (c *Client) CreateUserFromSignup(user *User, data string, hash string) (*Re
}
}
+// GetUser returns a user based on a provided user id string. Must be authenticated.
func (c *Client) GetUser(id string, etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/users/"+id+"/get", "", etag); err != nil {
return nil, err
@@ -462,6 +487,7 @@ func (c *Client) GetUser(id string, etag string) (*Result, *AppError) {
}
}
+// GetMe returns the current user.
func (c *Client) GetMe(etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/users/me", "", etag); err != nil {
return nil, err
@@ -472,6 +498,8 @@ func (c *Client) GetMe(etag string) (*Result, *AppError) {
}
}
+// GetProfilesForDirectMessageList returns a map of users for a team that can be direct
+// messaged, using user id as the key. Must be authenticated.
func (c *Client) GetProfilesForDirectMessageList(teamId string) (*Result, *AppError) {
if r, err := c.DoApiGet("/users/profiles_for_dm_list/"+teamId, "", ""); err != nil {
return nil, err
@@ -482,6 +510,8 @@ func (c *Client) GetProfilesForDirectMessageList(teamId string) (*Result, *AppEr
}
}
+// GetProfiles returns a map of users for a team using user id as the key. Must
+// be authenticated.
func (c *Client) GetProfiles(teamId string, etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/users/profiles/"+teamId, "", etag); err != nil {
return nil, err
@@ -492,6 +522,8 @@ func (c *Client) GetProfiles(teamId string, etag string) (*Result, *AppError) {
}
}
+// GetDirectProfiles gets a map of users that are currently shown in the sidebar,
+// using user id as the key. Must be authenticated.
func (c *Client) GetDirectProfiles(etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/users/direct_profiles", "", etag); err != nil {
return nil, err
@@ -502,6 +534,7 @@ func (c *Client) GetDirectProfiles(etag string) (*Result, *AppError) {
}
}
+// LoginById authenticates a user by user id and password.
func (c *Client) LoginById(id string, password string) (*Result, *AppError) {
m := make(map[string]string)
m["id"] = id
@@ -509,6 +542,8 @@ func (c *Client) LoginById(id string, password string) (*Result, *AppError) {
return c.login(m)
}
+// Login authenticates a user by login id, which can be username, email or some sort
+// of SSO identifier based on configuration, and a password.
func (c *Client) Login(loginId string, password string) (*Result, *AppError) {
m := make(map[string]string)
m["login_id"] = loginId
@@ -516,6 +551,7 @@ func (c *Client) Login(loginId string, password string) (*Result, *AppError) {
return c.login(m)
}
+// LoginByLdap authenticates a user by LDAP id and password.
func (c *Client) LoginByLdap(loginId string, password string) (*Result, *AppError) {
m := make(map[string]string)
m["login_id"] = loginId
@@ -524,6 +560,9 @@ func (c *Client) LoginByLdap(loginId string, password string) (*Result, *AppErro
return c.login(m)
}
+// LoginWithDevice authenticates a user by login id (username, email or some sort
+// of SSO identifier based on configuration), password and attaches a device id to
+// the session.
func (c *Client) LoginWithDevice(loginId string, password string, deviceId string) (*Result, *AppError) {
m := make(map[string]string)
m["login_id"] = loginId
@@ -550,6 +589,7 @@ func (c *Client) login(m map[string]string) (*Result, *AppError) {
}
}
+// Logout terminates the current user's session.
func (c *Client) Logout() (*Result, *AppError) {
if r, err := c.DoApiPost("/users/logout", ""); err != nil {
return nil, err
@@ -564,6 +604,9 @@ func (c *Client) Logout() (*Result, *AppError) {
}
}
+// CheckMfa returns a map with key "mfa_required" with the string value "true" or "false",
+// indicating whether MFA is required to log the user in, based on a provided login id
+// (username, email or some sort of SSO identifier based on configuration).
func (c *Client) CheckMfa(loginId string) (*Result, *AppError) {
m := make(map[string]string)
m["login_id"] = loginId
@@ -577,6 +620,8 @@ func (c *Client) CheckMfa(loginId string) (*Result, *AppError) {
}
}
+// GenerateMfaQrCode returns a QR code imagem containing the secret, to be scanned
+// by a multi-factor authentication mobile application. Must be authenticated.
func (c *Client) GenerateMfaQrCode() (*Result, *AppError) {
if r, err := c.DoApiGet("/users/generate_mfa_qr", "", ""); err != nil {
return nil, err
@@ -587,6 +632,9 @@ func (c *Client) GenerateMfaQrCode() (*Result, *AppError) {
}
}
+// UpdateMfa activates multi-factor authenticates for the current user if activate
+// is true and a valid token is provided. If activate is false, then token is not
+// required and multi-factor authentication is disabled for the current user.
func (c *Client) UpdateMfa(activate bool, token string) (*Result, *AppError) {
m := make(map[string]interface{})
m["activate"] = activate
@@ -761,6 +809,15 @@ func (c *Client) GetLogs() (*Result, *AppError) {
}
}
+func (c *Client) GetClusterStatus() ([]*ClusterInfo, *AppError) {
+ if r, err := c.DoApiGet("/admin/cluster_status", "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return ClusterInfosFromJson(r.Body), nil
+ }
+}
+
func (c *Client) GetAllAudits() (*Result, *AppError) {
if r, err := c.DoApiGet("/admin/audits", "", ""); err != nil {
return nil, err
@@ -1181,6 +1238,18 @@ func (c *Client) SearchPosts(terms string, isOrSearch bool) (*Result, *AppError)
}
}
+// GetFlaggedPosts will return a post list of posts that have been flagged by the user.
+// The page is set by the integer parameters offset and limit.
+func (c *Client) GetFlaggedPosts(offset int, limit int) (*Result, *AppError) {
+ if r, err := c.DoApiGet(c.GetTeamRoute()+fmt.Sprintf("/posts/flagged/%v/%v", offset, limit), "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
+ }
+}
+
func (c *Client) UploadProfileFile(data []byte, contentType string) (*Result, *AppError) {
return c.uploadFile(c.ApiUrl+"/users/newimage", data, contentType)
}
@@ -1368,8 +1437,9 @@ func (c *Client) AdminResetPassword(userId, newPassword string) (*Result, *AppEr
}
}
-func (c *Client) GetStatuses(data []string) (*Result, *AppError) {
- if r, err := c.DoApiPost("/users/status", ArrayToJson(data)); err != nil {
+// GetStatuses returns a map of string statuses using user id as the key
+func (c *Client) GetStatuses() (*Result, *AppError) {
+ if r, err := c.DoApiGet("/users/status", "", ""); err != nil {
return nil, err
} else {
defer closeBody(r)
@@ -1398,6 +1468,8 @@ func (c *Client) GetTeamMembers(teamId string) (*Result, *AppError) {
}
}
+// RegisterApp creates a new OAuth2 app to be used with the OAuth2 Provider. On success
+// it returns the created app. Must be authenticated as a user.
func (c *Client) RegisterApp(app *OAuthApp) (*Result, *AppError) {
if r, err := c.DoApiPost("/oauth/register", app.ToJson()); err != nil {
return nil, err
@@ -1408,6 +1480,9 @@ func (c *Client) RegisterApp(app *OAuthApp) (*Result, *AppError) {
}
}
+// AllowOAuth allows a new session by an OAuth2 App. On success
+// it returns the url to be redirected back to the app which initiated the oauth2 flow.
+// Must be authenticated as a user.
func (c *Client) AllowOAuth(rspType, clientId, redirect, scope, state string) (*Result, *AppError) {
if r, err := c.DoApiGet("/oauth/allow?response_type="+rspType+"&client_id="+clientId+"&redirect_uri="+url.QueryEscape(redirect)+"&scope="+scope+"&state="+url.QueryEscape(state), "", ""); err != nil {
return nil, err
@@ -1418,8 +1493,47 @@ func (c *Client) AllowOAuth(rspType, clientId, redirect, scope, state string) (*
}
}
+// GetOAuthAppsByUser returns the OAuth2 Apps registered by the user. On success
+// it returns a list of OAuth2 Apps from the same user or all the registered apps if the user
+// is a System Administrator. Must be authenticated as a user.
+func (c *Client) GetOAuthAppsByUser() (*Result, *AppError) {
+ if r, err := c.DoApiGet("/oauth/list", "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), OAuthAppListFromJson(r.Body)}, nil
+ }
+}
+
+// GetOAuthAppInfo lookup an OAuth2 App using the client_id. On success
+// it returns a Sanitized OAuth2 App. Must be authenticated as a user.
+func (c *Client) GetOAuthAppInfo(clientId string) (*Result, *AppError) {
+ if r, err := c.DoApiGet("/oauth/app/"+clientId, "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), OAuthAppFromJson(r.Body)}, nil
+ }
+}
+
+// DeleteOAuthApp deletes an OAuth2 app, the app must be deleted by the same user who created it or
+// a System Administrator. On success returs Status OK. Must be authenticated as a user.
+func (c *Client) DeleteOAuthApp(id string) (*Result, *AppError) {
+ data := make(map[string]string)
+ data["id"] = id
+ if r, err := c.DoApiPost("/oauth/delete", MapToJson(data)); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return &Result{r.Header.Get(HEADER_REQUEST_ID),
+ r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
+ }
+}
+
func (c *Client) GetAccessToken(data url.Values) (*Result, *AppError) {
- if r, err := c.DoApiPost("/oauth/access_token", data.Encode()); err != nil {
+ if r, err := c.DoPost("/oauth/access_token", data.Encode(), "application/x-www-form-urlencoded"); err != nil {
return nil, err
} else {
defer closeBody(r)
@@ -1509,6 +1623,16 @@ func (c *Client) GetPreferenceCategory(category string) (*Result, *AppError) {
}
}
+// DeletePreferences deletes a list of preferences owned by the current user. If successful,
+// it will return status=ok. Otherwise, an error will be returned.
+func (c *Client) DeletePreferences(preferences *Preferences) (bool, *AppError) {
+ if r, err := c.DoApiPost("/preferences/delete", preferences.ToJson()); err != nil {
+ return false, err
+ } else {
+ return c.CheckStatusOK(r), nil
+ }
+}
+
func (c *Client) CreateOutgoingWebhook(hook *OutgoingWebhook) (*Result, *AppError) {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/create", hook.ToJson()); err != nil {
return nil, err
@@ -1648,3 +1772,47 @@ func (c *Client) DeleteEmoji(id string) (bool, *AppError) {
func (c *Client) GetCustomEmojiImageUrl(id string) string {
return c.GetEmojiRoute() + "/" + id
}
+
+// Uploads a x509 base64 Certificate or Private Key file to be used with SAML.
+// data byte array is required and needs to be a Multi-Part with 'certificate' as the field name
+// contentType is also required. Returns nil if succesful, otherwise returns an AppError
+func (c *Client) UploadCertificateFile(data []byte, contentType string) *AppError {
+ url := c.ApiUrl + "/admin/add_certificate"
+ rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
+ rq.Header.Set("Content-Type", contentType)
+
+ if len(c.AuthToken) > 0 {
+ rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
+ }
+
+ if rp, err := c.HttpClient.Do(rq); err != nil {
+ return NewLocAppError(url, "model.client.connecting.app_error", nil, err.Error())
+ } else if rp.StatusCode >= 300 {
+ return AppErrorFromJson(rp.Body)
+ } else {
+ defer closeBody(rp)
+ return nil
+ }
+}
+
+// Removes a x509 base64 Certificate or Private Key file used with SAML.
+// filename is required. Returns nil if successful, otherwise returns an AppError
+func (c *Client) RemoveCertificateFile(filename string) *AppError {
+ if r, err := c.DoApiPost("/admin/remove_certificate", MapToJson(map[string]string{"filename": filename})); err != nil {
+ return err
+ } else {
+ defer closeBody(r)
+ return nil
+ }
+}
+
+// Checks if the x509 base64 Certificates and Private Key files used with SAML exists on the file system.
+// Returns a map[string]interface{} if successful, otherwise returns an AppError. Must be System Admin authenticated.
+func (c *Client) SamlCertificateStatus(filename string) (map[string]interface{}, *AppError) {
+ if r, err := c.DoApiGet("/admin/remove_certificate", "", ""); err != nil {
+ return nil, err
+ } else {
+ defer closeBody(r)
+ return StringInterfaceFromJson(r.Body), nil
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/cluster_info.go b/vendor/github.com/mattermost/platform/model/cluster_info.go
new file mode 100644
index 00000000..7c3384ae
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/cluster_info.go
@@ -0,0 +1,66 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+)
+
+type ClusterInfo struct {
+ Id string `json:"id"`
+ Version string `json:"version"`
+ ConfigHash string `json:"config_hash"`
+ InterNodeUrl string `json:"internode_url"`
+ Hostname string `json:"hostname"`
+ LastSuccessfulPing int64 `json:"last_ping"`
+ IsAlive bool `json:"is_alive"`
+}
+
+func (me *ClusterInfo) ToJson() string {
+ b, err := json.Marshal(me)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func ClusterInfoFromJson(data io.Reader) *ClusterInfo {
+ decoder := json.NewDecoder(data)
+ var me ClusterInfo
+ err := decoder.Decode(&me)
+ if err == nil {
+ return &me
+ } else {
+ return nil
+ }
+}
+
+func (me *ClusterInfo) HaveEstablishedInitialContact() bool {
+ if me.Id != "" {
+ return true
+ }
+
+ return false
+}
+
+func ClusterInfosToJson(objmap []*ClusterInfo) string {
+ if b, err := json.Marshal(objmap); err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func ClusterInfosFromJson(data io.Reader) []*ClusterInfo {
+ decoder := json.NewDecoder(data)
+
+ var objmap []*ClusterInfo
+ if err := decoder.Decode(&objmap); err != nil {
+ return make([]*ClusterInfo, 0)
+ } else {
+ return objmap
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/config.go b/vendor/github.com/mattermost/platform/model/config.go
index 3a0d7f97..d13ba19e 100644
--- a/vendor/github.com/mattermost/platform/model/config.go
+++ b/vendor/github.com/mattermost/platform/model/config.go
@@ -6,6 +6,7 @@ package model
import (
"encoding/json"
"io"
+ "net/url"
)
const (
@@ -22,8 +23,9 @@ const (
PASSWORD_MAXIMUM_LENGTH = 64
PASSWORD_MINIMUM_LENGTH = 5
- SERVICE_GITLAB = "gitlab"
- SERVICE_GOOGLE = "google"
+ SERVICE_GITLAB = "gitlab"
+ SERVICE_GOOGLE = "google"
+ SERVICE_OFFICE365 = "office365"
WEBSERVER_MODE_REGULAR = "regular"
WEBSERVER_MODE_GZIP = "gzip"
@@ -44,9 +46,12 @@ const (
RESTRICT_EMOJI_CREATION_ALL = "all"
RESTRICT_EMOJI_CREATION_ADMIN = "admin"
RESTRICT_EMOJI_CREATION_SYSTEM_ADMIN = "system_admin"
+
+ SITENAME_MAX_LENGTH = 30
)
type ServiceSettings struct {
+ SiteURL *string
ListenAddress string
MaximumLoginAttempts int
SegmentDeveloperKey string
@@ -75,6 +80,12 @@ type ServiceSettings struct {
RestrictCustomEmojiCreation *string
}
+type ClusterSettings struct {
+ Enable *bool
+ InterNodeListenAddress *string
+ InterNodeUrls []string
+}
+
type SSOSettings struct {
Enable bool
Secret string
@@ -189,10 +200,12 @@ type TeamSettings struct {
RestrictTeamNames *bool
EnableCustomBrand *bool
CustomBrandText *string
+ CustomDescriptionText *string
RestrictDirectMessage *string
RestrictTeamInvite *string
RestrictPublicChannelManagement *string
RestrictPrivateChannelManagement *string
+ UserStatusAwayTimeout *int64
}
type LdapSettings struct {
@@ -265,6 +278,12 @@ type SamlSettings struct {
LoginButtonText *string
}
+type NativeAppSettings struct {
+ AppDownloadLink *string
+ AndroidAppDownloadLink *string
+ IosAppDownloadLink *string
+}
+
type Config struct {
ServiceSettings ServiceSettings
TeamSettings TeamSettings
@@ -278,10 +297,13 @@ type Config struct {
SupportSettings SupportSettings
GitLabSettings SSOSettings
GoogleSettings SSOSettings
+ Office365Settings SSOSettings
LdapSettings LdapSettings
ComplianceSettings ComplianceSettings
LocalizationSettings LocalizationSettings
SamlSettings SamlSettings
+ NativeAppSettings NativeAppSettings
+ ClusterSettings ClusterSettings
}
func (o *Config) ToJson() string {
@@ -299,6 +321,8 @@ func (o *Config) GetSSOService(service string) *SSOSettings {
return &o.GitLabSettings
case SERVICE_GOOGLE:
return &o.GoogleSettings
+ case SERVICE_OFFICE365:
+ return &o.Office365Settings
}
return nil
@@ -348,6 +372,11 @@ func (o *Config) SetDefaults() {
o.EmailSettings.PasswordResetSalt = NewRandomString(32)
}
+ if o.ServiceSettings.SiteURL == nil {
+ o.ServiceSettings.SiteURL = new(string)
+ *o.ServiceSettings.SiteURL = ""
+ }
+
if o.ServiceSettings.EnableDeveloper == nil {
o.ServiceSettings.EnableDeveloper = new(bool)
*o.ServiceSettings.EnableDeveloper = false
@@ -408,6 +437,11 @@ func (o *Config) SetDefaults() {
*o.TeamSettings.CustomBrandText = ""
}
+ if o.TeamSettings.CustomDescriptionText == nil {
+ o.TeamSettings.CustomDescriptionText = new(string)
+ *o.TeamSettings.CustomDescriptionText = ""
+ }
+
if o.TeamSettings.EnableOpenServer == nil {
o.TeamSettings.EnableOpenServer = new(bool)
*o.TeamSettings.EnableOpenServer = false
@@ -433,6 +467,11 @@ func (o *Config) SetDefaults() {
*o.TeamSettings.RestrictPrivateChannelManagement = PERMISSIONS_ALL
}
+ if o.TeamSettings.UserStatusAwayTimeout == nil {
+ o.TeamSettings.UserStatusAwayTimeout = new(int64)
+ *o.TeamSettings.UserStatusAwayTimeout = 300
+ }
+
if o.EmailSettings.EnableSignInWithEmail == nil {
o.EmailSettings.EnableSignInWithEmail = new(bool)
@@ -474,7 +513,7 @@ func (o *Config) SetDefaults() {
if o.SupportSettings.TermsOfServiceLink == nil {
o.SupportSettings.TermsOfServiceLink = new(string)
- *o.SupportSettings.TermsOfServiceLink = "/static/help/terms.html"
+ *o.SupportSettings.TermsOfServiceLink = "https://about.mattermost.com/default-terms/"
}
if !IsSafeLink(o.SupportSettings.PrivacyPolicyLink) {
@@ -483,7 +522,7 @@ func (o *Config) SetDefaults() {
if o.SupportSettings.PrivacyPolicyLink == nil {
o.SupportSettings.PrivacyPolicyLink = new(string)
- *o.SupportSettings.PrivacyPolicyLink = "/static/help/privacy.html"
+ *o.SupportSettings.PrivacyPolicyLink = ""
}
if !IsSafeLink(o.SupportSettings.AboutLink) {
@@ -492,7 +531,7 @@ func (o *Config) SetDefaults() {
if o.SupportSettings.AboutLink == nil {
o.SupportSettings.AboutLink = new(string)
- *o.SupportSettings.AboutLink = "/static/help/about.html"
+ *o.SupportSettings.AboutLink = ""
}
if !IsSafeLink(o.SupportSettings.HelpLink) {
@@ -501,7 +540,7 @@ func (o *Config) SetDefaults() {
if o.SupportSettings.HelpLink == nil {
o.SupportSettings.HelpLink = new(string)
- *o.SupportSettings.HelpLink = "/static/help/help.html"
+ *o.SupportSettings.HelpLink = ""
}
if !IsSafeLink(o.SupportSettings.ReportAProblemLink) {
@@ -510,7 +549,7 @@ func (o *Config) SetDefaults() {
if o.SupportSettings.ReportAProblemLink == nil {
o.SupportSettings.ReportAProblemLink = new(string)
- *o.SupportSettings.ReportAProblemLink = "/static/help/report_problem.html"
+ *o.SupportSettings.ReportAProblemLink = ""
}
if o.SupportSettings.SupportEmail == nil {
@@ -675,6 +714,20 @@ func (o *Config) SetDefaults() {
*o.ServiceSettings.RestrictCustomEmojiCreation = RESTRICT_EMOJI_CREATION_ALL
}
+ if o.ClusterSettings.InterNodeListenAddress == nil {
+ o.ClusterSettings.InterNodeListenAddress = new(string)
+ *o.ClusterSettings.InterNodeListenAddress = ":8075"
+ }
+
+ if o.ClusterSettings.Enable == nil {
+ o.ClusterSettings.Enable = new(bool)
+ *o.ClusterSettings.Enable = false
+ }
+
+ if o.ClusterSettings.InterNodeUrls == nil {
+ o.ClusterSettings.InterNodeUrls = []string{}
+ }
+
if o.ComplianceSettings.Enable == nil {
o.ComplianceSettings.Enable = new(bool)
*o.ComplianceSettings.Enable = false
@@ -784,6 +837,21 @@ func (o *Config) SetDefaults() {
o.SamlSettings.LocaleAttribute = new(string)
*o.SamlSettings.LocaleAttribute = ""
}
+
+ if o.NativeAppSettings.AppDownloadLink == nil {
+ o.NativeAppSettings.AppDownloadLink = new(string)
+ *o.NativeAppSettings.AppDownloadLink = "https://about.mattermost.com/downloads/"
+ }
+
+ if o.NativeAppSettings.AndroidAppDownloadLink == nil {
+ o.NativeAppSettings.AndroidAppDownloadLink = new(string)
+ *o.NativeAppSettings.AndroidAppDownloadLink = "https://about.mattermost.com/mattermost-android-app/"
+ }
+
+ if o.NativeAppSettings.IosAppDownloadLink == nil {
+ o.NativeAppSettings.IosAppDownloadLink = new(string)
+ *o.NativeAppSettings.IosAppDownloadLink = "https://about.mattermost.com/mattermost-ios-app/"
+ }
}
func (o *Config) IsValid() *AppError {
@@ -792,6 +860,12 @@ func (o *Config) IsValid() *AppError {
return NewLocAppError("Config.IsValid", "model.config.is_valid.login_attempts.app_error", nil, "")
}
+ if len(*o.ServiceSettings.SiteURL) != 0 {
+ if _, err := url.ParseRequestURI(*o.ServiceSettings.SiteURL); err != nil {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.site_url.app_error", nil, "")
+ }
+ }
+
if len(o.ServiceSettings.ListenAddress) == 0 {
return NewLocAppError("Config.IsValid", "model.config.is_valid.listen_address.app_error", nil, "")
}
@@ -893,21 +967,37 @@ func (o *Config) IsValid() *AppError {
}
if *o.LdapSettings.Enable {
- if *o.LdapSettings.LdapServer == "" ||
- *o.LdapSettings.BaseDN == "" ||
- *o.LdapSettings.BindUsername == "" ||
- *o.LdapSettings.BindPassword == "" ||
- *o.LdapSettings.FirstNameAttribute == "" ||
- *o.LdapSettings.LastNameAttribute == "" ||
- *o.LdapSettings.EmailAttribute == "" ||
- *o.LdapSettings.UsernameAttribute == "" ||
- *o.LdapSettings.IdAttribute == "" {
- return NewLocAppError("Config.IsValid", "Required LDAP field missing", nil, "")
+ if *o.LdapSettings.LdapServer == "" {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_server", nil, "")
+ }
+
+ if *o.LdapSettings.BaseDN == "" {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_basedn", nil, "")
+ }
+
+ if *o.LdapSettings.FirstNameAttribute == "" {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_firstname", nil, "")
+ }
+
+ if *o.LdapSettings.LastNameAttribute == "" {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_lastname", nil, "")
+ }
+
+ if *o.LdapSettings.EmailAttribute == "" {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_email", nil, "")
+ }
+
+ if *o.LdapSettings.UsernameAttribute == "" {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_username", nil, "")
+ }
+
+ if *o.LdapSettings.IdAttribute == "" {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.ldap_id", nil, "")
}
}
if *o.SamlSettings.Enable {
- if len(*o.SamlSettings.IdpUrl) == 0 {
+ if len(*o.SamlSettings.IdpUrl) == 0 || !IsValidHttpUrl(*o.SamlSettings.IdpUrl) {
return NewLocAppError("Config.IsValid", "model.config.is_valid.saml_idp_url.app_error", nil, "")
}
@@ -960,6 +1050,10 @@ func (o *Config) IsValid() *AppError {
return NewLocAppError("Config.IsValid", "model.config.is_valid.password_length.app_error", map[string]interface{}{"MinLength": PASSWORD_MINIMUM_LENGTH, "MaxLength": PASSWORD_MAXIMUM_LENGTH}, "")
}
+ if len(o.TeamSettings.SiteName) > SITENAME_MAX_LENGTH {
+ return NewLocAppError("Config.IsValid", "model.config.is_valid.sitename_length.app_error", map[string]interface{}{"MaxLength": SITENAME_MAX_LENGTH}, "")
+ }
+
return nil
}
diff --git a/vendor/github.com/mattermost/platform/model/job.go b/vendor/github.com/mattermost/platform/model/job.go
index b6c68dce..229d5efd 100644
--- a/vendor/github.com/mattermost/platform/model/job.go
+++ b/vendor/github.com/mattermost/platform/model/job.go
@@ -84,6 +84,12 @@ func (task *ScheduledTask) Cancel() {
removeTaskByName(task.Name)
}
+// Executes the task immediatly. A recurring task will be run regularally after interval.
+func (task *ScheduledTask) Execute() {
+ task.function()
+ task.timer.Reset(task.Interval)
+}
+
func (task *ScheduledTask) String() string {
return fmt.Sprintf(
"%s\nInterval: %s\nRecurring: %t\n",
diff --git a/vendor/github.com/mattermost/platform/model/license.go b/vendor/github.com/mattermost/platform/model/license.go
index a77a7349..98b88fde 100644
--- a/vendor/github.com/mattermost/platform/model/license.go
+++ b/vendor/github.com/mattermost/platform/model/license.go
@@ -35,8 +35,10 @@ type Features struct {
Users *int `json:"users"`
LDAP *bool `json:"ldap"`
MFA *bool `json:"mfa"`
- GoogleSSO *bool `json:"google_sso"`
+ GoogleOAuth *bool `json:"google_oauth"`
+ Office365OAuth *bool `json:"office365_oauth"`
Compliance *bool `json:"compliance"`
+ Cluster *bool `json:"cluster"`
CustomBrand *bool `json:"custom_brand"`
MHPNS *bool `json:"mhpns"`
SAML *bool `json:"saml"`
@@ -65,9 +67,14 @@ func (f *Features) SetDefaults() {
*f.MFA = *f.FutureFeatures
}
- if f.GoogleSSO == nil {
- f.GoogleSSO = new(bool)
- *f.GoogleSSO = *f.FutureFeatures
+ if f.GoogleOAuth == nil {
+ f.GoogleOAuth = new(bool)
+ *f.GoogleOAuth = *f.FutureFeatures
+ }
+
+ if f.Office365OAuth == nil {
+ f.Office365OAuth = new(bool)
+ *f.Office365OAuth = *f.FutureFeatures
}
if f.Compliance == nil {
@@ -75,6 +82,11 @@ func (f *Features) SetDefaults() {
*f.Compliance = *f.FutureFeatures
}
+ if f.Cluster == nil {
+ f.Cluster = new(bool)
+ *f.Cluster = *f.FutureFeatures
+ }
+
if f.CustomBrand == nil {
f.CustomBrand = new(bool)
*f.CustomBrand = *f.FutureFeatures
diff --git a/vendor/github.com/mattermost/platform/model/message.go b/vendor/github.com/mattermost/platform/model/message.go
deleted file mode 100644
index 12f3be66..00000000
--- a/vendor/github.com/mattermost/platform/model/message.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-package model
-
-import (
- "encoding/json"
- "io"
-)
-
-const (
- ACTION_TYPING = "typing"
- ACTION_POSTED = "posted"
- ACTION_POST_EDITED = "post_edited"
- ACTION_POST_DELETED = "post_deleted"
- ACTION_CHANNEL_DELETED = "channel_deleted"
- ACTION_CHANNEL_VIEWED = "channel_viewed"
- ACTION_DIRECT_ADDED = "direct_added"
- ACTION_NEW_USER = "new_user"
- ACTION_LEAVE_TEAM = "leave_team"
- ACTION_USER_ADDED = "user_added"
- ACTION_USER_REMOVED = "user_removed"
- ACTION_PREFERENCE_CHANGED = "preference_changed"
- ACTION_EPHEMERAL_MESSAGE = "ephemeral_message"
-)
-
-type Message struct {
- TeamId string `json:"team_id"`
- ChannelId string `json:"channel_id"`
- UserId string `json:"user_id"`
- Action string `json:"action"`
- Props map[string]string `json:"props"`
-}
-
-func (m *Message) Add(key string, value string) {
- m.Props[key] = value
-}
-
-func NewMessage(teamId string, channelId string, userId string, action string) *Message {
- return &Message{TeamId: teamId, ChannelId: channelId, UserId: userId, Action: action, Props: make(map[string]string)}
-}
-
-func (o *Message) ToJson() string {
- b, err := json.Marshal(o)
- if err != nil {
- return ""
- } else {
- return string(b)
- }
-}
-
-func MessageFromJson(data io.Reader) *Message {
- decoder := json.NewDecoder(data)
- var o Message
- err := decoder.Decode(&o)
- if err == nil {
- return &o
- } else {
- return nil
- }
-}
diff --git a/vendor/github.com/mattermost/platform/model/oauth.go b/vendor/github.com/mattermost/platform/model/oauth.go
index c54df107..cfe643c9 100644
--- a/vendor/github.com/mattermost/platform/model/oauth.go
+++ b/vendor/github.com/mattermost/platform/model/oauth.go
@@ -25,8 +25,10 @@ type OAuthApp struct {
ClientSecret string `json:"client_secret"`
Name string `json:"name"`
Description string `json:"description"`
+ IconURL string `json:"icon_url"`
CallbackUrls StringArray `json:"callback_urls"`
Homepage string `json:"homepage"`
+ IsTrusted bool `json:"is_trusted"`
}
// IsValid validates the app and returns an error if it isn't configured
@@ -61,7 +63,13 @@ func (a *OAuthApp) IsValid() *AppError {
return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "app_id="+a.Id)
}
- if len(a.Homepage) == 0 || len(a.Homepage) > 256 {
+ for _, callback := range a.CallbackUrls {
+ if !IsValidHttpUrl(callback) {
+ return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.callback.app_error", nil, "")
+ }
+ }
+
+ if len(a.Homepage) == 0 || len(a.Homepage) > 256 || !IsValidHttpUrl(a.Homepage) {
return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.homepage.app_error", nil, "app_id="+a.Id)
}
@@ -69,6 +77,12 @@ func (a *OAuthApp) IsValid() *AppError {
return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.description.app_error", nil, "app_id="+a.Id)
}
+ if len(a.IconURL) > 0 {
+ if len(a.IconURL) > 512 || !IsValidHttpUrl(a.IconURL) {
+ return NewLocAppError("OAuthApp.IsValid", "model.oauth.is_valid.icon_url.app_error", nil, "app_id="+a.Id)
+ }
+ }
+
return nil
}
@@ -85,10 +99,6 @@ func (a *OAuthApp) PreSave() {
a.CreateAt = GetMillis()
a.UpdateAt = a.CreateAt
-
- if len(a.ClientSecret) > 0 {
- a.ClientSecret = HashPassword(a.ClientSecret)
- }
}
// PreUpdate should be run before updating the app in the db.
@@ -157,3 +167,23 @@ func OAuthAppMapFromJson(data io.Reader) map[string]*OAuthApp {
return nil
}
}
+
+func OAuthAppListToJson(l []*OAuthApp) string {
+ b, err := json.Marshal(l)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func OAuthAppListFromJson(data io.Reader) []*OAuthApp {
+ decoder := json.NewDecoder(data)
+ var o []*OAuthApp
+ err := decoder.Decode(&o)
+ if err == nil {
+ return o
+ } else {
+ return nil
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/outgoing_webhook.go b/vendor/github.com/mattermost/platform/model/outgoing_webhook.go
index ee7a32f1..ec2ed75c 100644
--- a/vendor/github.com/mattermost/platform/model/outgoing_webhook.go
+++ b/vendor/github.com/mattermost/platform/model/outgoing_webhook.go
@@ -9,6 +9,7 @@ import (
"io"
"net/url"
"strconv"
+ "strings"
)
type OutgoingWebhook struct {
@@ -21,6 +22,7 @@ type OutgoingWebhook struct {
ChannelId string `json:"channel_id"`
TeamId string `json:"team_id"`
TriggerWords StringArray `json:"trigger_words"`
+ TriggerWhen int `json:"trigger_when"`
CallbackURLs StringArray `json:"callback_urls"`
DisplayName string `json:"display_name"`
Description string `json:"description"`
@@ -171,6 +173,10 @@ func (o *OutgoingWebhook) IsValid() *AppError {
return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "")
}
+ if o.TriggerWhen > 1 {
+ return NewLocAppError("OutgoingWebhook.IsValid", "model.outgoing_hook.is_valid.content_type.app_error", nil, "")
+ }
+
return nil
}
@@ -204,3 +210,17 @@ func (o *OutgoingWebhook) HasTriggerWord(word string) bool {
return false
}
+
+func (o *OutgoingWebhook) TriggerWordStartsWith(word string) bool {
+ if len(o.TriggerWords) == 0 || len(word) == 0 {
+ return false
+ }
+
+ for _, trigger := range o.TriggerWords {
+ if strings.HasPrefix(word, trigger) {
+ return true
+ }
+ }
+
+ return false
+}
diff --git a/vendor/github.com/mattermost/platform/model/post.go b/vendor/github.com/mattermost/platform/model/post.go
index 173c99e3..175aecdd 100644
--- a/vendor/github.com/mattermost/platform/model/post.go
+++ b/vendor/github.com/mattermost/platform/model/post.go
@@ -162,9 +162,6 @@ func (o *Post) AddProp(key string, value interface{}) {
o.Props[key] = value
}
-func (o *Post) PreExport() {
-}
-
func (o *Post) IsSystemMessage() bool {
return len(o.Type) >= len(POST_SYSTEM_MESSAGE_PREFIX) && o.Type[:len(POST_SYSTEM_MESSAGE_PREFIX)] == POST_SYSTEM_MESSAGE_PREFIX
}
diff --git a/vendor/github.com/mattermost/platform/model/preference.go b/vendor/github.com/mattermost/platform/model/preference.go
index 22858e04..5787fe6e 100644
--- a/vendor/github.com/mattermost/platform/model/preference.go
+++ b/vendor/github.com/mattermost/platform/model/preference.go
@@ -6,6 +6,8 @@ package model
import (
"encoding/json"
"io"
+ "regexp"
+ "strings"
"unicode/utf8"
)
@@ -13,10 +15,17 @@ const (
PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW = "direct_channel_show"
PREFERENCE_CATEGORY_TUTORIAL_STEPS = "tutorial_step"
PREFERENCE_CATEGORY_ADVANCED_SETTINGS = "advanced_settings"
+ PREFERENCE_CATEGORY_FLAGGED_POST = "flagged_post"
PREFERENCE_CATEGORY_DISPLAY_SETTINGS = "display_settings"
PREFERENCE_NAME_COLLAPSE_SETTING = "collapse_previews"
+ PREFERENCE_CATEGORY_THEME = "theme"
+ // the name for theme props is the team id
+
+ PREFERENCE_CATEGORY_AUTHORIZED_OAUTH_APP = "oauth_app"
+ // the name for oauth_app is the client_id and value is the current scope
+
PREFERENCE_CATEGORY_LAST = "last"
PREFERENCE_NAME_LAST_CHANNEL = "channel"
)
@@ -57,13 +66,48 @@ func (o *Preference) IsValid() *AppError {
return NewLocAppError("Preference.IsValid", "model.preference.is_valid.category.app_error", nil, "category="+o.Category)
}
- if len(o.Name) == 0 || len(o.Name) > 32 {
+ if len(o.Name) > 32 {
return NewLocAppError("Preference.IsValid", "model.preference.is_valid.name.app_error", nil, "name="+o.Name)
}
- if utf8.RuneCountInString(o.Value) > 128 {
+ if utf8.RuneCountInString(o.Value) > 2000 {
return NewLocAppError("Preference.IsValid", "model.preference.is_valid.value.app_error", nil, "value="+o.Value)
}
+ 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 nil
}
+
+func (o *Preference) PreUpdate() {
+ if o.Category == PREFERENCE_CATEGORY_THEME {
+ // decode the value of theme (a map of strings to string) and eliminate any invalid values
+ var props map[string]string
+ if err := json.NewDecoder(strings.NewReader(o.Value)).Decode(&props); err != nil {
+ // just continue, the invalid preference value should get caught by IsValid before saving
+ return
+ }
+
+ colorPattern := regexp.MustCompile(`^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$`)
+
+ // blank out any invalid theme values
+ for name, value := range props {
+ if name == "image" || name == "type" || name == "codeTheme" {
+ continue
+ }
+
+ if !colorPattern.MatchString(value) {
+ props[name] = "#ffffff"
+ }
+ }
+
+ if b, err := json.Marshal(props); err == nil {
+ o.Value = string(b)
+ }
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/session.go b/vendor/github.com/mattermost/platform/model/session.go
index 8a5eec74..ef51374d 100644
--- a/vendor/github.com/mattermost/platform/model/session.go
+++ b/vendor/github.com/mattermost/platform/model/session.go
@@ -83,7 +83,11 @@ func (me *Session) IsExpired() bool {
}
func (me *Session) SetExpireInDays(days int) {
- me.ExpiresAt = GetMillis() + (1000 * 60 * 60 * 24 * int64(days))
+ if me.CreateAt == 0 {
+ me.ExpiresAt = GetMillis() + (1000 * 60 * 60 * 24 * int64(days))
+ } else {
+ me.ExpiresAt = me.CreateAt + (1000 * 60 * 60 * 24 * int64(days))
+ }
}
func (me *Session) AddProp(key string, value string) {
diff --git a/vendor/github.com/mattermost/platform/model/status.go b/vendor/github.com/mattermost/platform/model/status.go
new file mode 100644
index 00000000..8bf26f2f
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/status.go
@@ -0,0 +1,42 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+)
+
+const (
+ STATUS_OFFLINE = "offline"
+ STATUS_AWAY = "away"
+ STATUS_ONLINE = "online"
+ STATUS_CACHE_SIZE = 10000
+)
+
+type Status struct {
+ UserId string `json:"user_id"`
+ Status string `json:"status"`
+ LastActivityAt int64 `json:"last_activity_at"`
+}
+
+func (o *Status) ToJson() string {
+ b, err := json.Marshal(o)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func StatusFromJson(data io.Reader) *Status {
+ decoder := json.NewDecoder(data)
+ var o Status
+ err := decoder.Decode(&o)
+ if err == nil {
+ return &o
+ } else {
+ return nil
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/team.go b/vendor/github.com/mattermost/platform/model/team.go
index 072e0a8c..dccc0219 100644
--- a/vendor/github.com/mattermost/platform/model/team.go
+++ b/vendor/github.com/mattermost/platform/model/team.go
@@ -224,9 +224,6 @@ func CleanTeamName(s string) string {
return s
}
-func (o *Team) PreExport() {
-}
-
func (o *Team) Sanitize() {
o.Email = ""
o.AllowedDomains = ""
diff --git a/vendor/github.com/mattermost/platform/model/user.go b/vendor/github.com/mattermost/platform/model/user.go
index c792f80d..bad616d7 100644
--- a/vendor/github.com/mattermost/platform/model/user.go
+++ b/vendor/github.com/mattermost/platform/model/user.go
@@ -16,11 +16,6 @@ import (
const (
ROLE_SYSTEM_ADMIN = "system_admin"
- USER_AWAY_TIMEOUT = 5 * 60 * 1000 // 5 minutes
- USER_OFFLINE_TIMEOUT = 1 * 60 * 1000 // 1 minute
- USER_OFFLINE = "offline"
- USER_AWAY = "away"
- USER_ONLINE = "online"
USER_NOTIFY_ALL = "all"
USER_NOTIFY_MENTION = "mention"
USER_NOTIFY_NONE = "none"
@@ -44,12 +39,9 @@ type User struct {
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Roles string `json:"roles"`
- LastActivityAt int64 `json:"last_activity_at,omitempty"`
- LastPingAt int64 `json:"last_ping_at,omitempty"`
AllowMarketing bool `json:"allow_marketing,omitempty"`
Props StringMap `json:"props,omitempty"`
NotifyProps StringMap `json:"notify_props,omitempty"`
- ThemeProps StringMap `json:"theme_props,omitempty"`
LastPasswordUpdate int64 `json:"last_password_update,omitempty"`
LastPictureUpdate int64 `json:"last_picture_update,omitempty"`
FailedAttempts int `json:"failed_attempts,omitempty"`
@@ -106,10 +98,6 @@ func (u *User) IsValid() *AppError {
return NewLocAppError("User.IsValid", "model.user.is_valid.auth_data_pwd.app_error", nil, "user_id="+u.Id)
}
- if len(u.ThemeProps) > 2000 {
- return NewLocAppError("User.IsValid", "model.user.is_valid.theme.app_error", nil, "user_id="+u.Id)
- }
-
return nil
}
@@ -179,21 +167,6 @@ func (u *User) PreUpdate() {
}
u.NotifyProps["mention_keys"] = strings.Join(goodKeys, ",")
}
-
- if u.ThemeProps != nil {
- colorPattern := regexp.MustCompile(`^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$`)
-
- // blank out any invalid theme values
- for name, value := range u.ThemeProps {
- if name == "image" || name == "type" || name == "codeTheme" {
- continue
- }
-
- if !colorPattern.MatchString(value) {
- u.ThemeProps[name] = "#ffffff"
- }
- }
- }
}
func (u *User) SetDefaultNotifications() {
@@ -242,14 +215,6 @@ func (u *User) Etag(showFullName, showEmail bool) string {
return Etag(u.Id, u.UpdateAt, showFullName, showEmail)
}
-func (u *User) IsOffline() bool {
- return (GetMillis()-u.LastPingAt) > USER_OFFLINE_TIMEOUT && (GetMillis()-u.LastActivityAt) > USER_OFFLINE_TIMEOUT
-}
-
-func (u *User) IsAway() bool {
- return (GetMillis() - u.LastActivityAt) > USER_AWAY_TIMEOUT
-}
-
// Remove any private data from the user object
func (u *User) Sanitize(options map[string]bool) {
u.Password = ""
@@ -278,11 +243,9 @@ func (u *User) ClearNonProfileFields() {
u.MfaActive = false
u.MfaSecret = ""
u.EmailVerified = false
- u.LastPingAt = 0
u.AllowMarketing = false
u.Props = StringMap{}
u.NotifyProps = StringMap{}
- u.ThemeProps = StringMap{}
u.LastPasswordUpdate = 0
u.LastPictureUpdate = 0
u.FailedAttempts = 0
@@ -392,17 +355,6 @@ func (u *User) IsLDAPUser() bool {
return false
}
-func (u *User) PreExport() {
- u.Password = ""
- u.AuthData = new(string)
- *u.AuthData = ""
- u.LastActivityAt = 0
- u.LastPingAt = 0
- u.LastPasswordUpdate = 0
- u.LastPictureUpdate = 0
- u.FailedAttempts = 0
-}
-
// UserFromJson will decode the input and return a User
func UserFromJson(data io.Reader) *User {
decoder := json.NewDecoder(data)
@@ -461,6 +413,7 @@ var validUsernameChars = regexp.MustCompile(`^[a-z0-9\.\-_]+$`)
var restrictedUsernames = []string{
"all",
"channel",
+ "matterbot",
}
func IsValidUsername(s string) bool {
diff --git a/vendor/github.com/mattermost/platform/model/utils.go b/vendor/github.com/mattermost/platform/model/utils.go
index 27ab3e27..a4a4208c 100644
--- a/vendor/github.com/mattermost/platform/model/utils.go
+++ b/vendor/github.com/mattermost/platform/model/utils.go
@@ -34,12 +34,12 @@ type EncryptStringMap map[string]string
type AppError struct {
Id string `json:"id"`
- Message string `json:"message"` // Message to be display to the end user without debugging information
- DetailedError string `json:"detailed_error"` // Internal error string to help the developer
- RequestId string `json:"request_id"` // The RequestId that's also set in the header
- StatusCode int `json:"status_code"` // The http status code
- Where string `json:"-"` // The function where it happened in the form of Struct.Func
- IsOAuth bool `json:"is_oauth"` // Whether the error is OAuth specific
+ Message string `json:"message"` // Message to be display to the end user without debugging information
+ DetailedError string `json:"detailed_error"` // Internal error string to help the developer
+ RequestId string `json:"request_id,omitempty"` // The RequestId that's also set in the header
+ StatusCode int `json:"status_code,omitempty"` // The http status code
+ Where string `json:"-"` // The function where it happened in the form of Struct.Func
+ IsOAuth bool `json:"is_oauth,omitempty"` // Whether the error is OAuth specific
params map[string]interface{} `json:"-"`
}
diff --git a/vendor/github.com/mattermost/platform/model/version.go b/vendor/github.com/mattermost/platform/model/version.go
index c6f49525..49e8af04 100644
--- a/vendor/github.com/mattermost/platform/model/version.go
+++ b/vendor/github.com/mattermost/platform/model/version.go
@@ -13,6 +13,7 @@ import (
// It should be maitained in chronological order with most current
// release at the front of the list.
var versions = []string{
+ "3.3.0",
"3.2.0",
"3.1.0",
"3.0.0",
diff --git a/vendor/github.com/mattermost/platform/model/websocket_client.go b/vendor/github.com/mattermost/platform/model/websocket_client.go
new file mode 100644
index 00000000..a048bd85
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/websocket_client.go
@@ -0,0 +1,109 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "github.com/gorilla/websocket"
+ "net/http"
+)
+
+type WebSocketClient struct {
+ Url string // The location of the server like "ws://localhost:8065"
+ ApiUrl string // The api location of the server like "ws://localhost:8065/api/v3"
+ Conn *websocket.Conn // The WebSocket connection
+ AuthToken string // The token used to open the WebSocket
+ Sequence int64 // The ever-incrementing sequence attached to each WebSocket action
+ EventChannel chan *WebSocketEvent
+ ResponseChannel chan *WebSocketResponse
+}
+
+// NewWebSocketClient constructs a new WebSocket client with convienence
+// methods for talking to the server.
+func NewWebSocketClient(url, authToken string) (*WebSocketClient, *AppError) {
+ header := http.Header{}
+ header.Set(HEADER_AUTH, "BEARER "+authToken)
+ conn, _, err := websocket.DefaultDialer.Dial(url+API_URL_SUFFIX+"/users/websocket", header)
+ if err != nil {
+ return nil, NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
+ }
+
+ return &WebSocketClient{
+ url,
+ url + API_URL_SUFFIX,
+ conn,
+ authToken,
+ 1,
+ make(chan *WebSocketEvent, 100),
+ make(chan *WebSocketResponse, 100),
+ }, nil
+}
+
+func (wsc *WebSocketClient) Connect() *AppError {
+ header := http.Header{}
+ header.Set(HEADER_AUTH, "BEARER "+wsc.AuthToken)
+
+ var err error
+ wsc.Conn, _, err = websocket.DefaultDialer.Dial(wsc.ApiUrl+"/users/websocket", header)
+ if err != nil {
+ return NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
+ }
+
+ return nil
+}
+
+func (wsc *WebSocketClient) Close() {
+ wsc.Conn.Close()
+}
+
+func (wsc *WebSocketClient) Listen() {
+ go func() {
+ for {
+ var rawMsg json.RawMessage
+ var err error
+ if _, rawMsg, err = wsc.Conn.ReadMessage(); err != nil {
+ return
+ }
+
+ var event WebSocketEvent
+ if err := json.Unmarshal(rawMsg, &event); err == nil && event.IsValid() {
+ wsc.EventChannel <- &event
+ continue
+ }
+
+ var response WebSocketResponse
+ if err := json.Unmarshal(rawMsg, &response); err == nil && response.IsValid() {
+ wsc.ResponseChannel <- &response
+ continue
+ }
+ }
+ }()
+}
+
+func (wsc *WebSocketClient) SendMessage(action string, data map[string]interface{}) {
+ req := &WebSocketRequest{}
+ req.Seq = wsc.Sequence
+ req.Action = action
+ req.Data = data
+
+ wsc.Sequence++
+
+ wsc.Conn.WriteJSON(req)
+}
+
+// UserTyping will push a user_typing event out to all connected users
+// who are in the specified channel
+func (wsc *WebSocketClient) UserTyping(channelId, parentId string) {
+ data := map[string]interface{}{
+ "channel_id": channelId,
+ "parent_id": parentId,
+ }
+
+ wsc.SendMessage("user_typing", data)
+}
+
+// GetStatuses will return a map of string statuses using user id as the key
+func (wsc *WebSocketClient) GetStatuses() {
+ wsc.SendMessage("get_statuses", nil)
+}
diff --git a/vendor/github.com/mattermost/platform/model/websocket_message.go b/vendor/github.com/mattermost/platform/model/websocket_message.go
new file mode 100644
index 00000000..ae9a140c
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/websocket_message.go
@@ -0,0 +1,114 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+)
+
+const (
+ WEBSOCKET_EVENT_TYPING = "typing"
+ WEBSOCKET_EVENT_POSTED = "posted"
+ WEBSOCKET_EVENT_POST_EDITED = "post_edited"
+ WEBSOCKET_EVENT_POST_DELETED = "post_deleted"
+ WEBSOCKET_EVENT_CHANNEL_DELETED = "channel_deleted"
+ WEBSOCKET_EVENT_CHANNEL_VIEWED = "channel_viewed"
+ WEBSOCKET_EVENT_DIRECT_ADDED = "direct_added"
+ WEBSOCKET_EVENT_NEW_USER = "new_user"
+ WEBSOCKET_EVENT_LEAVE_TEAM = "leave_team"
+ WEBSOCKET_EVENT_USER_ADDED = "user_added"
+ WEBSOCKET_EVENT_USER_REMOVED = "user_removed"
+ WEBSOCKET_EVENT_PREFERENCE_CHANGED = "preference_changed"
+ WEBSOCKET_EVENT_EPHEMERAL_MESSAGE = "ephemeral_message"
+ WEBSOCKET_EVENT_STATUS_CHANGE = "status_change"
+)
+
+type WebSocketMessage interface {
+ ToJson() string
+ IsValid() bool
+}
+
+type WebSocketEvent struct {
+ TeamId string `json:"team_id"`
+ ChannelId string `json:"channel_id"`
+ UserId string `json:"user_id"`
+ Event string `json:"event"`
+ Data map[string]interface{} `json:"data"`
+}
+
+func (m *WebSocketEvent) Add(key string, value interface{}) {
+ m.Data[key] = value
+}
+
+func NewWebSocketEvent(teamId string, channelId string, userId string, event string) *WebSocketEvent {
+ return &WebSocketEvent{TeamId: teamId, ChannelId: channelId, UserId: userId, Event: event, Data: make(map[string]interface{})}
+}
+
+func (o *WebSocketEvent) IsValid() bool {
+ return o.Event != ""
+}
+
+func (o *WebSocketEvent) ToJson() string {
+ b, err := json.Marshal(o)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func WebSocketEventFromJson(data io.Reader) *WebSocketEvent {
+ decoder := json.NewDecoder(data)
+ var o WebSocketEvent
+ err := decoder.Decode(&o)
+ if err == nil {
+ return &o
+ } else {
+ return nil
+ }
+}
+
+type WebSocketResponse struct {
+ Status string `json:"status"`
+ SeqReply int64 `json:"seq_reply,omitempty"`
+ Data map[string]interface{} `json:"data,omitempty"`
+ Error *AppError `json:"error,omitempty"`
+}
+
+func (m *WebSocketResponse) Add(key string, value interface{}) {
+ m.Data[key] = value
+}
+
+func NewWebSocketResponse(status string, seqReply int64, data map[string]interface{}) *WebSocketResponse {
+ return &WebSocketResponse{Status: status, SeqReply: seqReply, Data: data}
+}
+
+func NewWebSocketError(seqReply int64, err *AppError) *WebSocketResponse {
+ return &WebSocketResponse{Status: STATUS_FAIL, SeqReply: seqReply, Error: err}
+}
+
+func (o *WebSocketResponse) IsValid() bool {
+ return o.Status != ""
+}
+
+func (o *WebSocketResponse) ToJson() string {
+ b, err := json.Marshal(o)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func WebSocketResponseFromJson(data io.Reader) *WebSocketResponse {
+ decoder := json.NewDecoder(data)
+ var o WebSocketResponse
+ err := decoder.Decode(&o)
+ if err == nil {
+ return &o
+ } else {
+ return nil
+ }
+}
diff --git a/vendor/github.com/mattermost/platform/model/websocket_request.go b/vendor/github.com/mattermost/platform/model/websocket_request.go
new file mode 100644
index 00000000..d0f35f68
--- /dev/null
+++ b/vendor/github.com/mattermost/platform/model/websocket_request.go
@@ -0,0 +1,43 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package model
+
+import (
+ "encoding/json"
+ "io"
+
+ goi18n "github.com/nicksnyder/go-i18n/i18n"
+)
+
+type WebSocketRequest struct {
+ // Client-provided fields
+ Seq int64 `json:"seq"`
+ Action string `json:"action"`
+ Data map[string]interface{} `json:"data"`
+
+ // Server-provided fields
+ Session Session `json:"-"`
+ T goi18n.TranslateFunc `json:"-"`
+ Locale string `json:"-"`
+}
+
+func (o *WebSocketRequest) ToJson() string {
+ b, err := json.Marshal(o)
+ if err != nil {
+ return ""
+ } else {
+ return string(b)
+ }
+}
+
+func WebSocketRequestFromJson(data io.Reader) *WebSocketRequest {
+ decoder := json.NewDecoder(data)
+ var o WebSocketRequest
+ err := decoder.Decode(&o)
+ if err == nil {
+ return &o
+ } else {
+ return nil
+ }
+}