summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bridge/config/config.go1
-rw-r--r--bridge/slack/handlers.go7
-rw-r--r--bridge/slack/helpers.go24
-rw-r--r--bridge/slack/helpers_test.go36
-rw-r--r--bridge/slack/slack.go51
-rw-r--r--gateway/gateway.go6
-rw-r--r--matterbridge.toml.sample7
7 files changed, 123 insertions, 9 deletions
diff --git a/bridge/config/config.go b/bridge/config/config.go
index 21010dbf..eb34912d 100644
--- a/bridge/config/config.go
+++ b/bridge/config/config.go
@@ -117,6 +117,7 @@ type Protocol struct {
ShowEmbeds bool // discord
SkipTLSVerify bool // IRC, mattermost
StripNick bool // all protocols
+ SyncTopic bool // slack
Team string // mattermost
Token string // gitter, slack, discord, api
Topic string // zulip
diff --git a/bridge/slack/handlers.go b/bridge/slack/handlers.go
index 035c5af5..89c800da 100644
--- a/bridge/slack/handlers.go
+++ b/bridge/slack/handlers.go
@@ -116,6 +116,11 @@ func (b *Bslack) skipMessageEvent(ev *slack.MessageEvent) bool {
return b.GetBool(noSendJoinConfig)
case sPinnedItem, sUnpinnedItem:
return true
+ case sChannelTopic, sChannelPurpose:
+ // Skip the event if our bot/user account changed the topic/purpose
+ if ev.User == b.si.User.ID {
+ return true
+ }
}
// Skip any messages that we made ourselves or from 'slackbot' (see #527).
@@ -136,7 +141,6 @@ func (b *Bslack) skipMessageEvent(ev *slack.MessageEvent) bool {
if len(ev.Files) > 0 {
return b.filesCached(ev.Files)
}
-
return false
}
@@ -201,6 +205,7 @@ func (b *Bslack) handleStatusEvent(ev *slack.MessageEvent, rmsg *config.Message)
rmsg.Username = sSystemUser
rmsg.Event = config.EventJoinLeave
case sChannelTopic, sChannelPurpose:
+ b.populateChannels()
rmsg.Event = config.EventTopicChange
case sMessageChanged:
rmsg.Text = ev.SubMessage.Text
diff --git a/bridge/slack/helpers.go b/bridge/slack/helpers.go
index b0fdaba1..39fbcea7 100644
--- a/bridge/slack/helpers.go
+++ b/bridge/slack/helpers.go
@@ -262,12 +262,28 @@ func (b *Bslack) populateMessageWithBotInfo(ev *slack.MessageEvent, rmsg *config
}
var (
- mentionRE = regexp.MustCompile(`<@([a-zA-Z0-9]+)>`)
- channelRE = regexp.MustCompile(`<#[a-zA-Z0-9]+\|(.+?)>`)
- variableRE = regexp.MustCompile(`<!((?:subteam\^)?[a-zA-Z0-9]+)(?:\|@?(.+?))?>`)
- urlRE = regexp.MustCompile(`<(.*?)(\|.*?)?>`)
+ mentionRE = regexp.MustCompile(`<@([a-zA-Z0-9]+)>`)
+ channelRE = regexp.MustCompile(`<#[a-zA-Z0-9]+\|(.+?)>`)
+ variableRE = regexp.MustCompile(`<!((?:subteam\^)?[a-zA-Z0-9]+)(?:\|@?(.+?))?>`)
+ urlRE = regexp.MustCompile(`<(.*?)(\|.*?)?>`)
+ topicOrPurposeRE = regexp.MustCompile(`(?s)(@.+) (cleared|set)(?: the)? channel (topic|purpose)(?:: (.*))?`)
)
+func (b *Bslack) extractTopicOrPurpose(text string) (string, string) {
+ r := topicOrPurposeRE.FindStringSubmatch(text)
+ if len(r) == 5 {
+ action, updateType, extracted := r[2], r[3], r[4]
+ switch action {
+ case "set":
+ return updateType, extracted
+ case "cleared":
+ return updateType, ""
+ }
+ }
+ b.Log.Warnf("Encountered channel topic or purpose change message with unexpected format: %s", text)
+ return "unknown", ""
+}
+
// @see https://api.slack.com/docs/message-formatting#linking_to_channels_and_users
func (b *Bslack) replaceMention(text string) string {
replaceFunc := func(match string) string {
diff --git a/bridge/slack/helpers_test.go b/bridge/slack/helpers_test.go
new file mode 100644
index 00000000..c9ff647d
--- /dev/null
+++ b/bridge/slack/helpers_test.go
@@ -0,0 +1,36 @@
+package bslack
+
+import (
+ "io/ioutil"
+ "testing"
+
+ "github.com/42wim/matterbridge/bridge"
+ "github.com/sirupsen/logrus"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestExtractTopicOrPurpose(t *testing.T) {
+ testcases := map[string]struct {
+ input string
+ wantChangeType string
+ wantOutput string
+ }{
+ "success - topic type": {"@someone set channel topic: foo bar", "topic", "foo bar"},
+ "success - purpose type": {"@someone set channel purpose: foo bar", "purpose", "foo bar"},
+ "success - one line": {"@someone set channel topic: foo bar", "topic", "foo bar"},
+ "success - multi-line": {"@someone set channel topic: foo\nbar", "topic", "foo\nbar"},
+ "success - cleared": {"@someone cleared channel topic", "topic", ""},
+ "error - unhandled": {"some unmatched message", "unknown", ""},
+ }
+
+ logger := logrus.New()
+ logger.SetOutput(ioutil.Discard)
+ cfg := &bridge.Config{Log: logger.WithFields(nil)}
+ b := newBridge(cfg)
+ for name, tc := range testcases {
+ gotChangeType, gotOutput := b.extractTopicOrPurpose(tc.input)
+
+ assert.Equalf(t, tc.wantChangeType, gotChangeType, "This testcase failed: %s", name)
+ assert.Equalf(t, tc.wantOutput, gotOutput, "This testcase failed: %s", name)
+ }
+}
diff --git a/bridge/slack/slack.go b/bridge/slack/slack.go
index d054ae81..a38bbb53 100644
--- a/bridge/slack/slack.go
+++ b/bridge/slack/slack.go
@@ -281,8 +281,14 @@ func (b *Bslack) sendRTM(msg config.Message) (string, error) {
return "", nil
}
- // Handle message deletions.
var handled bool
+
+ // Handle topic/purpose updates.
+ if handled, err = b.handleTopicOrPurpose(&msg, channelInfo); handled {
+ return "", err
+ }
+
+ // Handle message deletions.
if handled, err = b.deleteMessage(&msg, channelInfo); handled {
return msg.ID, err
}
@@ -315,6 +321,49 @@ func (b *Bslack) sendRTM(msg config.Message) (string, error) {
return b.postMessage(&msg, messageParameters, channelInfo)
}
+func (b *Bslack) updateTopicOrPurpose(msg *config.Message, channelInfo *slack.Channel) (bool, error) {
+ var updateFunc func(channelID string, value string) (*slack.Channel, error)
+
+ incomingChangeType, text := b.extractTopicOrPurpose(msg.Text)
+ switch incomingChangeType {
+ case "topic":
+ updateFunc = b.rtm.SetTopicOfConversation
+ case "purpose":
+ updateFunc = b.rtm.SetPurposeOfConversation
+ default:
+ b.Log.Errorf("Unhandled type received from extractTopicOrPurpose: %s", incomingChangeType)
+ return true, nil
+ }
+ for {
+ _, err := updateFunc(channelInfo.ID, text)
+ if err == nil {
+ return true, nil
+ }
+ if err = b.handleRateLimit(err); err != nil {
+ return true, err
+ }
+ }
+}
+
+// handles updating topic/purpose and determining whether to further propagate update messages.
+func (b *Bslack) handleTopicOrPurpose(msg *config.Message, channelInfo *slack.Channel) (bool, error) {
+ if msg.Event != config.EventTopicChange {
+ return false, nil
+ }
+
+ if b.GetBool("SyncTopic") {
+ return b.updateTopicOrPurpose(msg, channelInfo)
+ }
+
+ // Pass along to normal message handlers.
+ if b.GetBool("ShowTopicChange") {
+ return false, nil
+ }
+
+ // Swallow message as handled no-op.
+ return true, nil
+}
+
func (b *Bslack) deleteMessage(msg *config.Message, channelInfo *slack.Channel) (bool, error) {
if msg.Event != config.EventMsgDelete {
return false, nil
diff --git a/gateway/gateway.go b/gateway/gateway.go
index 72a0f6a6..2b8bdfa9 100644
--- a/gateway/gateway.go
+++ b/gateway/gateway.go
@@ -267,8 +267,10 @@ func (gw *Gateway) handleMessage(msg config.Message, dest *bridge.Bridge) []*BrM
return brMsgIDs
}
- // only relay topic change when configured
- if msg.Event == config.EventTopicChange && !gw.Bridges[dest.Account].GetBool("ShowTopicChange") {
+ // only relay topic change when used in some way on other side
+ if msg.Event == config.EventTopicChange &&
+ !gw.Bridges[dest.Account].GetBool("ShowTopicChange") &&
+ !gw.Bridges[dest.Account].GetBool("SyncTopic") {
return brMsgIDs
}
diff --git a/matterbridge.toml.sample b/matterbridge.toml.sample
index b51f351b..0d9a8a84 100644
--- a/matterbridge.toml.sample
+++ b/matterbridge.toml.sample
@@ -765,11 +765,16 @@ ShowJoinPart=false
#OPTIONAL (default false)
StripNick=false
-#Enable to show topic changes from other bridges
+#Enable to show topic/purpose changes from other bridges
#Only works hiding/show topic changes from slack bridge for now
#OPTIONAL (default false)
ShowTopicChange=false
+#Enable to sync topic/purpose changes from other bridges
+#Only works syncing topic changes from slack bridge for now
+#OPTIONAL (default false)
+SyncTopic=false
+
###################################################################
#telegram section
###################################################################