diff options
author | Carlos Tadeu Panato Junior <ctadeu@gmail.com> | 2017-11-21 00:57:35 +0100 |
---|---|---|
committer | Christopher Speller <crspeller@gmail.com> | 2017-11-20 15:57:35 -0800 |
commit | fdba2d50fd431796e49cef00484de410b7a7a350 (patch) | |
tree | f56c63e6b5f4c194c8390d91e1425e7c78106cd3 | |
parent | e2b165cf3ea241dd430cca8145a2dc459110666e (diff) | |
download | chat-fdba2d50fd431796e49cef00484de410b7a7a350.tar.gz chat-fdba2d50fd431796e49cef00484de410b7a7a350.tar.bz2 chat-fdba2d50fd431796e49cef00484de410b7a7a350.zip |
[PLT-840] Add option to outgoing webhooks to reply to the posted message as a comment (#7807)
-rw-r--r-- | api4/post_test.go | 65 | ||||
-rw-r--r-- | app/webhook.go | 13 | ||||
-rw-r--r-- | app/webhook_test.go | 4 | ||||
-rw-r--r-- | model/outgoing_webhook.go | 13 |
4 files changed, 72 insertions, 23 deletions
diff --git a/api4/post_test.go b/api4/post_test.go index 15553137a..c37b61ecd 100644 --- a/api4/post_test.go +++ b/api4/post_test.go @@ -5,6 +5,7 @@ package api4 import ( "encoding/json" + "fmt" "net/http" "net/http/httptest" "net/url" @@ -121,6 +122,7 @@ func testCreatePostWithOutgoingHook( hookContentType, expectedContentType, message, triggerWord string, fileIds []string, triggerWhen int, + commentPostType bool, ) { th := Setup().InitBasic().InitSystemAdmin() defer th.TearDown() @@ -199,6 +201,7 @@ func testCreatePostWithOutgoingHook( } expectedFormValues, _ := url.ParseQuery(expectedPayload.ToFormValues()) + if !reflect.DeepEqual(expectedFormValues, r.Form) { t.Logf("Form values are: %q\n, should be: %q\n", r.Form, expectedFormValues) success <- false @@ -206,6 +209,20 @@ func testCreatePostWithOutgoingHook( } } + respPostType := "" //if is empty or post will do a normal post. + if commentPostType { + respPostType = model.OUTGOING_HOOK_RESPONSE_TYPE_COMMENT + } + + outGoingHookResponse := &model.OutgoingWebhookResponse{ + Text: model.NewString("some test text"), + Username: "TestCommandServer", + IconURL: "https://www.mattermost.org/wp-content/uploads/2016/04/icon.png", + Type: "custom_as", + ResponseType: respPostType, + } + + fmt.Fprintf(w, outGoingHookResponse.ToJson()) success <- true })) defer ts.Close() @@ -250,29 +267,53 @@ func testCreatePostWithOutgoingHook( case <-time.After(time.Second): t.Fatal("Timeout, test server did not send the webhook.") } + + if commentPostType { + time.Sleep(time.Millisecond * 100) + postList, resp := th.SystemAdminClient.GetPostThread(post.Id, "") + CheckNoError(t, resp) + if postList.Order[0] != post.Id { + t.Fatal("wrong order") + } + + if _, ok := postList.Posts[post.Id]; !ok { + t.Fatal("should have had post") + } + + if len(postList.Posts) != 2 { + t.Fatal("should have 2 posts") + } + + } } func TestCreatePostWithOutgoingHook_form_urlencoded(t *testing.T) { - testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH) - testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH) - testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH) - testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH) + testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false) + testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false) + testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false) + testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false) + testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, true) + testCreatePostWithOutgoingHook(t, "application/x-www-form-urlencoded", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, true) } func TestCreatePostWithOutgoingHook_json(t *testing.T) { - testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH) - testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH) - testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH) - testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH) + testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, false) + testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH, false) + testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false) + testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false) + testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerword lorem ipsum", "triggerword", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, true) + testCreatePostWithOutgoingHook(t, "application/json", "application/json", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, true) } // hooks created before we added the ContentType field should be considered as // application/x-www-form-urlencoded func TestCreatePostWithOutgoingHook_no_content_type(t *testing.T) { - testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH) - testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH) - testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH) - testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH) + testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, false) + testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_STARTS_WITH, false) + testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, false) + testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerwordaaazzz lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_STARTS_WITH, false) + testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "triggerword", []string{"file_id_1"}, app.TRIGGERWORDS_EXACT_MATCH, true) + testCreatePostWithOutgoingHook(t, "", "application/x-www-form-urlencoded", "triggerword lorem ipsum", "", []string{"file_id_1, file_id_2"}, app.TRIGGERWORDS_EXACT_MATCH, true) } func TestCreatePostPublic(t *testing.T) { diff --git a/app/webhook.go b/app/webhook.go index 5ce56aa88..41a789ead 100644 --- a/app/webhook.go +++ b/app/webhook.go @@ -110,10 +110,15 @@ func (a *App) TriggerWebhook(payload *model.OutgoingWebhookPayload, hook *model. l4g.Error(utils.T("api.post.handle_webhook_events_and_forget.event_post.error"), err.Error()) } else { defer consumeAndClose(resp) + webhookResp := model.OutgoingWebhookResponseFromJson(resp.Body) if webhookResp != nil && webhookResp.Text != nil { - if _, err := a.CreateWebhookPost(hook.CreatorId, channel, *webhookResp.Text, webhookResp.Username, webhookResp.IconURL, webhookResp.Props, webhookResp.Type); err != nil { + postRootId := "" + if webhookResp.ResponseType == model.OUTGOING_HOOK_RESPONSE_TYPE_COMMENT { + postRootId = post.Id + } + if _, err := a.CreateWebhookPost(hook.CreatorId, channel, *webhookResp.Text, webhookResp.Username, webhookResp.IconURL, webhookResp.Props, webhookResp.Type, postRootId); err != nil { l4g.Error(utils.T("api.post.handle_webhook_events_and_forget.create_post.error"), err) } } @@ -203,12 +208,12 @@ func SplitWebhookPost(post *model.Post) ([]*model.Post, *model.AppError) { return splits, nil } -func (a *App) CreateWebhookPost(userId string, channel *model.Channel, text, overrideUsername, overrideIconUrl string, props model.StringInterface, postType string) (*model.Post, *model.AppError) { +func (a *App) CreateWebhookPost(userId string, channel *model.Channel, text, overrideUsername, overrideIconUrl string, props model.StringInterface, postType string, postRootId string) (*model.Post, *model.AppError) { // parse links into Markdown format linkWithTextRegex := regexp.MustCompile(`<([^<\|]+)\|([^>]+)>`) text = linkWithTextRegex.ReplaceAllString(text, "[${2}](${1})") - post := &model.Post{UserId: userId, ChannelId: channel.Id, Message: text, Type: postType} + post := &model.Post{UserId: userId, ChannelId: channel.Id, Message: text, Type: postType, RootId: postRootId} post.AddProp("from_webhook", "true") if strings.HasPrefix(post.Type, model.POST_SYSTEM_MESSAGE_PREFIX) { @@ -600,7 +605,7 @@ func (a *App) HandleIncomingWebhook(hookId string, req *model.IncomingWebhookReq overrideUsername := req.Username overrideIconUrl := req.IconURL - _, err := a.CreateWebhookPost(hook.UserId, channel, text, overrideUsername, overrideIconUrl, req.Props, webhookType) + _, err := a.CreateWebhookPost(hook.UserId, channel, text, overrideUsername, overrideIconUrl, req.Props, webhookType, "") return err } diff --git a/app/webhook_test.go b/app/webhook_test.go index f0cc0610a..9fef6fde3 100644 --- a/app/webhook_test.go +++ b/app/webhook_test.go @@ -38,7 +38,7 @@ func TestCreateWebhookPost(t *testing.T) { Text: "text", }, }, - }, model.POST_SLACK_ATTACHMENT) + }, model.POST_SLACK_ATTACHMENT, "") if err != nil { t.Fatal(err.Error()) } @@ -49,7 +49,7 @@ func TestCreateWebhookPost(t *testing.T) { } } - _, err = th.App.CreateWebhookPost(hook.UserId, th.BasicChannel, "foo", "user", "http://iconurl", nil, model.POST_SYSTEM_GENERIC) + _, err = th.App.CreateWebhookPost(hook.UserId, th.BasicChannel, "foo", "user", "http://iconurl", nil, model.POST_SYSTEM_GENERIC, "") if err == nil { t.Fatal("should have failed - bad post type") } diff --git a/model/outgoing_webhook.go b/model/outgoing_webhook.go index 14c6f2269..477a277de 100644 --- a/model/outgoing_webhook.go +++ b/model/outgoing_webhook.go @@ -46,13 +46,16 @@ type OutgoingWebhookPayload struct { } type OutgoingWebhookResponse struct { - Text *string `json:"text"` - Username string `json:"username"` - IconURL string `json:"icon_url"` - Props StringInterface `json:"props"` - Type string `json:"type"` + Text *string `json:"text"` + Username string `json:"username"` + IconURL string `json:"icon_url"` + Props StringInterface `json:"props"` + Type string `json:"type"` + ResponseType string `json:"response_type"` } +const OUTGOING_HOOK_RESPONSE_TYPE_COMMENT = "comment" + func (o *OutgoingWebhookPayload) ToJSON() string { b, err := json.Marshal(o) if err != nil { |