From f1a4c0738301f50b6a9e8bd635fbcc172decb199 Mon Sep 17 00:00:00 2001 From: Diep Pham Date: Thu, 2 Feb 2017 21:28:27 +0700 Subject: PLT-495 Improves slack markup conversion (#4914) * improves slack markup conversion * bold * strikethrough * blockquotes * handles blockquotes in slack_import * removes unnecessary formatting * fixes various format problems --- app/slackimport.go | 57 +++++++++++++++++++++++++-- app/slackimport_test.go | 103 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 150 insertions(+), 10 deletions(-) (limited to 'app') diff --git a/app/slackimport.go b/app/slackimport.go index 75a1606af..e54d0724b 100644 --- a/app/slackimport.go +++ b/app/slackimport.go @@ -564,12 +564,63 @@ func SlackConvertChannelMentions(channels []SlackChannel, posts map[string][]Sla } func SlackConvertPostsMarkup(posts map[string][]SlackPost) map[string][]SlackPost { - // Convert URLs in Slack's format to Markdown format. - regex := regexp.MustCompile(`<([^|<>]+)\|([^|<>]+)>`) + regexReplaceAllString := []struct { + regex *regexp.Regexp + rpl string + }{ + // URL + { + regexp.MustCompile(`<([^|<>]+)\|([^|<>]+)>`), + "[$2]($1)", + }, + // bold + { + regexp.MustCompile(`(^|[\s.;,])\*(\S[^*\n]+)\*`), + "$1**$2**", + }, + // strikethrough + { + regexp.MustCompile(`(^|[\s.;,])\~(\S[^~\n]+)\~`), + "$1~~$2~~", + }, + // single paragraph blockquote + // Slack converts > character to > + { + regexp.MustCompile(`(?sm)^>`), + ">", + }, + } + + regexReplaceAllStringFunc := []struct { + regex *regexp.Regexp + fn func(string) string + }{ + // multiple paragraphs blockquotes + { + regexp.MustCompile(`(?sm)^>>>(.+)$`), + func(src string) string { + // remove >>> prefix, might have leading \n + prefixRegexp := regexp.MustCompile(`^([\n])?>>>(.*)`) + src = prefixRegexp.ReplaceAllString(src, "$1$2") + // append > to start of line + appendRegexp := regexp.MustCompile(`(?m)^`) + return appendRegexp.ReplaceAllString(src, ">$0") + }, + }, + } for channelName, channelPosts := range posts { for postIdx, post := range channelPosts { - posts[channelName][postIdx].Text = regex.ReplaceAllString(post.Text, "[$2]($1)") + result := post.Text + + for _, rule := range regexReplaceAllString { + result = rule.regex.ReplaceAllString(result, rule.rpl) + } + + for _, rule := range regexReplaceAllStringFunc { + result = rule.regex.ReplaceAllStringFunc(result, rule.fn) + } + posts[channelName][postIdx].Text = result } } diff --git a/app/slackimport_test.go b/app/slackimport_test.go index 3389c5217..6db6adf2d 100644 --- a/app/slackimport_test.go +++ b/app/slackimport_test.go @@ -190,7 +190,7 @@ func TestSlackSanitiseChannelProperties(t *testing.T) { c1s := SlackSanitiseChannelProperties(c1) if c1.DisplayName != c1s.DisplayName || c1.Name != c1s.Name || c1.Purpose != c1s.Purpose || c1.Header != c1s.Header { - t.Fatalf("Unexpected alterations to the channel properties.") + t.Fatal("Unexpected alterations to the channel properties.") } c2 := model.Channel{ @@ -227,14 +227,103 @@ func TestSlackConvertPostsMarkup(t *testing.T) { { Text: "This message contains a mailto link to in it.", }, + { + Text: "This message contains a *bold* word.", + }, + { + Text: "This is not a * bold * word.", + }, + { + Text: `There is *no bold word +in this*.`, + }, + { + Text: "*This* is not a*bold* word.*This* is a bold word, *and* this; *and* this too.", + }, + { + Text: "This message contains a ~strikethrough~ word.", + }, + { + Text: "This is not a ~ strikethrough ~ word.", + }, + { + Text: `There is ~no strikethrough word +in this~.`, + }, + { + Text: "~This~ is not a~strikethrough~ word.~This~ is a strikethrough word, ~and~ this; ~and~ this too.", + }, + { + Text: `This message contains multiple paragraphs blockquotes +>>>first +second +third`, + }, + { + Text: `This message contains single paragraph blockquotes +>something +>another thing`, + }, + { + Text: "This message has no > block quote", + }, } - output := SlackConvertPostsMarkup(input) - - if output["test"][0].Text != "This message contains a link to [Google](https://google.com)." { - t.Fatalf("Unexpected message after markup translation: %v", output["test"][0].Text) + expectedOutput := make(map[string][]SlackPost) + expectedOutput["test"] = []SlackPost{ + { + Text: "This message contains a link to [Google](https://google.com).", + }, + { + Text: "This message contains a mailto link to [me@example.com](mailto:me@example.com) in it.", + }, + { + Text: "This message contains a **bold** word.", + }, + { + Text: "This is not a * bold * word.", + }, + { + Text: `There is *no bold word +in this*.`, + }, + { + Text: "**This** is not a*bold* word.**This** is a bold word, **and** this; **and** this too.", + }, + { + Text: "This message contains a ~~strikethrough~~ word.", + }, + { + Text: "This is not a ~ strikethrough ~ word.", + }, + { + Text: `There is ~no strikethrough word +in this~.`, + }, + { + Text: "~~This~~ is not a~strikethrough~ word.~~This~~ is a strikethrough word, ~~and~~ this; ~~and~~ this too.", + }, + { + Text: `This message contains multiple paragraphs blockquotes +>first +>second +>third`, + }, + { + Text: `This message contains single paragraph blockquotes +>something +>another thing`, + }, + { + Text: "This message has no > block quote", + }, } - if output["test"][1].Text != "This message contains a mailto link to [me@example.com](mailto:me@example.com) in it." { - t.Fatalf("Unexpected message after markup translation: %v", output["test"][0].Text) + + actualOutput := SlackConvertPostsMarkup(input) + + for i := range actualOutput["test"] { + if actualOutput["test"][i].Text != expectedOutput["test"][i].Text { + t.Errorf("Unexpected message after markup translation: %v", actualOutput["test"][i].Text) + } } } -- cgit v1.2.3-1-g7c22