@@ -4,18 +4,20 @@ import (
4
4
"context"
5
5
"errors"
6
6
"fmt"
7
+ "net/url"
7
8
"strings"
8
9
"time"
9
10
11
+ "github.com/PagerDuty/go-pagerduty"
10
12
"github.com/google/go-cmp/cmp"
11
13
"github.com/google/go-cmp/cmp/cmpopts"
12
14
"github.com/matryer/try"
13
-
14
- "github.com/PagerDuty/go-pagerduty"
15
-
16
15
"github.com/slack-go/slack"
16
+ "mvdan.cc/xurls/v2"
17
17
)
18
18
19
+ var rxRelaxed = xurls .Relaxed ()
20
+
19
21
type slackUsers []slackUser
20
22
21
23
func (users slackUsers ) findByPDUser (pdUser pagerduty.User ) * slackUser {
@@ -276,6 +278,91 @@ func (metaClient *slackMetaClient) updateTopic(ctx context.Context, channelID st
276
278
return nil
277
279
}
278
280
281
+ func escapeText (txt string ) (string , error ) {
282
+ obj := slack .NewTextBlockObject ("mrkdown" , "foobarbar" , false , false )
283
+ block := slack .NewSectionBlock (obj , nil , nil )
284
+ msg := slack .NewBlockMessage (block )
285
+ msg .
286
+
287
+ remainingTxt := escapeAmpersands (txt )
288
+
289
+ for {
290
+ idxPair := rxRelaxed .FindStringIndex (remainingTxt )
291
+ if idxPair == nil {
292
+ break
293
+ }
294
+
295
+ startIdx := idxPair [0 ]
296
+ if startIdx > 0 && startIdx != '<' && startIdx != '|' {
297
+ continue
298
+ }
299
+
300
+ rxRelaxed .ReplaceAllString ()
301
+
302
+ match := remainingTxt [startIdx :indexPair [1 ]]
303
+ parsedURL , err := url .Parse (match )
304
+ if err != nil {
305
+ return "" , fmt .Errorf ("failed to parse URL %q: %s" , match , err )
306
+ }
307
+ if parsedURL .Scheme == "" {
308
+ strings .ReplaceAll (txt , match , fmt .Sprintf ("<http://%s|%s>" , match , match ))
309
+ } else {
310
+ strings .ReplaceAll (txt , match , fmt .Sprintf ("<http://%s|%s>" , match , match ))
311
+ }
312
+ }
313
+
314
+ }
315
+
316
+ func escapeAmpersands (txt string ) string {
317
+ parts := strings .Split (txt , "&" )
318
+ if len (parts ) == 1 {
319
+ return txt
320
+ }
321
+
322
+ const ampSuffix = "amp;"
323
+
324
+ var b strings.Builder
325
+ for i , part := range parts {
326
+ b .WriteString (part )
327
+ if i == len (parts )- 1 {
328
+ break
329
+ }
330
+ b .WriteRune ('&' )
331
+ nextIdx := i + 1
332
+ if strings .HasPrefix (parts [nextIdx ], ampSuffix ) {
333
+ b .WriteString (ampSuffix )
334
+ parts [nextIdx ] = strings .TrimPrefix (parts [nextIdx ], ampSuffix )
335
+ }
336
+ }
337
+
338
+ return b .String ()
339
+ }
340
+
341
+ func isEncodedURL (txt string , pair []int ) bool {
342
+ left := pair [0 ] - 1
343
+ if left == 0 {
344
+ return false
345
+ }
346
+ right := pair [1 ] + 1
347
+ if right == len (txt )- 1 {
348
+ return false
349
+ }
350
+ return txt [left ] == '<' && txt [right ] == '>'
351
+ }
352
+
353
+ func textMatchesAt (txt string , i int , substr string ) bool {
354
+ if len (txt ) < i {
355
+ return false
356
+ }
357
+
358
+ suffix := txt [i :]
359
+ lenSubstr := len (substr )
360
+ if len (suffix ) < lenSubstr {
361
+ return false
362
+ }
363
+ return suffix [:lenSubstr ] == substr
364
+ }
365
+
279
366
func createSlackUser (apiUser slack.User ) slackUser {
280
367
return slackUser {
281
368
id : apiUser .ID ,
0 commit comments