summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarlos Tadeu Panato Junior <ctadeu@gmail.com>2017-11-21 00:57:35 +0100
committerChristopher Speller <crspeller@gmail.com>2017-11-20 15:57:35 -0800
commitfdba2d50fd431796e49cef00484de410b7a7a350 (patch)
treef56c63e6b5f4c194c8390d91e1425e7c78106cd3
parente2b165cf3ea241dd430cca8145a2dc459110666e (diff)
downloadchat-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.go65
-rw-r--r--app/webhook.go13
-rw-r--r--app/webhook_test.go4
-rw-r--r--model/outgoing_webhook.go13
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 {