124
api/command.go
124
api/command.go
@@ -4,15 +4,15 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"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"
|
||||||
"net/http"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type commandHandler func(c *Context, command *model.Command) bool
|
type commandHandler func(c *Context, command *model.Command) bool
|
||||||
@@ -24,6 +24,8 @@ var commands = []commandHandler{
|
|||||||
echoCommand,
|
echoCommand,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")
|
r.Handle("/command", ApiUserRequired(command)).Methods("POST")
|
||||||
@@ -41,7 +43,6 @@ func command(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkCommand(c, command)
|
checkCommand(c, command)
|
||||||
|
|
||||||
if c.Err != nil {
|
if c.Err != nil {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -56,8 +57,6 @@ func checkCommand(c *Context, command *model.Command) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
tchan := Srv.Store.Team().Get(c.Session.TeamId)
|
|
||||||
|
|
||||||
if len(command.ChannelId) > 0 {
|
if len(command.ChannelId) > 0 {
|
||||||
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, command.ChannelId, c.Session.UserId)
|
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, command.ChannelId, c.Session.UserId)
|
||||||
|
|
||||||
@@ -66,24 +65,9 @@ func checkCommand(c *Context, command *model.Command) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allowValet := false
|
|
||||||
if tResult := <-tchan; tResult.Err != nil {
|
|
||||||
c.Err = model.NewAppError("checkCommand", "Could not find the team for this session, team_id="+c.Session.TeamId, "")
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
allowValet = tResult.Data.(*model.Team).AllowValet
|
|
||||||
}
|
|
||||||
|
|
||||||
ec := runtime.FuncForPC(reflect.ValueOf(echoCommand).Pointer()).Name()
|
|
||||||
|
|
||||||
for _, v := range commands {
|
for _, v := range commands {
|
||||||
if !allowValet && ec == runtime.FuncForPC(reflect.ValueOf(v).Pointer()).Name() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if v(c, command) {
|
if v(c, command) || c.Err != nil {
|
||||||
return true
|
|
||||||
} else if c.Err != nil {
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,55 +96,65 @@ func logoutCommand(c *Context, command *model.Command) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func echoCommand(c *Context, command *model.Command) bool {
|
func echoCommand(c *Context, command *model.Command) bool {
|
||||||
|
|
||||||
cmd := "/echo"
|
cmd := "/echo"
|
||||||
|
maxThreads := 100
|
||||||
|
|
||||||
if strings.Index(command.Command, cmd) == 0 {
|
if !command.Suggest && strings.Index(command.Command, cmd) == 0 {
|
||||||
parts := strings.SplitN(command.Command, " ", 3)
|
parameters := strings.SplitN(command.Command, " ", 2)
|
||||||
|
if len(parameters) != 2 || len(parameters[1]) == 0 {
|
||||||
channelName := ""
|
|
||||||
if len(parts) >= 2 {
|
|
||||||
channelName = parts[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
message := ""
|
|
||||||
if len(parts) >= 3 {
|
|
||||||
message = parts[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
if result := <-Srv.Store.Channel().GetChannels(c.Session.TeamId, c.Session.UserId); result.Err != nil {
|
|
||||||
c.Err = result.Err
|
|
||||||
return false
|
return false
|
||||||
} else {
|
}
|
||||||
channels := result.Data.(*model.ChannelList)
|
message := strings.Trim(parameters[1], " ")
|
||||||
|
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:], " ")
|
||||||
|
|
||||||
for _, v := range channels.Channels {
|
if checkDelay, err := strconv.Atoi(delayStr); err == nil {
|
||||||
if v.Type == model.CHANNEL_DIRECT {
|
delay = checkDelay
|
||||||
continue
|
message = message[:delayIdx]
|
||||||
}
|
|
||||||
|
|
||||||
if v.Name == channelName && !command.Suggest {
|
|
||||||
post := &model.Post{}
|
|
||||||
post.ChannelId = v.Id
|
|
||||||
post.Message = message
|
|
||||||
|
|
||||||
if _, err := CreateValetPost(c, post); err != nil {
|
|
||||||
c.Err = err
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
command.Response = model.RESP_EXECUTED
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(channelName) == 0 || (strings.Index(v.Name, channelName) == 0 && len(parts) < 3) {
|
|
||||||
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd + " " + v.Name, Description: "Echo a message using Valet in a channel"})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if delay > 10000 {
|
||||||
|
c.Err = model.NewAppError("echoCommand", "Delays must be under 10000 seconds", "")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
c.Err = model.NewAppError("echoCommand", "High volume of echo request, cannot process request", "")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
echoSem <- true
|
||||||
|
go func() {
|
||||||
|
defer func() { <-echoSem }()
|
||||||
|
post := &model.Post{}
|
||||||
|
post.ChannelId = command.ChannelId
|
||||||
|
post.Message = message
|
||||||
|
|
||||||
|
time.Sleep(time.Duration(delay) * time.Second)
|
||||||
|
|
||||||
|
if _, err := CreatePost(c, post, false); err != nil {
|
||||||
|
l4g.Error("Unable to create /echo post, err=%v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
command.Response = model.RESP_EXECUTED
|
||||||
|
return true
|
||||||
|
|
||||||
} else if strings.Index(cmd, command.Command) == 0 {
|
} else if strings.Index(cmd, command.Command) == 0 {
|
||||||
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: "Echo a message using Valet in a channel"})
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: "Echo back text from your account, /echo \"message\" [delay in seoncds]"})
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/mattermost/platform/model"
|
"github.com/mattermost/platform/model"
|
||||||
"github.com/mattermost/platform/store"
|
"github.com/mattermost/platform/store"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSuggestRootCommands(t *testing.T) {
|
func TestSuggestRootCommands(t *testing.T) {
|
||||||
@@ -50,6 +51,12 @@ func TestSuggestRootCommands(t *testing.T) {
|
|||||||
if rs3.Suggestions[0].Suggestion != "/join" {
|
if rs3.Suggestions[0].Suggestion != "/join" {
|
||||||
t.Fatal("should have join cmd")
|
t.Fatal("should have join cmd")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rs4 := Client.Must(Client.Command("", "/ech", true)).Data.(*model.Command)
|
||||||
|
|
||||||
|
if rs4.Suggestions[0].Suggestion != "/echo" {
|
||||||
|
t.Fatal("should have echo cmd")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogoutCommands(t *testing.T) {
|
func TestLogoutCommands(t *testing.T) {
|
||||||
@@ -145,3 +152,31 @@ func TestJoinCommands(t *testing.T) {
|
|||||||
t.Fatal("didn't join channel")
|
t.Fatal("didn't join channel")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.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.Command)
|
||||||
|
if r1.Response != model.RESP_EXECUTED {
|
||||||
|
t.Fatal("Echo command failed to execute")
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 := Client.Must(Client.GetPosts(channel1.Id, 0, 2, "")).Data.(*model.PostList)
|
||||||
|
if len(p1.Order) != 1 {
|
||||||
|
t.Fatal("Echo command failed to send")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const (
|
|||||||
|
|
||||||
type Command struct {
|
type Command struct {
|
||||||
Command string `json:"command"`
|
Command string `json:"command"`
|
||||||
Response string `json:"reponse"`
|
Response string `json:"response"`
|
||||||
GotoLocation string `json:"goto_location"`
|
GotoLocation string `json:"goto_location"`
|
||||||
ChannelId string `json:"channel_id"`
|
ChannelId string `json:"channel_id"`
|
||||||
Suggest bool `json:"-"`
|
Suggest bool `json:"-"`
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user