Этот коммит содержится в:
=Corey Hulen
2016-01-08 12:41:26 -06:00
родитель 001a4448ca
Коммит 3fba8e42b1
17 изменённых файлов: 578 добавлений и 78 удалений

Просмотреть файл

@@ -4,45 +4,169 @@
package api package api
import ( import (
// "io" //"io"
// "net/http" "net/http"
// "path" // "path"
// "strconv" // "strconv"
// "strings" "strings"
// "time" // "time"
l4g "code.google.com/p/log4go" l4g "code.google.com/p/log4go"
"github.com/gorilla/mux" "github.com/gorilla/mux"
// "github.com/mattermost/platform/model" "github.com/mattermost/platform/model"
// "github.com/mattermost/platform/utils" "github.com/mattermost/platform/utils"
) )
// type commandHandler func(c *Context, command *model.Command) bool type CommandProvider interface {
GetCommand() *model.Command
DoCommand(c *Context, channelId string, message string) *model.CommandResponse
}
// var ( var commandProviders = make(map[string]CommandProvider)
// cmds = map[string]string{
// "logoutCommand": "/logout", func RegisterCommandProvider(newProvider CommandProvider) {
// "joinCommand": "/join", commandProviders[newProvider.GetCommand().Trigger] = newProvider
// "loadTestCommand": "/loadtest", }
// "echoCommand": "/echo",
// "shrugCommand": "/shrug", func GetCommandProvidersProvider(name string) CommandProvider {
// "meCommand": "/me", provider, ok := commandProviders[name]
// } if ok {
// commands = []commandHandler{ return provider
// logoutCommand, }
// joinCommand,
// loadTestCommand, return nil
// echoCommand, }
// shrugCommand,
// meCommand,
// }
// commandNotImplementedErr = model.NewAppError("checkCommand", "Command not implemented", "")
// )
// var echoSem chan bool
func InitCommand(r *mux.Router) { func InitCommand(r *mux.Router) {
l4g.Debug("Initializing command api routes") l4g.Debug("Initializing command api routes")
// r.Handle("/command", ApiUserRequired(command)).Methods("POST")
sr := r.PathPrefix("/commands").Subrouter()
sr.Handle("/execute", ApiUserRequired(execute)).Methods("POST")
sr.Handle("/list", ApiUserRequired(listCommands)).Methods("POST")
sr.Handle("/create", ApiUserRequired(create)).Methods("POST")
sr.Handle("/list_team_commands", ApiUserRequired(listTeamCommands)).Methods("GET")
// sr.Handle("/regen_token", ApiUserRequired(regenOutgoingHookToken)).Methods("POST")
// sr.Handle("/delete", ApiUserRequired(deleteOutgoingHook)).Methods("POST")
}
func listCommands(c *Context, w http.ResponseWriter, r *http.Request) {
commands := make([]*model.Command, 0, 32)
for _, value := range commandProviders {
cpy := *value.GetCommand()
cpy.Token = ""
cpy.CreatorId = ""
cpy.Method = ""
cpy.URL = ""
cpy.Username = ""
cpy.IconURL = ""
commands = append(commands, &cpy)
}
w.Write([]byte(model.CommandListToJson(commands)))
}
func execute(c *Context, w http.ResponseWriter, r *http.Request) {
props := model.MapFromJson(r.Body)
command := strings.TrimSpace(props["command"])
channelId := strings.TrimSpace(props["channelId"])
if len(command) <= 1 || strings.Index(command, "/") != 0 {
c.Err = model.NewAppError("command", "Command must start with /", "")
return
}
if len(channelId) > 0 {
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId)
if !c.HasPermissionsToChannel(cchan, "checkCommand") {
return
}
}
parts := strings.Split(command, " ")
trigger := parts[0][1:]
provider := GetCommandProvidersProvider(trigger)
if provider != nil {
message := strings.Join(parts[1:], " ")
response := provider.DoCommand(c, channelId, message)
if response.ResponseType == model.COMMAND_RESPONSE_TYPE_IN_CHANNEL {
post := &model.Post{}
post.ChannelId = channelId
post.Message = response.Text
if _, err := CreatePost(c, post, true); err != nil {
c.Err = model.NewAppError("command", "An error while saving the command response to the channel", "")
}
}
w.Write([]byte(response.ToJson()))
} else {
c.Err = model.NewAppError("command", "Command with a trigger of '"+trigger+"' not found", "")
}
}
func create(c *Context, w http.ResponseWriter, r *http.Request) {
if !*utils.Cfg.ServiceSettings.EnableCommands {
c.Err = model.NewAppError("createCommand", "Commands have been disabled by the system admin.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
}
if *utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations {
if !(c.IsSystemAdmin() || c.IsTeamAdmin()) {
c.Err = model.NewAppError("createCommand", "Integrations have been limited to admins only.", "")
c.Err.StatusCode = http.StatusForbidden
return
}
}
c.LogAudit("attempt")
cmd := model.CommandFromJson(r.Body)
if cmd == nil {
c.SetInvalidParam("createCommand", "command")
return
}
cmd.CreatorId = c.Session.UserId
cmd.TeamId = c.Session.TeamId
if result := <-Srv.Store.Command().Save(cmd); result.Err != nil {
c.Err = result.Err
return
} else {
c.LogAudit("success")
rcmd := result.Data.(*model.Command)
w.Write([]byte(rcmd.ToJson()))
}
}
func listTeamCommands(c *Context, w http.ResponseWriter, r *http.Request) {
if !*utils.Cfg.ServiceSettings.EnableCommands {
c.Err = model.NewAppError("createCommand", "Commands have been disabled by the system admin.", "")
c.Err.StatusCode = http.StatusNotImplemented
return
}
if *utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations {
if !(c.IsSystemAdmin() || c.IsTeamAdmin()) {
c.Err = model.NewAppError("createCommand", "Integrations have been limited to admins only.", "")
c.Err.StatusCode = http.StatusForbidden
return
}
}
if result := <-Srv.Store.Command().GetByTeam(c.Session.TeamId); result.Err != nil {
c.Err = result.Err
return
} else {
cmds := result.Data.([]*model.Command)
w.Write([]byte(model.CommandListToJson(cmds)))
}
} }
// func command(c *Context, w http.ResponseWriter, r *http.Request) { // func command(c *Context, w http.ResponseWriter, r *http.Request) {

