diff options
Diffstat (limited to 'api/command.go')
-rw-r--r-- | api/command.go | 801 |
1 files changed, 277 insertions, 524 deletions
diff --git a/api/command.go b/api/command.go index ab63a15a7..985735fe2 100644 --- a/api/command.go +++ b/api/command.go @@ -4,12 +4,10 @@ package api import ( - "io" + "io/ioutil" "net/http" - "path" - "strconv" + "net/url" "strings" - "time" l4g "github.com/alecthomas/log4go" "github.com/gorilla/mux" @@ -17,630 +15,385 @@ import ( "github.com/mattermost/platform/utils" ) -type commandHandler func(c *Context, command *model.Command) bool - -var ( - cmds = map[string]string{ - "logoutCommand": "/logout", - "joinCommand": "/join", - "loadTestCommand": "/loadtest", - "echoCommand": "/echo", - "shrugCommand": "/shrug", - "meCommand": "/me", - } - commands = []commandHandler{ - logoutCommand, - joinCommand, - loadTestCommand, - echoCommand, - shrugCommand, - meCommand, - } - commandNotImplementedErr = model.NewLocAppError("checkCommand", "api.command.no_implemented.app_error", nil, "") -) -var echoSem chan bool - -func InitCommand(r *mux.Router) { - l4g.Debug(utils.T("api.command.init.debug")) - r.Handle("/command", ApiUserRequired(command)).Methods("POST") +type CommandProvider interface { + GetCommand() *model.Command + DoCommand(c *Context, channelId string, message string) *model.CommandResponse } -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), - } +var commandProviders = make(map[string]CommandProvider) - checkCommand(c, command) - if c.Err != nil { - if c.Err != commandNotImplementedErr { - return - } else { - c.Err = nil - command.Response = model.RESP_NOT_IMPLEMENTED - w.Write([]byte(command.ToJson())) - return - } - } else { - w.Write([]byte(command.ToJson())) - } +func RegisterCommandProvider(newProvider CommandProvider) { + commandProviders[newProvider.GetCommand().Trigger] = newProvider } -func checkCommand(c *Context, command *model.Command) bool { - - if len(command.Command) == 0 || strings.Index(command.Command, "/") != 0 { - c.Err = model.NewLocAppError("checkCommand", "api.command.check_command.start.app_error", nil, "") - return false +func GetCommandProvidersProvider(name string) CommandProvider { + provider, ok := commandProviders[name] + if ok { + return provider } - if len(command.ChannelId) > 0 { - cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, command.ChannelId, c.Session.UserId) + return nil +} - if !c.HasPermissionsToChannel(cchan, "checkCommand") { - return true - } - } +func InitCommand(r *mux.Router) { + l4g.Debug(utils.T("api.command.init.debug")) - if !command.Suggest { - implemented := false - for _, cmd := range cmds { - bounds := len(cmd) - if len(command.Command) < bounds { - continue - } - if command.Command[:bounds] == cmd { - implemented = true - } - } - if !implemented { - c.Err = commandNotImplementedErr - return false - } - } + sr := r.PathPrefix("/commands").Subrouter() - for _, v := range commands { + sr.Handle("/execute", ApiUserRequired(executeCommand)).Methods("POST") + sr.Handle("/list", ApiUserRequired(listCommands)).Methods("GET") - if v(c, command) || c.Err != nil { - return true - } - } + sr.Handle("/create", ApiUserRequired(createCommand)).Methods("POST") + sr.Handle("/list_team_commands", ApiUserRequired(listTeamCommands)).Methods("GET") + sr.Handle("/regen_token", ApiUserRequired(regenCommandToken)).Methods("POST") + sr.Handle("/delete", ApiUserRequired(deleteCommand)).Methods("POST") - return false + sr.Handle("/test", ApiAppHandler(testCommand)).Methods("POST") + sr.Handle("/test", ApiAppHandler(testCommand)).Methods("GET") } -func logoutCommand(c *Context, command *model.Command) bool { - - cmd := cmds["logoutCommand"] - - if strings.Index(command.Command, cmd) == 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: c.T("api.command.logout_command.description")}) - - if !command.Suggest { - command.GotoLocation = "/logout" - command.Response = model.RESP_EXECUTED - return true +func listCommands(c *Context, w http.ResponseWriter, r *http.Request) { + commands := make([]*model.Command, 0, 32) + seen := make(map[string]bool) + for _, value := range commandProviders { + cpy := *value.GetCommand() + if cpy.AutoComplete && !seen[cpy.Id] { + cpy.Sanatize() + seen[cpy.Trigger] = true + commands = append(commands, &cpy) } - - } else if strings.Index(cmd, command.Command) == 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: c.T("api.command.logout_command.description")}) } - return false -} - -func echoCommand(c *Context, command *model.Command) bool { - cmd := cmds["echoCommand"] - maxThreads := 100 - - if !command.Suggest && strings.Index(command.Command, cmd) == 0 { - parameters := strings.SplitN(command.Command, " ", 2) - if len(parameters) != 2 || len(parameters[1]) == 0 { - return false - } - 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:], " ") - - if checkDelay, err := strconv.Atoi(delayStr); err == nil { - delay = checkDelay - message = message[:delayIdx] + if result := <-Srv.Store.Command().GetByTeam(c.Session.TeamId); result.Err != nil { + c.Err = result.Err + return + } else { + teamCmds := result.Data.([]*model.Command) + for _, cmd := range teamCmds { + if cmd.AutoComplete && !seen[cmd.Id] { + cmd.Sanatize() + seen[cmd.Trigger] = true + commands = append(commands, cmd) } } - - if delay > 10000 { - c.Err = model.NewLocAppError("echoCommand", "api.command.echo_command.under.app_error", nil, "") - 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.NewLocAppError("echoCommand", "api.command.echo_command.high_volume.app_error", nil, "") - 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, true); err != nil { - l4g.Error(utils.T("api.command.echo_command.create.error"), err) - } - }() - - command.Response = model.RESP_EXECUTED - return true - - } else if strings.Index(cmd, command.Command) == 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: c.T("api.command.echo_command.description")}) } - return false + w.Write([]byte(model.CommandListToJson(commands))) } -func meCommand(c *Context, command *model.Command) bool { - cmd := cmds["meCommand"] +func executeCommand(c *Context, w http.ResponseWriter, r *http.Request) { + props := model.MapFromJson(r.Body) + command := strings.TrimSpace(props["command"]) + channelId := strings.TrimSpace(props["channelId"]) - if !command.Suggest && strings.Index(command.Command, cmd) == 0 { - message := "" + if len(command) <= 1 || strings.Index(command, "/") != 0 { + c.Err = model.NewLocAppError("executeCommand", "api.command.check_command.start.app_error", nil, "") + return + } - parameters := strings.SplitN(command.Command, " ", 2) - if len(parameters) > 1 { - message += "*" + parameters[1] + "*" - } + if len(channelId) > 0 { + cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId) - post := &model.Post{} - post.Message = message - post.ChannelId = command.ChannelId - if _, err := CreatePost(c, post, false); err != nil { - l4g.Error(utils.T("api.command.me_command.create.error"), err) - return false + if !c.HasPermissionsToChannel(cchan, "checkCommand") { + return } - command.Response = model.RESP_EXECUTED - return true - - } else if strings.Index(cmd, command.Command) == 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: c.T("api.command.me_command.description")}) } - return false -} - -func shrugCommand(c *Context, command *model.Command) bool { - cmd := cmds["shrugCommand"] + parts := strings.Split(command, " ") + trigger := parts[0][1:] + message := strings.Join(parts[1:], " ") + provider := GetCommandProvidersProvider(trigger) - if !command.Suggest && strings.Index(command.Command, cmd) == 0 { - message := `¯\\\_(ツ)_/¯` + if provider != nil { - parameters := strings.SplitN(command.Command, " ", 2) - if len(parameters) > 1 { - message += " " + parameters[1] - } + response := provider.DoCommand(c, channelId, message) + handleResponse(c, w, response, channelId) + return + } else { + chanChan := Srv.Store.Channel().Get(channelId) + teamChan := Srv.Store.Team().Get(c.Session.TeamId) + userChan := Srv.Store.User().Get(c.Session.UserId) - post := &model.Post{} - post.Message = message - post.ChannelId = command.ChannelId - if _, err := CreatePost(c, post, false); err != nil { - l4g.Error(utils.T("api.command.shrug_command.create.error"), err) - return false - } - command.Response = model.RESP_EXECUTED - return true + if result := <-Srv.Store.Command().GetByTeam(c.Session.TeamId); result.Err != nil { + c.Err = result.Err + return + } else { - } else if strings.Index(cmd, command.Command) == 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: c.T("api.command.shrug_command.description")}) - } + var team *model.Team + if tr := <-teamChan; tr.Err != nil { + c.Err = tr.Err + return + } else { + team = tr.Data.(*model.Team) - return false -} + } -func joinCommand(c *Context, command *model.Command) bool { + var user *model.User + if ur := <-userChan; ur.Err != nil { + c.Err = ur.Err + return + } else { + user = ur.Data.(*model.User) + } - // looks for "/join channel-name" - cmd := cmds["joinCommand"] + var channel *model.Channel + if cr := <-chanChan; cr.Err != nil { + c.Err = cr.Err + return + } else { + channel = cr.Data.(*model.Channel) + } - if strings.Index(command.Command, cmd) == 0 { + teamCmds := result.Data.([]*model.Command) + for _, cmd := range teamCmds { + if trigger == cmd.Trigger { + l4g.Debug("Executing cmd=" + trigger + " userId=" + c.Session.UserId) - parts := strings.Split(command.Command, " ") + p := url.Values{} + p.Set("token", cmd.Token) - startsWith := "" + p.Set("team_id", cmd.TeamId) + p.Set("team_domain", team.Name) - if len(parts) == 2 { - startsWith = parts[1] - } + p.Set("channel_id", channelId) + p.Set("channel_name", channel.Name) - 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) + p.Set("user_id", c.Session.UserId) + p.Set("user_name", user.Username) - for _, v := range channels.Channels { + p.Set("command", "/"+trigger) + p.Set("text", message) + p.Set("response_url", "not supported yet") - if v.Name == startsWith && !command.Suggest { - - if v.Type == model.CHANNEL_DIRECT { - return false + method := "POST" + if cmd.Method == model.COMMAND_METHOD_GET { + method = "GET" } - JoinChannel(c, v.Id, "") - - if c.Err != nil { - return false + client := &http.Client{} + req, _ := http.NewRequest(method, cmd.URL, strings.NewReader(p.Encode())) + req.Header.Set("Accept", "application/json") + if cmd.Method == model.COMMAND_METHOD_POST { + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") } - command.GotoLocation = c.GetTeamURL() + "/channels/" + v.Name - command.Response = model.RESP_EXECUTED - return true - } + if resp, err := client.Do(req); err != nil { + c.Err = model.NewAppError("command", "Command with a trigger of '"+trigger+"' failed", err.Error()) + } else { + if resp.StatusCode == http.StatusOK { + response := model.CommandResponseFromJson(resp.Body) + if response == nil { + c.Err = model.NewAppError("command", "Command with a trigger of '"+trigger+"' returned an empty response", "") + } else { + handleResponse(c, w, response, channelId) + } + } else { + body, _ := ioutil.ReadAll(resp.Body) + c.Err = model.NewAppError("command", "Command with a trigger of '"+trigger+"' returned response "+resp.Status, string(body)) + } + } - if len(startsWith) == 0 || strings.Index(v.Name, startsWith) == 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd + " " + v.Name, Description: c.T("api.commmand.join_command.description")}) + return } } + } - } else if strings.Index(cmd, command.Command) == 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: c.T("api.commmand.join_command.description")}) } - return false + c.Err = model.NewAppError("command", "Command with a trigger of '"+trigger+"' not found", "") } -func loadTestCommand(c *Context, command *model.Command) bool { - cmd := cmds["loadTestCommand"] - - // This command is only available when EnableTesting is true - if !utils.Cfg.ServiceSettings.EnableTesting { - 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 +func handleResponse(c *Context, w http.ResponseWriter, response *model.CommandResponse, channelId string) { + 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", "") } - if loadTestUrlCommand(c, command) { - return true + } else if response.ResponseType == model.COMMAND_RESPONSE_TYPE_EPHEMERAL { + post := &model.Post{} + post.ChannelId = channelId + post.Message = "TODO_EPHEMERAL: " + 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", "") } - } else if strings.Index(cmd, command.Command) == 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: c.T("api.command.load_test_command.description")}) } - return false + w.Write([]byte(response.ToJson())) } -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 +func createCommand(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 } - return utils.Range{begin, end}, true -} -func contains(items []string, token string) bool { - for _, elem := range items { - if elem == token { - return true + 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 } } - return false -} -func loadTestSetupCommand(c *Context, command *model.Command) bool { - cmd := cmds["loadTestCommand"] + " setup" + c.LogAudit("attempt") - 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") + cmd := model.CommandFromJson(r.Body) - numArgs := 0 - if doTeams { - numArgs++ - } - if doFuzz { - numArgs++ - } + if cmd == nil { + c.SetInvalidParam("createCommand", "command") + return + } - 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.GetSiteURL()) + cmd.CreatorId = c.Session.UserId + cmd.TeamId = c.Session.TeamId - if doTeams { - if err := CreateBasicUser(client); err != nil { - l4g.Error(utils.T("api.command.load_test_setup_command.create.error")) - return true - } - client.LoginByEmail(BTEST_TEAM_NAME, BTEST_USER_EMAIL, BTEST_USER_PASSWORD) - environment, err := CreateTestEnvironmentWithTeams( - client, - utils.Range{numTeams, numTeams}, - utils.Range{numChannels, numChannels}, - utils.Range{numUsers, numUsers}, - utils.Range{numPosts, numPosts}, - doFuzz) - if err != true { - l4g.Error(utils.T("api.command.load_test_setup_command.create.error")) - return true - } else { - l4g.Info("Testing environment created") - for i := 0; i < len(environment.Teams); i++ { - l4g.Info(utils.T("api.command.load_test_setup_command.created.info"), environment.Teams[i].Name) - l4g.Info(utils.T("api.command.load_test_setup_command.login.info"), environment.Environments[i].Users[0].Email, USER_PASSWORD) - } - } - } else { - client.MockSession(c.Session.Token) - CreateTestEnvironmentInTeam( - 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: c.T("api.command.load_test_setup_command.description")}) + 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())) } - - return false } -func loadTestUsersCommand(c *Context, command *model.Command) bool { - cmd1 := cmds["loadTestCommand"] + " users" - cmd2 := cmds["loadTestCommand"] + " users fuzz" +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 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} + 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 } - client := model.NewClient(c.GetSiteURL()) - 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: c.T("api.command.load_test_users_command.users.description")}) - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: c.T("api.command.load_test_users_command.fuzz.description")}) - } else if strings.Index(cmd2, command.Command) == 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: c.T("api.command.load_test_users_command.fuzz.description")}) } - return false + 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 loadTestChannelsCommand(c *Context, command *model.Command) bool { - cmd1 := cmds["loadTestCommand"] + " channels" - cmd2 := cmds["loadTestCommand"] + " channels fuzz" +func regenCommandToken(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 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} + 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 } - client := model.NewClient(c.GetSiteURL()) - client.MockSession(c.Session.Token) - 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: c.T("api.command.load_test_channels_command.channel.description")}) - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: c.T("api.command.load_test_channels_command.fuzz.description")}) - } else if strings.Index(cmd2, command.Command) == 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: c.T("api.command.load_test_channels_command.fuzz.description")}) } - return false -} + c.LogAudit("attempt") -func loadTestPostsCommand(c *Context, command *model.Command) bool { - cmd1 := cmds["loadTestCommand"] + " posts" - cmd2 := cmds["loadTestCommand"] + " posts fuzz" + props := model.MapFromJson(r.Body) - if strings.Index(command.Command, cmd1) == 0 && !command.Suggest { - cmd := cmd1 - doFuzz := false - if strings.Index(command.Command, cmd2) == 0 { - cmd = cmd2 - doFuzz = true - } + id := props["id"] + if len(id) == 0 { + c.SetInvalidParam("regenCommandToken", "id") + return + } - postsr, err := parseRange(command.Command, cmd) - if err == false { - postsr = utils.Range{20, 30} - } + var cmd *model.Command + if result := <-Srv.Store.Command().Get(id); result.Err != nil { + c.Err = result.Err + return + } else { + cmd = result.Data.(*model.Command) - 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} - } + if c.Session.TeamId != cmd.TeamId && c.Session.UserId != cmd.CreatorId && !c.IsTeamAdmin() { + c.LogAudit("fail - inappropriate permissions") + c.Err = model.NewAppError("regenToken", "Inappropriate permissions to regenerate command token", "user_id="+c.Session.UserId) + return } + } - 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++ - } - } + cmd.Token = model.NewId() - client := model.NewClient(c.GetSiteURL()) - client.MockSession(c.Session.Token) - 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: c.T("api.command.load_test_posts_command.posts.description")}) - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: c.T("api.command.load_test_posts_command.fuzz.description")}) - } else if strings.Index(cmd2, command.Command) == 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd2, Description: c.T("api.command.load_test_posts_command.fuzz.description")}) + if result := <-Srv.Store.Command().Update(cmd); result.Err != nil { + c.Err = result.Err + return + } else { + w.Write([]byte(result.Data.(*model.Command).ToJson())) } - - return false } -func loadTestUrlCommand(c *Context, command *model.Command) bool { - cmd := cmds["loadTestCommand"] + " url" - - if strings.Index(command.Command, cmd) == 0 && !command.Suggest { - url := "" +func deleteCommand(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 + } - parameters := strings.SplitN(command.Command, " ", 3) - if len(parameters) != 3 { - c.Err = model.NewLocAppError("loadTestUrlCommand", "api.command.load_test_url_command.url.app_error", nil, "") - return true - } else { - url = parameters[2] + 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 } + } - // provide a shortcut to easily access tests stored in doc/developer/tests - if !strings.HasPrefix(url, "http") { - url = "https://raw.githubusercontent.com/mattermost/platform/master/doc/developer/tests/" + url - - if path.Ext(url) == "" { - url += ".md" - } - } + c.LogAudit("attempt") - var contents io.ReadCloser - if r, err := http.Get(url); err != nil { - c.Err = model.NewLocAppError("loadTestUrlCommand", "api.command.load_test_url_command.file.app_error", nil, err.Error()) - return false - } else if r.StatusCode > 400 { - c.Err = model.NewLocAppError("loadTestUrlCommand", "api.command.load_test_url_command.file.app_error", nil, r.Status) - return false - } else { - contents = r.Body - } + props := model.MapFromJson(r.Body) - bytes := make([]byte, 4000) + id := props["id"] + if len(id) == 0 { + c.SetInvalidParam("deleteCommand", "id") + return + } - // break contents into 4000 byte posts - for { - length, err := contents.Read(bytes) - if err != nil && err != io.EOF { - c.Err = model.NewLocAppError("loadTestUrlCommand", "api.command.load_test_url_command.reading.app_error", nil, err.Error()) - return false - } + if result := <-Srv.Store.Command().Get(id); result.Err != nil { + c.Err = result.Err + return + } else { + if c.Session.TeamId != result.Data.(*model.Command).TeamId && c.Session.UserId != result.Data.(*model.Command).CreatorId && !c.IsTeamAdmin() { + c.LogAudit("fail - inappropriate permissions") + c.Err = model.NewAppError("deleteCommand", "Inappropriate permissions to delete command", "user_id="+c.Session.UserId) + return + } + } - if length == 0 { - break - } + if err := (<-Srv.Store.Command().Delete(id, model.GetMillis())).Err; err != nil { + c.Err = err + return + } - post := &model.Post{} - post.Message = string(bytes[:length]) - post.ChannelId = command.ChannelId + c.LogAudit("success") + w.Write([]byte(model.MapToJson(props))) +} - if _, err := CreatePost(c, post, false); err != nil { - l4g.Error(utils.T("api.command.load_test_url_command.create.error"), err) - return false - } - } +func testCommand(c *Context, w http.ResponseWriter, r *http.Request) { + r.ParseForm() - command.Response = model.RESP_EXECUTED + msg := "" + if r.Method == "POST" { + msg = msg + "\ntoken=" + r.FormValue("token") + msg = msg + "\nteam_domain=" + r.FormValue("team_domain") + } else { + body, _ := ioutil.ReadAll(r.Body) + msg = string(body) + } - return true - } else if strings.Index(cmd, command.Command) == 0 && strings.Index(command.Command, "/loadtest posts") != 0 { - command.AddSuggestion(&model.SuggestCommand{Suggestion: cmd, Description: c.T("api.command.load_test_url_command.description")}) + rc := &model.CommandResponse{ + Text: "test command response " + msg, + ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL, } - return false + w.Write([]byte(rc.ToJson())) } |