mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
488 lines
14 KiB
Go
488 lines
14 KiB
Go
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
|
// See License.txt for license information.
|
|
|
|
package api
|
|
|
|
import (
|
|
l4g "code.google.com/p/log4go"
|
|
"github.com/gorilla/mux"
|
|
"github.com/mattermost/platform/model"
|
|
"github.com/mattermost/platform/utils"
|
|
"net/http"
|
|
"reflect"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type commandHandler func(c *Context, command *model.Command) bool
|
|
|
|
var commands = []commandHandler{
|
|
logoutCommand,
|
|
joinCommand,
|
|
loadTestCommand,
|
|
echoCommand,
|
|
}
|
|
|
|
func InitCommand(r *mux.Router) {
|
|
l4g.Debug("Initializing command api routes")
|
|
r.Handle("/command", ApiUserRequired(command)).Methods("POST")
|
|
}
|
|
|
|
func command(c *Context, w http.ResponseWriter, r *http.Request) {
|
|
|
|
props := model.MapFromJson(r.Body)
|
|
|
|
command := &model.Command{
|
|
Command: strings.TrimSpace(props["command"]),
|
|
ChannelId: strings.TrimSpace(props["channelId"]),
|
|
Suggest: props["suggest"] == "true",
|
|
Suggestions: make([]*model.SuggestCommand, 0, 128),
|
|
}
|
|
|
|
checkCommand(c, command)
|
|
|
|
if c.Err != nil {
|
|
return
|
|
} else {
|
|
w.Write([]byte(command.ToJson()))
|
|
}
|
|
}
|
|
|
|
func checkCommand(c *Context, command *model.Command) bool {
|
|
|
|
if len(command.Command) == 0 || strings.Index(command.Command, "/") != 0 {
|
|
c.Err = model.NewAppError("checkCommand", "Command must start with /", "")
|
|
return false
|
|
}
|
|
|
|
tchan := Srv.Store.Team().Get(c.Session.TeamId)
|
|
|
|
if len(command.ChannelId) > 0 {
|
|
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, command.ChannelId, c.Session.UserId)
|
|
|
|
if !c.HasPermissionsToChannel(cchan, "checkCommand") {
|
|
return true
|
|
}
|
|
}
|
|
|
|
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 {
|
|
if !allowValet && ec == runtime.FuncForPC(reflect.ValueOf(v).Pointer()).Name() {
|
|
continue
|
|
}
|
|
|
|
if v(c, command) {
|
|
return true
|
|
} else if c.Err != nil {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func logoutCommand(c *Context, command *model.Command) bool {
|
|
|
|
cmd := "/logout"
|
|
|
|
if strings.Index(command.Command, cmd) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: "Logout"})
|
|
|
|
if !command.Suggest {
|
|
command.GotoLocation = "/logout"
|
|
command.Response = model.RESP_EXECUTED
|
|
return true
|
|
}
|
|
|
|
} else if strings.Index(cmd, command.Command) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: "Logout"})
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func echoCommand(c *Context, command *model.Command) bool {
|
|
|
|
cmd := "/echo"
|
|
|
|
if strings.Index(command.Command, cmd) == 0 {
|
|
parts := strings.SplitN(command.Command, " ", 3)
|
|
|
|
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
|
|
} else {
|
|
channels := result.Data.(*model.ChannelList)
|
|
|
|
for _, v := range channels.Channels {
|
|
if v.Type == model.CHANNEL_DIRECT {
|
|
continue
|
|
}
|
|
|
|
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"})
|
|
}
|
|
}
|
|
}
|
|
|
|
} else if strings.Index(cmd, command.Command) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: "Echo a message using Valet in a channel"})
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func joinCommand(c *Context, command *model.Command) bool {
|
|
|
|
// looks for "/join channel-name"
|
|
cmd := "/join"
|
|
|
|
if strings.Index(command.Command, cmd) == 0 {
|
|
|
|
parts := strings.Split(command.Command, " ")
|
|
|
|
startsWith := ""
|
|
|
|
if len(parts) == 2 {
|
|
startsWith = parts[1]
|
|
}
|
|
|
|
if result := <-Srv.Store.Channel().GetMoreChannels(c.Session.TeamId, c.Session.UserId); result.Err != nil {
|
|
c.Err = result.Err
|
|
return false
|
|
} else {
|
|
channels := result.Data.(*model.ChannelList)
|
|
|
|
for _, v := range channels.Channels {
|
|
|
|
if v.Name == startsWith && !command.Suggest {
|
|
|
|
if v.Type == model.CHANNEL_DIRECT {
|
|
return false
|
|
}
|
|
|
|
JoinChannel(c, v.Id, "")
|
|
|
|
if c.Err != nil {
|
|
return false
|
|
}
|
|
|
|
command.GotoLocation = "/channels/" + v.Name
|
|
command.Response = model.RESP_EXECUTED
|
|
return true
|
|
}
|
|
|
|
if len(startsWith) == 0 || strings.Index(v.Name, startsWith) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd + " " + v.Name, Description: "Join the open channel"})
|
|
}
|
|
}
|
|
}
|
|
} else if strings.Index(cmd, command.Command) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: "Join an open channel"})
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func loadTestCommand(c *Context, command *model.Command) bool {
|
|
cmd := "/loadtest"
|
|
|
|
// This command is only available when AllowTesting is true
|
|
if !utils.Cfg.ServiceSettings.AllowTesting {
|
|
return false
|
|
}
|
|
|
|
if strings.Index(command.Command, cmd) == 0 {
|
|
if loadTestSetupCommand(c, command) {
|
|
return true
|
|
}
|
|
if loadTestUsersCommand(c, command) {
|
|
return true
|
|
}
|
|
if loadTestChannelsCommand(c, command) {
|
|
return true
|
|
}
|
|
if loadTestPostsCommand(c, command) {
|
|
return true
|
|
}
|
|
} else if strings.Index(cmd, command.Command) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: "Debug Load Testing"})
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func parseRange(command string, cmd string) (utils.Range, bool) {
|
|
tokens := strings.Fields(strings.TrimPrefix(command, cmd))
|
|
var begin int
|
|
var end int
|
|
var err1 error
|
|
var err2 error
|
|
switch {
|
|
case len(tokens) == 1:
|
|
begin, err1 = strconv.Atoi(tokens[0])
|
|
end = begin
|
|
if err1 != nil {
|
|
return utils.Range{0, 0}, false
|
|
}
|
|
case len(tokens) >= 2:
|
|
begin, err1 = strconv.Atoi(tokens[0])
|
|
end, err2 = strconv.Atoi(tokens[1])
|
|
if err1 != nil || err2 != nil {
|
|
return utils.Range{0, 0}, false
|
|
}
|
|
default:
|
|
return utils.Range{0, 0}, false
|
|
}
|
|
return utils.Range{begin, end}, true
|
|
}
|
|
|
|
func contains(items []string, token string) bool {
|
|
for _, elem := range items {
|
|
if elem == token {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func loadTestSetupCommand(c *Context, command *model.Command) bool {
|
|
cmd := "/loadtest setup"
|
|
|
|
if strings.Index(command.Command, cmd) == 0 && !command.Suggest {
|
|
tokens := strings.Fields(strings.TrimPrefix(command.Command, cmd))
|
|
doTeams := contains(tokens, "teams")
|
|
doFuzz := contains(tokens, "fuzz")
|
|
|
|
numArgs := 0
|
|
if doTeams {
|
|
numArgs++
|
|
}
|
|
if doFuzz {
|
|
numArgs++
|
|
}
|
|
|
|
var numTeams int
|
|
var numChannels int
|
|
var numUsers int
|
|
var numPosts int
|
|
|
|
// Defaults
|
|
numTeams = 10
|
|
numChannels = 10
|
|
numUsers = 10
|
|
numPosts = 10
|
|
|
|
if doTeams {
|
|
if (len(tokens) - numArgs) >= 4 {
|
|
numTeams, _ = strconv.Atoi(tokens[numArgs+0])
|
|
numChannels, _ = strconv.Atoi(tokens[numArgs+1])
|
|
numUsers, _ = strconv.Atoi(tokens[numArgs+2])
|
|
numPosts, _ = strconv.Atoi(tokens[numArgs+3])
|
|
}
|
|
} else {
|
|
if (len(tokens) - numArgs) >= 3 {
|
|
numChannels, _ = strconv.Atoi(tokens[numArgs+0])
|
|
numUsers, _ = strconv.Atoi(tokens[numArgs+1])
|
|
numPosts, _ = strconv.Atoi(tokens[numArgs+2])
|
|
}
|
|
}
|
|
client := model.NewClient(c.TeamUrl + "/api/v1")
|
|
|
|
if doTeams {
|
|
if err := CreateBasicUser(client); err != nil {
|
|
l4g.Error("Failed to create testing enviroment")
|
|
return true
|
|
}
|
|
client.LoginByEmail(BTEST_TEAM_DOMAIN_NAME, BTEST_USER_EMAIL, BTEST_USER_PASSWORD)
|
|
enviroment, err := CreateTestEnviromentWithTeams(
|
|
client,
|
|
utils.Range{numTeams, numTeams},
|
|
utils.Range{numChannels, numChannels},
|
|
utils.Range{numUsers, numUsers},
|
|
utils.Range{numPosts, numPosts},
|
|
doFuzz)
|
|
if err != true {
|
|
l4g.Error("Failed to create testing enviroment")
|
|
return true
|
|
} else {
|
|
l4g.Info("Testing enviroment created")
|
|
for i := 0; i < len(enviroment.Teams); i++ {
|
|
l4g.Info("Team Created: " + enviroment.Teams[i].Domain)
|
|
l4g.Info("\t User to login: " + enviroment.Enviroments[i].Users[0].Email + ", " + USER_PASSWORD)
|
|
}
|
|
}
|
|
} else {
|
|
client.MockSession(c.Session.Id)
|
|
CreateTestEnviromentInTeam(
|
|
client,
|
|
c.Session.TeamId,
|
|
utils.Range{numChannels, numChannels},
|
|
utils.Range{numUsers, numUsers},
|
|
utils.Range{numPosts, numPosts},
|
|
doFuzz)
|
|
}
|
|
return true
|
|
} else if strings.Index(cmd, command.Command) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{
|
|
Suggestion: cmd,
|
|
Description: "Creates a testing enviroment in current team. [teams] [fuzz] <Num Channels> <Num Users> <NumPosts>"})
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func loadTestUsersCommand(c *Context, command *model.Command) bool {
|
|
cmd1 := "/loadtest users"
|
|
cmd2 := "/loadtest users fuzz"
|
|
|
|
if strings.Index(command.Command, cmd1) == 0 && !command.Suggest {
|
|
cmd := cmd1
|
|
doFuzz := false
|
|
if strings.Index(command.Command, cmd2) == 0 {
|
|
doFuzz = true
|
|
cmd = cmd2
|
|
}
|
|
usersr, err := parseRange(command.Command, cmd)
|
|
if err == false {
|
|
usersr = utils.Range{10, 15}
|
|
}
|
|
client := model.NewClient(c.TeamUrl + "/api/v1")
|
|
userCreator := NewAutoUserCreator(client, c.Session.TeamId)
|
|
userCreator.Fuzzy = doFuzz
|
|
userCreator.CreateTestUsers(usersr)
|
|
return true
|
|
} else if strings.Index(cmd1, command.Command) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd1, Description: "Add a specified number of random users to current team <Min Users> <Max Users>"})
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: "Add a specified number of random users with fuzz text to current team <Min Users> <Max Users>"})
|
|
} else if strings.Index(cmd2, command.Command) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: "Add a specified number of random users with fuzz text to current team <Min Users> <Max Users>"})
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func loadTestChannelsCommand(c *Context, command *model.Command) bool {
|
|
cmd1 := "/loadtest channels"
|
|
cmd2 := "/loadtest channels fuzz"
|
|
|
|
if strings.Index(command.Command, cmd1) == 0 && !command.Suggest {
|
|
cmd := cmd1
|
|
doFuzz := false
|
|
if strings.Index(command.Command, cmd2) == 0 {
|
|
doFuzz = true
|
|
cmd = cmd2
|
|
}
|
|
channelsr, err := parseRange(command.Command, cmd)
|
|
if err == false {
|
|
channelsr = utils.Range{20, 30}
|
|
}
|
|
client := model.NewClient(c.TeamUrl + "/api/v1")
|
|
client.MockSession(c.Session.Id)
|
|
channelCreator := NewAutoChannelCreator(client, c.Session.TeamId)
|
|
channelCreator.Fuzzy = doFuzz
|
|
channelCreator.CreateTestChannels(channelsr)
|
|
return true
|
|
} else if strings.Index(cmd1, command.Command) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd1, Description: "Add a specified number of random channels to current team <MinChannels> <MaxChannels>"})
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: "Add a specified number of random channels with fuzz text to current team <Min Channels> <Max Channels>"})
|
|
} else if strings.Index(cmd2, command.Command) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: "Add a specified number of random channels with fuzz text to current team <Min Channels> <Max Channels>"})
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func loadTestPostsCommand(c *Context, command *model.Command) bool {
|
|
cmd1 := "/loadtest posts"
|
|
cmd2 := "/loadtest posts fuzz"
|
|
|
|
if strings.Index(command.Command, cmd1) == 0 && !command.Suggest {
|
|
cmd := cmd1
|
|
doFuzz := false
|
|
if strings.Index(command.Command, cmd2) == 0 {
|
|
cmd = cmd2
|
|
doFuzz = true
|
|
}
|
|
|
|
postsr, err := parseRange(command.Command, cmd)
|
|
if err == false {
|
|
postsr = utils.Range{20, 30}
|
|
}
|
|
|
|
tokens := strings.Fields(strings.TrimPrefix(command.Command, cmd))
|
|
rimages := utils.Range{0, 0}
|
|
if len(tokens) >= 3 {
|
|
if numImages, err := strconv.Atoi(tokens[2]); err == nil {
|
|
rimages = utils.Range{numImages, numImages}
|
|
}
|
|
}
|
|
|
|
var usernames []string
|
|
if result := <-Srv.Store.User().GetProfiles(c.Session.TeamId); result.Err == nil {
|
|
profileUsers := result.Data.(map[string]*model.User)
|
|
usernames = make([]string, len(profileUsers))
|
|
i := 0
|
|
for _, userprof := range profileUsers {
|
|
usernames[i] = userprof.Username
|
|
i++
|
|
}
|
|
}
|
|
|
|
client := model.NewClient(c.TeamUrl + "/api/v1")
|
|
client.MockSession(c.Session.Id)
|
|
testPoster := NewAutoPostCreator(client, command.ChannelId)
|
|
testPoster.Fuzzy = doFuzz
|
|
testPoster.Users = usernames
|
|
|
|
numImages := utils.RandIntFromRange(rimages)
|
|
numPosts := utils.RandIntFromRange(postsr)
|
|
for i := 0; i < numPosts; i++ {
|
|
testPoster.HasImage = (i < numImages)
|
|
testPoster.CreateRandomPost()
|
|
}
|
|
return true
|
|
} else if strings.Index(cmd1, command.Command) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd1, Description: "Add some random posts to current channel <Min Posts> <Max Posts> <Min Images> <Max Images>"})
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: "Add some random posts with fuzz text to current channel <Min Posts> <Max Posts> <Min Images> <Max Images>"})
|
|
} else if strings.Index(cmd2, command.Command) == 0 {
|
|
command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: "Add some random posts with fuzz text to current channel <Min Posts> <Max Posts> <Min Images> <Max Images>"})
|
|
}
|
|
|
|
return false
|
|
}
|