81
api/command_echo.go Обычный файл
Просмотреть файл

@@ -0,0 +1,81 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package api
import (
"strconv"
"strings"
"time"
l4g "code.google.com/p/log4go"
"github.com/mattermost/platform/model"
)
var echoSem chan bool
type EchoProvider struct {
}
func init() {
RegisterCommandProvider(&EchoProvider{})
}
func (me *EchoProvider) GetCommand() *model.Command {
return &model.Command{
Trigger: "echo",
AutoComplete: true,
AutoCompleteDesc: "Echo back text from your account",
AutoCompleteHint: "\"message\" [delay in seconds]",
DisplayName: "echo",
}
}
func (me *EchoProvider) DoCommand(c *Context, channelId string, message string) *model.CommandResponse {
maxThreads := 100
delay := 0
if endMsg := strings.LastIndex(message, "\""); string(message[0]) == "\"" && endMsg > 1 {
if checkDelay, err := strconv.Atoi(strings.Trim(message[endMsg:], " \"")); err == nil {
delay = checkDelay
}
message = message[1:endMsg]
} else if strings.Index(message, " ") > -1 {
delayIdx := strings.LastIndex(message, " ")
delayStr := strings.Trim(message[delayIdx:], " ")
if checkDelay, err := strconv.Atoi(delayStr); err == nil {
delay = checkDelay
message = message[:delayIdx]
}
}
if delay > 10000 {
return &model.CommandResponse{Text: "Delays must be under 10000 seconds", ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
}
if echoSem == nil {
// We want one additional thread allowed so we never reach channel lockup
echoSem = make(chan bool, maxThreads+1)
}
if len(echoSem) >= maxThreads {
return &model.CommandResponse{Text: "High volume of echo request, cannot process request", ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
}
echoSem <- true
go func() {
defer func() { <-echoSem }()
post := &model.Post{}
post.ChannelId = channelId
post.Message = message
time.Sleep(time.Duration(delay) * time.Second)
if _, err := CreatePost(c, post, true); err != nil {
l4g.Error("Unable to create /echo post, err=%v", err)
}
}()
return &model.CommandResponse{}
}

42
api/command_echo_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,42 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package api
import (
"testing"
"time"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
)
func TestEchoCommand(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
echoTestString := "/echo test"
r1 := Client.Must(Client.Command(channel1.Id, echoTestString, false)).Data.(*model.CommandResponse)
if r1 == nil {
t.Fatal("Echo command failed to execute")
}
time.Sleep(100 * time.Millisecond)
p1 := Client.Must(Client.GetPosts(channel1.Id, 0, 2, "")).Data.(*model.PostList)
if len(p1.Order) != 1 {
t.Fatal("Echo command failed to send")
}
}

Просмотреть файл

@@ -3,15 +3,127 @@
package api package api
// import ( import (
// "strings" "testing"
// "testing"
// "time"
// "github.com/mattermost/platform/model" "github.com/mattermost/platform/model"
// "github.com/mattermost/platform/store" "github.com/mattermost/platform/store"
// "github.com/mattermost/platform/utils" "github.com/mattermost/platform/utils"
// ) )
func TestListCommands(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
if results, err := Client.ListCommands(); err != nil {
t.Fatal(err)
} else {
commands := results.Data.([]*model.Command)
foundEcho := false
for _, command := range commands {
if command.Trigger == "echo" {
foundEcho = true
}
}
if !foundEcho {
t.Fatal("Couldn't find echo command")
}
}
}
func TestCreateCommand(t *testing.T) {
Setup()
*utils.Cfg.ServiceSettings.EnableCommands = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
cmd := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST}
if _, err := Client.CreateCommand(cmd); err == nil {
t.Fatal("should have failed because not admin")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
var rcmd *model.Command
if result, err := Client.CreateCommand(cmd); err != nil {
t.Fatal(err)
} else {
rcmd = result.Data.(*model.Command)
}
if rcmd.CreatorId != user.Id {
t.Fatal("user ids didn't match")
}
if rcmd.TeamId != team.Id {
t.Fatal("team ids didn't match")
}
cmd = &model.Command{CreatorId: "123", TeamId: "456", URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST}
if result, err := Client.CreateCommand(cmd); err != nil {
t.Fatal(err)
} else {
if result.Data.(*model.Command).CreatorId != user.Id {
t.Fatal("bad user id wasn't overwritten")
}
if result.Data.(*model.Command).TeamId != team.Id {
t.Fatal("bad team id wasn't overwritten")
}
}
*utils.Cfg.ServiceSettings.EnableCommands = false
}
func TestListTeamCommands(t *testing.T) {
Setup()
*utils.Cfg.ServiceSettings.EnableCommands = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
cmd1 := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST}
cmd1 = Client.Must(Client.CreateCommand(cmd1)).Data.(*model.Command)
if result, err := Client.ListTeamCommands(); err != nil {
t.Fatal(err)
} else {
cmds := result.Data.([]*model.Command)
if len(hooks) != 1 {
t.Fatal("incorrect number of cmd")
}
}
*utils.Cfg.ServiceSettings.EnableCommands = false
}
// func TestSuggestRootCommands(t *testing.T) { // func TestSuggestRootCommands(t *testing.T) {
// Setup() // Setup()

Просмотреть файл

@@ -1435,6 +1435,10 @@ func PermanentDeleteUser(c *Context, user *model.User) *model.AppError {
return result.Err return result.Err
} }
if result := <-Srv.Store.Command().PermanentDeleteByUser(user.Id); result.Err != nil {
return result.Err
}
if result := <-Srv.Store.Preference().PermanentDeleteByUser(user.Id); result.Err != nil { if result := <-Srv.Store.Preference().PermanentDeleteByUser(user.Id); result.Err != nil {
return result.Err return result.Err
} }

