1
1
package webhook
2
2
3
3
import (
4
+ "bytes"
4
5
"errors"
6
+ "regexp"
5
7
6
8
"github.com/requilence/integram"
7
9
)
8
10
9
11
var m = integram.HTMLRichText {}
12
+ var markdownRichText = integram.MarkdownRichText {}
10
13
11
14
type Config struct {
12
15
integram.BotConfig
@@ -17,16 +20,17 @@ type webhook struct {
17
20
Mrkdwn bool
18
21
Channel string
19
22
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"`
30
34
} `json:"attachments"`
31
35
}
32
36
@@ -60,6 +64,62 @@ func update(c *integram.Context) error {
60
64
return nil
61
65
}
62
66
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
+
63
123
func webhookHandler (c * integram.Context , wc * integram.WebhookContext ) (err error ) {
64
124
65
125
wh := webhook {Mrkdwn : true }
@@ -81,6 +141,7 @@ func webhookHandler(c *integram.Context, wc *integram.WebhookContext) (err error
81
141
}
82
142
83
143
haveAttachmentWithText := false
144
+ haveMrkdwnAttachment := false
84
145
for i , attachment := range wh .Attachments {
85
146
if i > 0 {
86
147
text += "\n "
@@ -99,19 +160,32 @@ func webhookHandler(c *integram.Context, wc *integram.WebhookContext) (err error
99
160
}
100
161
101
162
haveAttachmentWithText = true
163
+ for _ , field := range attachment .MrkdwnIn {
164
+ if field == "pretext" {
165
+ haveMrkdwnAttachment = true
166
+ }
167
+ }
102
168
103
169
text += attachment .Pretext
104
170
}
105
171
106
172
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 ()
108
180
}
109
181
}
110
182
111
183
if wh .Text != "" {
112
- m := c .NewMessage ().SetText ( wh . Text + " " + wh . Channel ). EnableAntiFlood ()
184
+ m := c .NewMessage ().EnableAntiFlood ()
113
185
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 ()
115
189
}
116
190
return m .Send ()
117
191
}
0 commit comments