github.com/qichengzx/mattermost-server@v4.5.1-0.20180604164826-2c75247c97d0+incompatible/api4/command.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package api4 5 6 import ( 7 "io/ioutil" 8 "net/http" 9 "strconv" 10 "strings" 11 12 "github.com/mattermost/mattermost-server/model" 13 ) 14 15 func (api *API) InitCommand() { 16 api.BaseRoutes.Commands.Handle("", api.ApiSessionRequired(createCommand)).Methods("POST") 17 api.BaseRoutes.Commands.Handle("", api.ApiSessionRequired(listCommands)).Methods("GET") 18 api.BaseRoutes.Commands.Handle("/execute", api.ApiSessionRequired(executeCommand)).Methods("POST") 19 20 api.BaseRoutes.Command.Handle("", api.ApiSessionRequired(updateCommand)).Methods("PUT") 21 api.BaseRoutes.Command.Handle("", api.ApiSessionRequired(deleteCommand)).Methods("DELETE") 22 23 api.BaseRoutes.Team.Handle("/commands/autocomplete", api.ApiSessionRequired(listAutocompleteCommands)).Methods("GET") 24 api.BaseRoutes.Command.Handle("/regen_token", api.ApiSessionRequired(regenCommandToken)).Methods("PUT") 25 26 api.BaseRoutes.Teams.Handle("/command_test", api.ApiHandler(testCommand)).Methods("POST") 27 api.BaseRoutes.Teams.Handle("/command_test", api.ApiHandler(testCommand)).Methods("GET") 28 } 29 30 func createCommand(c *Context, w http.ResponseWriter, r *http.Request) { 31 cmd := model.CommandFromJson(r.Body) 32 if cmd == nil { 33 c.SetInvalidParam("command") 34 return 35 } 36 37 c.LogAudit("attempt") 38 39 if !c.App.SessionHasPermissionToTeam(c.Session, cmd.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) { 40 c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS) 41 return 42 } 43 44 cmd.CreatorId = c.Session.UserId 45 46 rcmd, err := c.App.CreateCommand(cmd) 47 if err != nil { 48 c.Err = err 49 return 50 } 51 52 c.LogAudit("success") 53 w.WriteHeader(http.StatusCreated) 54 w.Write([]byte(rcmd.ToJson())) 55 } 56 57 func updateCommand(c *Context, w http.ResponseWriter, r *http.Request) { 58 c.RequireCommandId() 59 if c.Err != nil { 60 return 61 } 62 63 cmd := model.CommandFromJson(r.Body) 64 if cmd == nil || cmd.Id != c.Params.CommandId { 65 c.SetInvalidParam("command") 66 return 67 } 68 69 c.LogAudit("attempt") 70 71 oldCmd, err := c.App.GetCommand(c.Params.CommandId) 72 if err != nil { 73 c.Err = err 74 return 75 } 76 77 if cmd.TeamId != oldCmd.TeamId { 78 c.Err = model.NewAppError("updateCommand", "api.command.team_mismatch.app_error", nil, "user_id="+c.Session.UserId, http.StatusBadRequest) 79 return 80 } 81 82 if !c.App.SessionHasPermissionToTeam(c.Session, oldCmd.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) { 83 c.LogAudit("fail - inappropriate permissions") 84 c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS) 85 return 86 } 87 88 if c.Session.UserId != oldCmd.CreatorId && !c.App.SessionHasPermissionToTeam(c.Session, oldCmd.TeamId, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) { 89 c.LogAudit("fail - inappropriate permissions") 90 c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) 91 return 92 } 93 94 rcmd, err := c.App.UpdateCommand(oldCmd, cmd) 95 if err != nil { 96 c.Err = err 97 return 98 } 99 100 c.LogAudit("success") 101 102 w.Write([]byte(rcmd.ToJson())) 103 } 104 105 func deleteCommand(c *Context, w http.ResponseWriter, r *http.Request) { 106 c.RequireCommandId() 107 if c.Err != nil { 108 return 109 } 110 111 c.LogAudit("attempt") 112 113 cmd, err := c.App.GetCommand(c.Params.CommandId) 114 if err != nil { 115 c.Err = err 116 return 117 } 118 119 if !c.App.SessionHasPermissionToTeam(c.Session, cmd.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) { 120 c.LogAudit("fail - inappropriate permissions") 121 c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS) 122 return 123 } 124 125 if c.Session.UserId != cmd.CreatorId && !c.App.SessionHasPermissionToTeam(c.Session, cmd.TeamId, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) { 126 c.LogAudit("fail - inappropriate permissions") 127 c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) 128 return 129 } 130 131 err = c.App.DeleteCommand(cmd.Id) 132 if err != nil { 133 c.Err = err 134 return 135 } 136 137 c.LogAudit("success") 138 139 ReturnStatusOK(w) 140 } 141 142 func listCommands(c *Context, w http.ResponseWriter, r *http.Request) { 143 customOnly, failConv := strconv.ParseBool(r.URL.Query().Get("custom_only")) 144 if failConv != nil { 145 customOnly = false 146 } 147 148 teamId := r.URL.Query().Get("team_id") 149 150 if len(teamId) == 0 { 151 c.SetInvalidParam("team_id") 152 return 153 } 154 155 var commands []*model.Command 156 var err *model.AppError 157 if customOnly { 158 if !c.App.SessionHasPermissionToTeam(c.Session, teamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) { 159 c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS) 160 return 161 } 162 commands, err = c.App.ListTeamCommands(teamId) 163 if err != nil { 164 c.Err = err 165 return 166 } 167 } else { 168 //User with no permission should see only system commands 169 if !c.App.SessionHasPermissionToTeam(c.Session, teamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) { 170 commands, err = c.App.ListAutocompleteCommands(teamId, c.T) 171 if err != nil { 172 c.Err = err 173 return 174 } 175 } else { 176 commands, err = c.App.ListAllCommands(teamId, c.T) 177 if err != nil { 178 c.Err = err 179 return 180 } 181 } 182 } 183 184 w.Write([]byte(model.CommandListToJson(commands))) 185 } 186 187 func executeCommand(c *Context, w http.ResponseWriter, r *http.Request) { 188 commandArgs := model.CommandArgsFromJson(r.Body) 189 if commandArgs == nil { 190 c.SetInvalidParam("command_args") 191 return 192 } 193 194 if len(commandArgs.Command) <= 1 || strings.Index(commandArgs.Command, "/") != 0 || len(commandArgs.ChannelId) != 26 { 195 c.Err = model.NewAppError("executeCommand", "api.command.execute_command.start.app_error", nil, "", http.StatusBadRequest) 196 return 197 } 198 199 // checks that user is a member of the specified channel, and that they have permission to use slash commands in it 200 if !c.App.SessionHasPermissionToChannel(c.Session, commandArgs.ChannelId, model.PERMISSION_USE_SLASH_COMMANDS) { 201 c.SetPermissionError(model.PERMISSION_USE_SLASH_COMMANDS) 202 return 203 } 204 205 channel, err := c.App.GetChannel(commandArgs.ChannelId) 206 if err != nil { 207 c.Err = err 208 return 209 } else if channel.Type != model.CHANNEL_DIRECT && channel.Type != model.CHANNEL_GROUP { 210 // if this isn't a DM or GM, the team id is implicitly taken from the channel so that slash commands created on 211 // some other team can't be run against this one 212 commandArgs.TeamId = channel.TeamId 213 } else { 214 // if the slash command was used in a DM or GM, ensure that the user is a member of the specified team, so that 215 // they can't just execute slash commands against arbitrary teams 216 if c.Session.GetTeamByTeamId(commandArgs.TeamId) == nil { 217 if !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_USE_SLASH_COMMANDS) { 218 c.SetPermissionError(model.PERMISSION_USE_SLASH_COMMANDS) 219 return 220 } 221 } 222 } 223 224 commandArgs.UserId = c.Session.UserId 225 commandArgs.T = c.T 226 commandArgs.Session = c.Session 227 commandArgs.SiteURL = c.GetSiteURLHeader() 228 229 response, err := c.App.ExecuteCommand(commandArgs) 230 if err != nil { 231 c.Err = err 232 return 233 } 234 235 w.Write([]byte(response.ToJson())) 236 } 237 238 func listAutocompleteCommands(c *Context, w http.ResponseWriter, r *http.Request) { 239 c.RequireTeamId() 240 if c.Err != nil { 241 return 242 } 243 244 if !c.App.SessionHasPermissionToTeam(c.Session, c.Params.TeamId, model.PERMISSION_VIEW_TEAM) { 245 c.SetPermissionError(model.PERMISSION_VIEW_TEAM) 246 return 247 } 248 249 commands, err := c.App.ListAutocompleteCommands(c.Params.TeamId, c.T) 250 if err != nil { 251 c.Err = err 252 return 253 } 254 255 w.Write([]byte(model.CommandListToJson(commands))) 256 } 257 258 func regenCommandToken(c *Context, w http.ResponseWriter, r *http.Request) { 259 c.RequireCommandId() 260 if c.Err != nil { 261 return 262 } 263 264 c.LogAudit("attempt") 265 cmd, err := c.App.GetCommand(c.Params.CommandId) 266 if err != nil { 267 c.Err = err 268 return 269 } 270 271 if !c.App.SessionHasPermissionToTeam(c.Session, cmd.TeamId, model.PERMISSION_MANAGE_SLASH_COMMANDS) { 272 c.LogAudit("fail - inappropriate permissions") 273 c.SetPermissionError(model.PERMISSION_MANAGE_SLASH_COMMANDS) 274 return 275 } 276 277 if c.Session.UserId != cmd.CreatorId && !c.App.SessionHasPermissionToTeam(c.Session, cmd.TeamId, model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) { 278 c.LogAudit("fail - inappropriate permissions") 279 c.SetPermissionError(model.PERMISSION_MANAGE_OTHERS_SLASH_COMMANDS) 280 return 281 } 282 283 rcmd, err := c.App.RegenCommandToken(cmd) 284 if err != nil { 285 c.Err = err 286 return 287 } 288 289 resp := make(map[string]string) 290 resp["token"] = rcmd.Token 291 292 w.Write([]byte(model.MapToJson(resp))) 293 } 294 295 func testCommand(c *Context, w http.ResponseWriter, r *http.Request) { 296 r.ParseForm() 297 298 msg := "" 299 if r.Method == "POST" { 300 msg = msg + "\ntoken=" + r.FormValue("token") 301 msg = msg + "\nteam_domain=" + r.FormValue("team_domain") 302 } else { 303 body, _ := ioutil.ReadAll(r.Body) 304 msg = string(body) 305 } 306 307 rc := &model.CommandResponse{ 308 Text: "test command response " + msg, 309 ResponseType: model.COMMAND_RESPONSE_TYPE_IN_CHANNEL, 310 Type: "custom_test", 311 Props: map[string]interface{}{"someprop": "somevalue"}, 312 } 313 314 w.Write([]byte(rc.ToJson())) 315 }