Просмотреть файл

@@ -5,17 +5,19 @@
"SegmentDeveloperKey": "", "SegmentDeveloperKey": "",
"GoogleDeveloperKey": "", "GoogleDeveloperKey": "",
"EnableOAuthServiceProvider": false, "EnableOAuthServiceProvider": false,
"EnableIncomingWebhooks": false, "EnableIncomingWebhooks": true,
"EnableOutgoingWebhooks": false, "EnableOutgoingWebhooks": true,
"EnablePostUsernameOverride": false, "EnableCommands": true,
"EnablePostIconOverride": false, "EnableOnlyAdminIntegrations": true,
"EnablePostUsernameOverride": true,
"EnablePostIconOverride": true,
"EnableTesting": false, "EnableTesting": false,
"EnableDeveloper": false, "EnableDeveloper": false,
"EnableSecurityFixAlert": true, "EnableSecurityFixAlert": true,
"SessionLengthWebInDays" : 30, "SessionLengthWebInDays": 30,
"SessionLengthMobileInDays" : 30, "SessionLengthMobileInDays": 30,
"SessionLengthSSOInDays" : 30, "SessionLengthSSOInDays": 30,
"SessionCacheInMinutes" : 10 "SessionCacheInMinutes": 10
}, },
"TeamSettings": { "TeamSettings": {
"SiteName": "Mattermost", "SiteName": "Mattermost",
@@ -107,5 +109,28 @@
"AuthEndpoint": "", "AuthEndpoint": "",
"TokenEndpoint": "", "TokenEndpoint": "",
"UserApiEndpoint": "" "UserApiEndpoint": ""
},
"GoogleSettings": {
"Enable": false,
"Secret": "",
"Id": "",
"Scope": "",
"AuthEndpoint": "",
"TokenEndpoint": "",
"UserApiEndpoint": ""
},
"LdapSettings": {
"Enable": false,
"LdapServer": null,
"LdapPort": 389,
"BaseDN": null,
"BindUsername": null,
"BindPassword": null,
"FirstNameAttribute": null,
"LastNameAttribute": null,
"EmailAttribute": null,
"UsernameAttribute": null,
"IdAttribute": null,
"QueryTimeout": 60
} }
} }

