summaryrefslogtreecommitdiffstats
path: root/api/command.go
diff options
context:
space:
mode:
Diffstat (limited to 'api/command.go')
-rw-r--r--api/command.go470
1 files changed, 470 insertions, 0 deletions
diff --git a/api/command.go b/api/command.go
new file mode 100644
index 000000000..9efc79b49
--- /dev/null
+++ b/api/command.go
@@ -0,0 +1,470 @@
+// 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"
+ "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")
+ hub.Start()
+}
+
+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
+ }
+
+ 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
+ }
+ }
+
+ for _, v := range commands {
+ 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, "/command")
+
+ 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
+}