From 0925976fe7705ef71cac893aab3f9ec473f638ea Mon Sep 17 00:00:00 2001 From: Chris Sexton Date: Tue, 24 Oct 2017 15:38:36 -0400 Subject: [PATCH] slack: import velour/chat parsing * Removed emoji conversion * Had to make getUser return a bool as well as the user string --- slack/fix_text.go | 96 +++++++++++++++++++++++++++++++++++++++++++++++ slack/slack.go | 18 ++++----- 2 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 slack/fix_text.go diff --git a/slack/fix_text.go b/slack/fix_text.go new file mode 100644 index 0000000..c63a483 --- /dev/null +++ b/slack/fix_text.go @@ -0,0 +1,96 @@ +package slack + +import ( + "unicode/utf8" +) + +// fixText strips all of the Slack-specific annotations from message text, +// replacing it with the equivalent display form. +// Currently it: +// • Replaces user mentions like <@U124356> with @ followed by the user's nick. +// This uses the lookupUser function, which must map U1243456 to the nick. +// • Replaces user mentions like with the user's nick. +// • Strips < and > surrounding links. +// +// This was directly bogarted from velour/chat with emoji conversion removed. +func fixText(findUser func(id string) (string, bool), text string) string { + var output []rune + for len(text) > 0 { + r, i := utf8.DecodeRuneInString(text) + text = text[i:] + switch { + case r == '<': + var tag []rune + for { + r, i := utf8.DecodeRuneInString(text) + text = text[i:] + switch { + case r == '>': + if t, ok := fixTag(findUser, tag); ok { + output = append(output, t...) + break + } + fallthrough + case len(text) == 0: + output = append(output, '<') + output = append(output, tag...) + output = append(output, r) + default: + tag = append(tag, r) + continue + } + break + } + default: + output = append(output, r) + } + } + return string(output) +} + +func fixTag(findUser func(string) (string, bool), tag []rune) ([]rune, bool) { + switch { + case hasPrefix(tag, "@U"): + if i := indexRune(tag, '|'); i >= 0 { + return tag[i+1:], true + } + if findUser != nil { + if u, ok := findUser(string(tag[1:])); ok { + return []rune("@" + u), true + } + } + return tag, true + + case hasPrefix(tag, "#C"): + if i := indexRune(tag, '|'); i >= 0 { + return append([]rune{'#'}, tag[i+1:]...), true + } + + case hasPrefix(tag, "http"): + if i := indexRune(tag, '|'); i >= 0 { + tag = tag[:i] + } + return tag, true + } + + return nil, false +} + +func hasPrefix(text []rune, prefix string) bool { + for _, r := range prefix { + if len(text) == 0 || text[0] != r { + return false + } + text = text[1:] + } + return true +} + +func indexRune(text []rune, find rune) int { + for i, r := range text { + if r == find { + return i + } + } + return -1 +} diff --git a/slack/slack.go b/slack/slack.go index 62e1b78..85436b5 100644 --- a/slack/slack.go +++ b/slack/slack.go @@ -306,14 +306,13 @@ var urlDetector = regexp.MustCompile(`<(.+)://([^|^>]+).*>`) func (s *Slack) buildMessage(m slackMessage) msg.Message { text := html.UnescapeString(m.Text) - // remove <> from URLs, URLs may also be - text = urlDetector.ReplaceAllString(text, "${1}://${2}") + text = fixText(s.getUser, text) isCmd, text := bot.IsCmd(s.config, text) isAction := m.SubType == "me_message" - u := s.getUser(m.User) + u, _ := s.getUser(m.User) if m.Username != "" { u = m.Username } @@ -460,9 +459,9 @@ func (s *Slack) connect() { } // Get username for Slack user ID -func (s *Slack) getUser(id string) string { +func (s *Slack) getUser(id string) (string, bool) { if name, ok := s.users[id]; ok { - return name + return name, true } log.Printf("User %s not already found, requesting info", id) @@ -472,17 +471,17 @@ func (s *Slack) getUser(id string) string { if err != nil || resp.StatusCode != 200 { log.Printf("Error posting user info request: %d %s", resp.StatusCode, err) - return "UNKNOWN" + return "UNKNOWN", false } defer resp.Body.Close() var userInfo slackUserInfoResp err = json.NewDecoder(resp.Body).Decode(&userInfo) if err != nil { log.Println("Error decoding response: ", err) - return "UNKNOWN" + return "UNKNOWN", false } s.users[id] = userInfo.User.Name - return s.users[id] + return s.users[id], true } // Who gets usernames out of a channel @@ -513,7 +512,8 @@ func (s *Slack) Who(id string) []string { handles := []string{} for _, member := range chanInfo.Channel.Members { - handles = append(handles, s.getUser(member)) + u, _ := s.getUser(member) + handles = append(handles, u) } log.Printf("Returning %d handles", len(handles)) return handles