Просмотреть файл

@@ -7,6 +7,8 @@
"EnableOAuthServiceProvider": false, "EnableOAuthServiceProvider": false,
"EnableIncomingWebhooks": false, "EnableIncomingWebhooks": false,
"EnableOutgoingWebhooks": false, "EnableOutgoingWebhooks": false,
"EnableCommands": false,
"EnableOnlyAdminIntegrations": false,
"EnablePostUsernameOverride": false, "EnablePostUsernameOverride": false,
"EnablePostIconOverride": false, "EnablePostIconOverride": false,
"EnableTesting": false, "EnableTesting": false,

Просмотреть файл

@@ -7,6 +7,8 @@
"EnableOAuthServiceProvider": false, "EnableOAuthServiceProvider": false,
"EnableIncomingWebhooks": false, "EnableIncomingWebhooks": false,
"EnableOutgoingWebhooks": false, "EnableOutgoingWebhooks": false,
"EnableCommands": false,
"EnableOnlyAdminIntegrations": false,
"EnablePostUsernameOverride": false, "EnablePostUsernameOverride": false,
"EnablePostIconOverride": false, "EnablePostIconOverride": false,
"EnableTesting": false, "EnableTesting": false,

Просмотреть файл

@@ -372,7 +372,25 @@ func (c *Client) Command(channelId string, command string, suggest bool) (*Resul
m["command"] = command m["command"] = command
m["channelId"] = channelId m["channelId"] = channelId
m["suggest"] = strconv.FormatBool(suggest) m["suggest"] = strconv.FormatBool(suggest)
if r, err := c.DoApiPost("/command", MapToJson(m)); err != nil { if r, err := c.DoApiPost("/commands/execute", MapToJson(m)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), CommandResponseFromJson(r.Body)}, nil
}
}
func (c *Client) ListCommands() (*Result, *AppError) {
if r, err := c.DoApiPost("/commands/list", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), CommandListFromJson(r.Body)}, nil
}
}
func (c *Client) CreateCommand(cmd *Command) (*Result, *AppError) {
if r, err := c.DoApiPost("/commands/create", cmd.ToJson()); err != nil {
return nil, err return nil, err
} else { } else {
return &Result{r.Header.Get(HEADER_REQUEST_ID), return &Result{r.Header.Get(HEADER_REQUEST_ID),

40
model/command_response.go Обычный файл
Просмотреть файл

@@ -0,0 +1,40 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"encoding/json"
"io"
)
const (
COMMAND_RESPONSE_TYPE_IN_CHANNEL = "in_channel"
COMMAND_RESPONSE_TYPE_EPHEMERAL = "ephemeral"
)
type CommandResponse struct {
ResponseType string `json:"response_type"`
Text string `json:"text"`
Attachments interface{} `json:"attachments"`
}
func (o *CommandResponse) ToJson() string {
b, err := json.Marshal(o)
if err != nil {
return ""
} else {
return string(b)
}
}
func CommandResponseFromJson(data io.Reader) *CommandResponse {
decoder := json.NewDecoder(data)
var o CommandResponse
err := decoder.Decode(&o)
if err == nil {
return &o
} else {
return nil
}
}

19
model/command_response_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,19 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"strings"
"testing"
)
func TestCommandResponseJson(t *testing.T) {
o := CommandResponse{Text: "test"}
json := o.ToJson()
ro := CommandResponseFromJson(strings.NewReader(json))
if o.Text != ro.Text {
t.Fatal("Ids do not match")
}
}

Просмотреть файл

@@ -24,22 +24,24 @@ const (
) )
type ServiceSettings struct { type ServiceSettings struct {
ListenAddress string ListenAddress string
MaximumLoginAttempts int MaximumLoginAttempts int
SegmentDeveloperKey string SegmentDeveloperKey string
GoogleDeveloperKey string GoogleDeveloperKey string
EnableOAuthServiceProvider bool EnableOAuthServiceProvider bool
EnableIncomingWebhooks bool EnableIncomingWebhooks bool
EnableOutgoingWebhooks bool EnableOutgoingWebhooks bool
EnablePostUsernameOverride bool EnableCommands *bool
EnablePostIconOverride bool EnableOnlyAdminIntegrations *bool
EnableTesting bool EnablePostUsernameOverride bool
EnableDeveloper *bool EnablePostIconOverride bool
EnableSecurityFixAlert *bool EnableTesting bool
SessionLengthWebInDays *int EnableDeveloper *bool
SessionLengthMobileInDays *int EnableSecurityFixAlert *bool
SessionLengthSSOInDays *int SessionLengthWebInDays *int
SessionCacheInMinutes *int SessionLengthMobileInDays *int
SessionLengthSSOInDays *int
SessionCacheInMinutes *int
} }
type SSOSettings struct { type SSOSettings struct {
@@ -330,6 +332,16 @@ func (o *Config) SetDefaults() {
o.ServiceSettings.SessionCacheInMinutes = new(int) o.ServiceSettings.SessionCacheInMinutes = new(int)
*o.ServiceSettings.SessionCacheInMinutes = 10 *o.ServiceSettings.SessionCacheInMinutes = 10
} }
if o.ServiceSettings.EnableCommands == nil {
o.ServiceSettings.EnableCommands = new(bool)
*o.ServiceSettings.EnableCommands = false
}
if o.ServiceSettings.EnableOnlyAdminIntegrations == nil {
o.ServiceSettings.EnableOnlyAdminIntegrations = new(bool)
*o.ServiceSettings.EnableOnlyAdminIntegrations = true
}
} }
func (o *Config) IsValid() *AppError { func (o *Config) IsValid() *AppError {

Просмотреть файл

@@ -24,10 +24,10 @@ var versions = []string{
} }
var CurrentVersion string = versions[0] var CurrentVersion string = versions[0]
var BuildNumber = "_BUILD_NUMBER_" var BuildNumber = "dev"
var BuildDate = "_BUILD_DATE_" var BuildDate = "Fri Jan 8 14:19:26 UTC 2016"
var BuildHash = "_BUILD_HASH_" var BuildHash = "001a4448ca5fb0018eeb442915b473b121c04bf3"
var BuildEnterpriseReady = "_BUILD_ENTERPRISE_READY_" var BuildEnterpriseReady = "false"
func SplitVersion(version string) (int64, int64, int64) { func SplitVersion(version string) (int64, int64, int64) {
parts := strings.Split(version, ".") parts := strings.Split(version, ".")
@@ -73,7 +73,7 @@ func GetPreviousVersion(currentVersion string) (int64, int64) {
} }
func IsOfficalBuild() bool { func IsOfficalBuild() bool {
return BuildNumber != "_BUILD_NUMBER_" return BuildNumber != "dev"
} }
func IsCurrentVersion(versionToCheck string) bool { func IsCurrentVersion(versionToCheck string) bool {

Просмотреть файл

@@ -194,6 +194,8 @@ func getClientConfig(c *model.Config) map[string]string {
props["GoogleDeveloperKey"] = c.ServiceSettings.GoogleDeveloperKey props["GoogleDeveloperKey"] = c.ServiceSettings.GoogleDeveloperKey
props["EnableIncomingWebhooks"] = strconv.FormatBool(c.ServiceSettings.EnableIncomingWebhooks) props["EnableIncomingWebhooks"] = strconv.FormatBool(c.ServiceSettings.EnableIncomingWebhooks)
props["EnableOutgoingWebhooks"] = strconv.FormatBool(c.ServiceSettings.EnableOutgoingWebhooks) props["EnableOutgoingWebhooks"] = strconv.FormatBool(c.ServiceSettings.EnableOutgoingWebhooks)
props["EnableCommands"] = strconv.FormatBool(*c.ServiceSettings.EnableCommands)
props["EnableOnlyAdminIntegrations"] = strconv.FormatBool(*c.ServiceSettings.EnableOnlyAdminIntegrations)
props["EnablePostUsernameOverride"] = strconv.FormatBool(c.ServiceSettings.EnablePostUsernameOverride) props["EnablePostUsernameOverride"] = strconv.FormatBool(c.ServiceSettings.EnablePostUsernameOverride)
props["EnablePostIconOverride"] = strconv.FormatBool(c.ServiceSettings.EnablePostIconOverride) props["EnablePostIconOverride"] = strconv.FormatBool(c.ServiceSettings.EnablePostIconOverride)
props["EnableDeveloper"] = strconv.FormatBool(*c.ServiceSettings.EnableDeveloper) props["EnableDeveloper"] = strconv.FormatBool(*c.ServiceSettings.EnableDeveloper)

Просмотреть файл

@@ -134,15 +134,10 @@ export default class CreatePost extends React.Component {
post.message, post.message,
false, false,
(data) => { (data) => {
if (data.response === 'not implemented') {
this.sendMessage(post);
return;
}
PostStore.storeDraft(data.channel_id, null); PostStore.storeDraft(data.channel_id, null);
this.setState({messageText: '', submitting: false, postError: null, previews: [], serverError: null}); this.setState({messageText: '', submitting: false, postError: null, previews: [], serverError: null});
if (data.goto_location.length > 0) { if (data.goto_location && data.goto_location.length > 0) {
window.location.href = data.goto_location; window.location.href = data.goto_location;
} }
}, },

Просмотреть файл

@@ -747,20 +747,28 @@ export function savePreferences(preferences, success, error) {
} }
export function getSuggestedCommands(command, suggestionId, component) { export function getSuggestedCommands(command, suggestionId, component) {
client.executeCommand( client.listCommands(
'',
command,
true,
(data) => { (data) => {
var matches = [];
data.forEach((cmd) => {
if (('/' + cmd.trigger).indexOf(command) === 0) {
matches.push({
suggestion: '/' + cmd.trigger + ' ' + cmd.auto_complete_hint,
description: cmd.auto_complete_desc
});
}
});
// pull out the suggested commands from the returned data // pull out the suggested commands from the returned data
const terms = data.suggestions.map((suggestion) => suggestion.suggestion); //const terms = matches.map((suggestion) => suggestion.trigger);
const terms = matches.map((suggestion) => suggestion.suggestion);
AppDispatcher.handleServerAction({ AppDispatcher.handleServerAction({
type: ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS, type: ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS,
id: suggestionId, id: suggestionId,
matchedPretext: command, matchedPretext: command,
terms, terms,
items: data.suggestions, items: matches,
component component
}); });
}, },

Просмотреть файл

@@ -839,7 +839,7 @@ export function getChannelExtraInfo(id, success, error) {
export function executeCommand(channelId, command, suggest, success, error) { export function executeCommand(channelId, command, suggest, success, error) {
$.ajax({ $.ajax({
url: '/api/v1/command', url: '/api/v1/commands/execute',
dataType: 'json', dataType: 'json',
contentType: 'application/json', contentType: 'application/json',
type: 'POST', type: 'POST',
@@ -852,6 +852,20 @@ export function executeCommand(channelId, command, suggest, success, error) {
}); });
} }
export function listCommands(success, error) {
$.ajax({
url: '/api/v1/commands/list',
dataType: 'json',
contentType: 'application/json',
type: 'POST',
success,
error: function onError(xhr, status, err) {
var e = handleError('listCommands', xhr, status, err);
error(e);
}
});
}
export function getPostsPage(channelId, offset, limit, success, error, complete) { export function getPostsPage(channelId, offset, limit, success, error, complete) {
$.ajax({ $.ajax({
cache: false, cache: false,