@@ -5,6 +5,7 @@ package app
5
5
6
6
import (
7
7
"fmt"
8
+ "io"
8
9
"io/ioutil"
9
10
"net/http"
10
11
"net/url"
@@ -160,7 +161,6 @@ func (a *App) ExecuteCommand(args *model.CommandArgs) (*model.CommandResponse, *
160
161
trigger := parts [0 ][1 :]
161
162
trigger = strings .ToLower (trigger )
162
163
message := strings .Join (parts [1 :], " " )
163
- provider := GetCommandProvider (trigger )
164
164
165
165
clientTriggerId , triggerId , appErr := model .GenerateTriggerId (args .UserId , a .AsymmetricSigningKey ())
166
166
if appErr != nil {
@@ -169,24 +169,52 @@ func (a *App) ExecuteCommand(args *model.CommandArgs) (*model.CommandResponse, *
169
169
170
170
args .TriggerId = triggerId
171
171
172
- if provider != nil {
173
- if cmd := provider .GetCommand (a , args .T ); cmd != nil {
174
- response := provider .DoCommand (a , args , message )
175
- return a .HandleCommandResponse (cmd , args , response , true )
176
- }
172
+ cmd , response := a .tryExecuteBuiltInCommand (args , trigger , message )
173
+ if cmd != nil && response != nil {
174
+ return a .HandleCommandResponse (cmd , args , response , true )
177
175
}
178
176
179
- cmd , response , appErr : = a .ExecutePluginCommand (args )
177
+ cmd , response , appErr = a .tryExecutePluginCommand (args )
180
178
if appErr != nil {
181
179
return nil , appErr
182
- }
183
- if cmd != nil {
180
+ } else if cmd != nil && response != nil {
184
181
response .TriggerId = clientTriggerId
185
182
return a .HandleCommandResponse (cmd , args , response , true )
186
183
}
187
184
185
+ cmd , response , appErr = a .tryExecuteCustomCommand (args , trigger , message )
186
+ if appErr != nil {
187
+ return nil , appErr
188
+ } else if cmd != nil && response != nil {
189
+ response .TriggerId = clientTriggerId
190
+ return a .HandleCommandResponse (cmd , args , response , false )
191
+ }
192
+
193
+ return nil , model .NewAppError ("command" , "api.command.execute_command.not_found.app_error" , map [string ]interface {}{"Trigger" : trigger }, "" , http .StatusNotFound )
194
+ }
195
+
196
+ // tryExecutePluginCommand attempts to run a built in command based on the given arguments. If no such command can be
197
+ // found, returns nil for all arguments.
198
+ func (a * App ) tryExecuteBuiltInCommand (args * model.CommandArgs , trigger string , message string ) (* model.Command , * model.CommandResponse ) {
199
+ provider := GetCommandProvider (trigger )
200
+ if provider == nil {
201
+ return nil , nil
202
+ }
203
+
204
+ cmd := provider .GetCommand (a , args .T )
205
+ if cmd == nil {
206
+ return nil , nil
207
+ }
208
+
209
+ return cmd , provider .DoCommand (a , args , message )
210
+ }
211
+
212
+ // tryExecuteCustomCommand attempts to run a custom command based on the given arguments. If no such command can be
213
+ // found, returns nil for all arguments.
214
+ func (a * App ) tryExecuteCustomCommand (args * model.CommandArgs , trigger string , message string ) (* model.Command , * model.CommandResponse , * model.AppError ) {
215
+ // Handle custom commands
188
216
if ! * a .Config ().ServiceSettings .EnableCommands {
189
- return nil , model .NewAppError ("ExecuteCommand" , "api.command.disabled.app_error" , nil , "" , http .StatusNotImplemented )
217
+ return nil , nil , model .NewAppError ("ExecuteCommand" , "api.command.disabled.app_error" , nil , "" , http .StatusNotImplemented )
190
218
}
191
219
192
220
chanChan := a .Srv .Store .Channel ().Get (args .ChannelId , true )
@@ -195,98 +223,121 @@ func (a *App) ExecuteCommand(args *model.CommandArgs) (*model.CommandResponse, *
195
223
196
224
result := <- a .Srv .Store .Command ().GetByTeam (args .TeamId )
197
225
if result .Err != nil {
198
- return nil , result .Err
226
+ return nil , nil , result .Err
199
227
}
200
228
201
229
tr := <- teamChan
202
230
if tr .Err != nil {
203
- return nil , tr .Err
231
+ return nil , nil , tr .Err
204
232
}
205
233
team := tr .Data .(* model.Team )
206
234
207
235
ur := <- userChan
208
236
if ur .Err != nil {
209
- return nil , ur .Err
237
+ return nil , nil , ur .Err
210
238
}
211
239
user := ur .Data .(* model.User )
212
240
213
241
cr := <- chanChan
214
242
if cr .Err != nil {
215
- return nil , cr .Err
243
+ return nil , nil , cr .Err
216
244
}
217
245
channel := cr .Data .(* model.Channel )
218
246
247
+ var cmd * model.Command
248
+
219
249
teamCmds := result .Data .([]* model.Command )
220
- for _ , cmd := range teamCmds {
221
- if trigger == cmd .Trigger {
222
- mlog .Debug (fmt .Sprintf (utils .T ("api.command.execute_command.debug" ), trigger , args .UserId ))
250
+ for _ , teamCmd := range teamCmds {
251
+ if trigger == teamCmd .Trigger {
252
+ cmd = teamCmd
253
+ }
254
+ }
223
255
224
- p := url.Values {}
225
- p .Set ("token" , cmd .Token )
256
+ if cmd == nil {
257
+ return nil , nil , nil
258
+ }
226
259
227
- p .Set ("team_id" , cmd .TeamId )
228
- p .Set ("team_domain" , team .Name )
260
+ mlog .Debug (fmt .Sprintf (utils .T ("api.command.execute_command.debug" ), trigger , args .UserId ))
229
261
230
- p . Set ( "channel_id" , args . ChannelId )
231
- p .Set ("channel_name " , channel . Name )
262
+ p := url. Values {}
263
+ p .Set ("token " , cmd . Token )
232
264
233
- p .Set ("user_id " , args . UserId )
234
- p .Set ("user_name " , user . Username )
265
+ p .Set ("team_id " , cmd . TeamId )
266
+ p .Set ("team_domain " , team . Name )
235
267
236
- p .Set ("command " , "/" + trigger )
237
- p .Set ("text " , message )
268
+ p .Set ("channel_id " , args . ChannelId )
269
+ p .Set ("channel_name " , channel . Name )
238
270
239
- p .Set ("trigger_id" , triggerId )
271
+ p .Set ("user_id" , args .UserId )
272
+ p .Set ("user_name" , user .Username )
240
273
241
- hook , appErr := a .CreateCommandWebhook (cmd .Id , args )
242
- if appErr != nil {
243
- return nil , model .NewAppError ("command" , "api.command.execute_command.failed.app_error" , map [string ]interface {}{"Trigger" : trigger }, appErr .Error (), http .StatusInternalServerError )
244
- }
245
- p .Set ("response_url" , args .SiteURL + "/hooks/commands/" + hook .Id )
246
-
247
- var req * http.Request
248
- if cmd .Method == model .COMMAND_METHOD_GET {
249
- req , _ = http .NewRequest (http .MethodGet , cmd .URL , nil )
250
-
251
- if req .URL .RawQuery != "" {
252
- req .URL .RawQuery += "&"
253
- }
254
- req .URL .RawQuery += p .Encode ()
255
- } else {
256
- req , _ = http .NewRequest (http .MethodPost , cmd .URL , strings .NewReader (p .Encode ()))
257
- }
274
+ p .Set ("command" , "/" + trigger )
275
+ p .Set ("text" , message )
258
276
259
- req .Header .Set ("Accept" , "application/json" )
260
- req .Header .Set ("Authorization" , "Token " + cmd .Token )
261
- if cmd .Method == model .COMMAND_METHOD_POST {
262
- req .Header .Set ("Content-Type" , "application/x-www-form-urlencoded" )
263
- }
277
+ p .Set ("trigger_id" , args .TriggerId )
264
278
265
- resp , err := a .HTTPService .MakeClient (false ).Do (req )
266
- if err != nil {
267
- return nil , model .NewAppError ("command" , "api.command.execute_command.failed.app_error" , map [string ]interface {}{"Trigger" : trigger }, err .Error (), http .StatusInternalServerError )
268
- }
269
- if resp .StatusCode != http .StatusOK {
270
- defer resp .Body .Close ()
271
- body , _ := ioutil .ReadAll (resp .Body )
272
- return nil , model .NewAppError ("command" , "api.command.execute_command.failed_resp.app_error" , map [string ]interface {}{"Trigger" : trigger , "Status" : resp .Status }, string (body ), http .StatusInternalServerError )
273
- }
279
+ hook , appErr := a .CreateCommandWebhook (cmd .Id , args )
280
+ if appErr != nil {
281
+ return cmd , nil , model .NewAppError ("command" , "api.command.execute_command.failed.app_error" , map [string ]interface {}{"Trigger" : trigger }, appErr .Error (), http .StatusInternalServerError )
282
+ }
283
+ p .Set ("response_url" , args .SiteURL + "/hooks/commands/" + hook .Id )
274
284
275
- response , err := model .CommandResponseFromHTTPBody (resp .Header .Get ("Content-Type" ), resp .Body )
276
- if err != nil {
277
- return nil , model .NewAppError ("command" , "api.command.execute_command.failed.app_error" , map [string ]interface {}{"Trigger" : trigger }, err .Error (), http .StatusInternalServerError )
278
- }
279
- if response == nil {
280
- return nil , model .NewAppError ("command" , "api.command.execute_command.failed_empty.app_error" , map [string ]interface {}{"Trigger" : trigger }, "" , http .StatusInternalServerError )
281
- }
285
+ return a .doCommandRequest (cmd , p )
286
+ }
282
287
283
- response .TriggerId = clientTriggerId
288
+ func (a * App ) doCommandRequest (cmd * model.Command , p url.Values ) (* model.Command , * model.CommandResponse , * model.AppError ) {
289
+ // Prepare the request
290
+ var req * http.Request
291
+ var err error
292
+ if cmd .Method == model .COMMAND_METHOD_GET {
293
+ req , err = http .NewRequest (http .MethodGet , cmd .URL , nil )
294
+ } else {
295
+ req , err = http .NewRequest (http .MethodPost , cmd .URL , strings .NewReader (p .Encode ()))
296
+ }
297
+
298
+ if err != nil {
299
+ return cmd , nil , model .NewAppError ("command" , "api.command.execute_command.failed.app_error" , map [string ]interface {}{"Trigger" : cmd .Trigger }, err .Error (), http .StatusInternalServerError )
300
+ }
284
301
285
- return a .HandleCommandResponse (cmd , args , response , false )
302
+ if cmd .Method == model .COMMAND_METHOD_GET {
303
+ if req .URL .RawQuery != "" {
304
+ req .URL .RawQuery += "&"
286
305
}
306
+ req .URL .RawQuery += p .Encode ()
287
307
}
288
308
289
- return nil , model .NewAppError ("command" , "api.command.execute_command.not_found.app_error" , map [string ]interface {}{"Trigger" : trigger }, "" , http .StatusNotFound )
309
+ req .Header .Set ("Accept" , "application/json" )
310
+ req .Header .Set ("Authorization" , "Token " + cmd .Token )
311
+ if cmd .Method == model .COMMAND_METHOD_POST {
312
+ req .Header .Set ("Content-Type" , "application/x-www-form-urlencoded" )
313
+ }
314
+
315
+ // Send the request
316
+ resp , err := a .HTTPService .MakeClient (false ).Do (req )
317
+ if err != nil {
318
+ return cmd , nil , model .NewAppError ("command" , "api.command.execute_command.failed.app_error" , map [string ]interface {}{"Trigger" : cmd .Trigger }, err .Error (), http .StatusInternalServerError )
319
+ }
320
+
321
+ defer resp .Body .Close ()
322
+
323
+ // Handle the response
324
+ body := io .LimitReader (resp .Body , MaxIntegrationResponseSize )
325
+
326
+ if resp .StatusCode != http .StatusOK {
327
+ // Ignore the error below because the resulting string will just be the empty string if bodyBytes is nil
328
+ bodyBytes , _ := ioutil .ReadAll (body )
329
+
330
+ return cmd , nil , model .NewAppError ("command" , "api.command.execute_command.failed_resp.app_error" , map [string ]interface {}{"Trigger" : cmd .Trigger , "Status" : resp .Status }, string (bodyBytes ), http .StatusInternalServerError )
331
+ }
332
+
333
+ response , err := model .CommandResponseFromHTTPBody (resp .Header .Get ("Content-Type" ), body )
334
+ if err != nil {
335
+ return cmd , nil , model .NewAppError ("command" , "api.command.execute_command.failed.app_error" , map [string ]interface {}{"Trigger" : cmd .Trigger }, err .Error (), http .StatusInternalServerError )
336
+ } else if response == nil {
337
+ return cmd , nil , model .NewAppError ("command" , "api.command.execute_command.failed_empty.app_error" , map [string ]interface {}{"Trigger" : cmd .Trigger }, "" , http .StatusInternalServerError )
338
+ }
339
+
340
+ return cmd , response , nil
290
341
}
291
342
292
343
func (a * App ) HandleCommandResponse (command * model.Command , args * model.CommandArgs , response * model.CommandResponse , builtIn bool ) (* model.CommandResponse , * model.AppError ) {
0 commit comments