11package webhook
22
33import (
4+ "bytes"
45 "errors"
6+ "regexp"
57
68 "github.com/requilence/integram"
79)
810
911var m = integram.HTMLRichText {}
12+ var markdownRichText = integram.MarkdownRichText {}
1013
1114type Config struct {
1215 integram.BotConfig
@@ -17,16 +20,17 @@ type webhook struct {
1720 Mrkdwn bool
1821 Channel string
1922 Attachments []struct {
20- Pretext string `json:"pretext"`
21- Fallback string `json:"fallback"`
22- AuthorName string `json:"author_name"`
23- AuthorLink string `json:"author_link"`
24- Title string `json:"title"`
25- TitleLink string `json:"title_link"`
26- Text string `json:"text"`
27- ImageURL string `json:"image_url"`
28- ThumbURL string `json:"thumb_url"`
29- Ts int `json:"ts"`
23+ Pretext string `json:"pretext"`
24+ Fallback string `json:"fallback"`
25+ AuthorName string `json:"author_name"`
26+ AuthorLink string `json:"author_link"`
27+ Title string `json:"title"`
28+ TitleLink string `json:"title_link"`
29+ Text string `json:"text"`
30+ MrkdwnIn []string `json:"mrkdwn_in"`
31+ ImageURL string `json:"image_url"`
32+ ThumbURL string `json:"thumb_url"`
33+ Ts int `json:"ts"`
3034 } `json:"attachments"`
3135}
3236
@@ -60,6 +64,62 @@ func update(c *integram.Context) error {
6064 return nil
6165}
6266
67+ func convertLinks (text string , regex * regexp.Regexp , encodeEntities func (string ) string , linkFormat func (string , string ) string ) string {
68+ if encodeEntities == nil {
69+ encodeEntities = func (text string ) string {
70+ return text
71+ }
72+ }
73+ submatches := regex .FindAllStringSubmatchIndex (text , - 1 )
74+ if submatches == nil {
75+ return encodeEntities (text )
76+ }
77+
78+ convertedBuffer := new (bytes.Buffer )
79+ convertedBuffer .Grow (len (text ))
80+ currentPosition := 0
81+ for _ , submatch := range submatches {
82+ if submatch [0 ] > 0 {
83+ convertedBuffer .WriteString (encodeEntities (text [currentPosition :submatch [0 ]]))
84+ }
85+ if submatch [2 ] < 0 {
86+ // Code block, copy as-is
87+ convertedBuffer .WriteString (encodeEntities (text [submatch [0 ]:submatch [1 ]]))
88+ } else {
89+ // URL link, convert
90+ url := text [submatch [2 ]:submatch [3 ]]
91+ displayText := url
92+ if submatch [4 ] > 0 && submatch [4 ] != submatch [5 ] {
93+ displayText = text [submatch [4 ] + 1 :submatch [5 ]]
94+ }
95+ convertedBuffer .WriteString (linkFormat (displayText , url ))
96+ }
97+ currentPosition = submatch [1 ]
98+ }
99+ if currentPosition < len (text ) {
100+ convertedBuffer .WriteString (encodeEntities (text [currentPosition :]))
101+ }
102+ return convertedBuffer .String ()
103+ }
104+
105+ func convertLinksToMarkdown (text string ) string {
106+ // Escape URL links if outside code blocks.
107+ // Message format is documented at https://api.slack.com/docs/message-formatting)
108+ // References to a Slack channel (@), user (#) or variable (!) are kept as-is
109+ linkOrCodeBlockRegexp := regexp .MustCompile ("```.+```|`[^`\n ]+`|<([^@#! \n ][^|> \n ]*)(|[^>\n ]+)?>" )
110+ return convertLinks (text , linkOrCodeBlockRegexp , nil , markdownRichText .URL );
111+ }
112+
113+ func convertLinksToHtml (text string ) string {
114+ linkOrCodeBlockRegexp := regexp .MustCompile ("<code>.*</code>|<pre>.*</pre>|<([^@#! \n ][^|> \n ]*)(|[^>\n ]+)?>" )
115+ return convertLinks (text , linkOrCodeBlockRegexp , nil , m .URL );
116+ }
117+
118+ func convertPlainWithLinksToHTML (text string ) string {
119+ linkRegexp := regexp .MustCompile ("<([^@#! \n ][^|> \n ]*)(|[^>\n ]+)?>" )
120+ return convertLinks (text , linkRegexp , m .EncodeEntities , m .URL );
121+ }
122+
63123func webhookHandler (c * integram.Context , wc * integram.WebhookContext ) (err error ) {
64124
65125 wh := webhook {Mrkdwn : true }
@@ -81,6 +141,7 @@ func webhookHandler(c *integram.Context, wc *integram.WebhookContext) (err error
81141 }
82142
83143 haveAttachmentWithText := false
144+ haveMrkdwnAttachment := false
84145 for i , attachment := range wh .Attachments {
85146 if i > 0 {
86147 text += "\n "
@@ -99,19 +160,32 @@ func webhookHandler(c *integram.Context, wc *integram.WebhookContext) (err error
99160 }
100161
101162 haveAttachmentWithText = true
163+ for _ , field := range attachment .MrkdwnIn {
164+ if field == "pretext" {
165+ haveMrkdwnAttachment = true
166+ }
167+ }
102168
103169 text += attachment .Pretext
104170 }
105171
106172 if haveAttachmentWithText {
107- return c .NewMessage ().SetText (text ).EnableAntiFlood ().EnableHTML ().Send ()
173+ m := c .NewMessage ().EnableAntiFlood ()
174+ if haveMrkdwnAttachment {
175+ m .SetText (convertLinksToMarkdown (text )).EnableMarkdown ()
176+ } else {
177+ m .SetText (convertLinksToHtml (text )).EnableHTML ()
178+ }
179+ return m .Send ()
108180 }
109181 }
110182
111183 if wh .Text != "" {
112- m := c .NewMessage ().SetText ( wh . Text + " " + wh . Channel ). EnableAntiFlood ()
184+ m := c .NewMessage ().EnableAntiFlood ()
113185 if wh .Mrkdwn {
114- m .EnableMarkdown ()
186+ m .SetText (convertLinksToMarkdown (wh .Text + " " + wh .Channel )).EnableMarkdown ()
187+ } else {
188+ m .SetText (convertPlainWithLinksToHTML (wh .Text + " " + wh .Channel )).EnableHTML ()
115189 }
116190 return m .Send ()
117191 }
0 commit comments